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, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    Closed,
  257}
  258
  259impl ReportEditorEvent {
  260    pub fn event_type(&self) -> &'static str {
  261        match self {
  262            Self::Saved { .. } => "Editor Saved",
  263            Self::EditorOpened => "Editor Opened",
  264            Self::Closed => "Editor Closed",
  265        }
  266    }
  267}
  268
  269struct InlineValueCache {
  270    enabled: bool,
  271    inlays: Vec<InlayId>,
  272    refresh_task: Task<Option<()>>,
  273}
  274
  275impl InlineValueCache {
  276    fn new(enabled: bool) -> Self {
  277        Self {
  278            enabled,
  279            inlays: Vec::new(),
  280            refresh_task: Task::ready(None),
  281        }
  282    }
  283}
  284
  285#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  286pub enum InlayId {
  287    EditPrediction(usize),
  288    DebuggerValue(usize),
  289    // LSP
  290    Hint(usize),
  291    Color(usize),
  292}
  293
  294impl InlayId {
  295    fn id(&self) -> usize {
  296        match self {
  297            Self::EditPrediction(id) => *id,
  298            Self::DebuggerValue(id) => *id,
  299            Self::Hint(id) => *id,
  300            Self::Color(id) => *id,
  301        }
  302    }
  303}
  304
  305pub enum ActiveDebugLine {}
  306pub enum DebugStackFrameLine {}
  307enum DocumentHighlightRead {}
  308enum DocumentHighlightWrite {}
  309enum InputComposition {}
  310pub enum PendingInput {}
  311enum SelectedTextHighlight {}
  312
  313pub enum ConflictsOuter {}
  314pub enum ConflictsOurs {}
  315pub enum ConflictsTheirs {}
  316pub enum ConflictsOursMarker {}
  317pub enum ConflictsTheirsMarker {}
  318
  319#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  320pub enum Navigated {
  321    Yes,
  322    No,
  323}
  324
  325impl Navigated {
  326    pub fn from_bool(yes: bool) -> Navigated {
  327        if yes { Navigated::Yes } else { Navigated::No }
  328    }
  329}
  330
  331#[derive(Debug, Clone, PartialEq, Eq)]
  332enum DisplayDiffHunk {
  333    Folded {
  334        display_row: DisplayRow,
  335    },
  336    Unfolded {
  337        is_created_file: bool,
  338        diff_base_byte_range: Range<usize>,
  339        display_row_range: Range<DisplayRow>,
  340        multi_buffer_range: Range<Anchor>,
  341        status: DiffHunkStatus,
  342    },
  343}
  344
  345pub enum HideMouseCursorOrigin {
  346    TypingAction,
  347    MovementAction,
  348}
  349
  350pub fn init_settings(cx: &mut App) {
  351    EditorSettings::register(cx);
  352}
  353
  354pub fn init(cx: &mut App) {
  355    init_settings(cx);
  356
  357    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  358
  359    workspace::register_project_item::<Editor>(cx);
  360    workspace::FollowableViewRegistry::register::<Editor>(cx);
  361    workspace::register_serializable_item::<Editor>(cx);
  362
  363    cx.observe_new(
  364        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  365            workspace.register_action(Editor::new_file);
  366            workspace.register_action(Editor::new_file_vertical);
  367            workspace.register_action(Editor::new_file_horizontal);
  368            workspace.register_action(Editor::cancel_language_server_work);
  369            workspace.register_action(Editor::toggle_focus);
  370        },
  371    )
  372    .detach();
  373
  374    cx.on_action(move |_: &workspace::NewFile, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388    cx.on_action(move |_: &workspace::NewWindow, cx| {
  389        let app_state = workspace::AppState::global(cx);
  390        if let Some(app_state) = app_state.upgrade() {
  391            workspace::open_new(
  392                Default::default(),
  393                app_state,
  394                cx,
  395                |workspace, window, cx| {
  396                    cx.activate(true);
  397                    Editor::new_file(workspace, &Default::default(), window, cx)
  398                },
  399            )
  400            .detach();
  401        }
  402    });
  403}
  404
  405pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  406    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  407}
  408
  409pub trait DiagnosticRenderer {
  410    fn render_group(
  411        &self,
  412        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  413        buffer_id: BufferId,
  414        snapshot: EditorSnapshot,
  415        editor: WeakEntity<Editor>,
  416        cx: &mut App,
  417    ) -> Vec<BlockProperties<Anchor>>;
  418
  419    fn render_hover(
  420        &self,
  421        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  422        range: Range<Point>,
  423        buffer_id: BufferId,
  424        cx: &mut App,
  425    ) -> Option<Entity<markdown::Markdown>>;
  426
  427    fn open_link(
  428        &self,
  429        editor: &mut Editor,
  430        link: SharedString,
  431        window: &mut Window,
  432        cx: &mut Context<Editor>,
  433    );
  434}
  435
  436pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  437
  438impl GlobalDiagnosticRenderer {
  439    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  440        cx.try_global::<Self>().map(|g| g.0.clone())
  441    }
  442}
  443
  444impl gpui::Global for GlobalDiagnosticRenderer {}
  445pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  446    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  447}
  448
  449pub struct SearchWithinRange;
  450
  451trait InvalidationRegion {
  452    fn ranges(&self) -> &[Range<Anchor>];
  453}
  454
  455#[derive(Clone, Debug, PartialEq)]
  456pub enum SelectPhase {
  457    Begin {
  458        position: DisplayPoint,
  459        add: bool,
  460        click_count: usize,
  461    },
  462    BeginColumnar {
  463        position: DisplayPoint,
  464        reset: bool,
  465        mode: ColumnarMode,
  466        goal_column: u32,
  467    },
  468    Extend {
  469        position: DisplayPoint,
  470        click_count: usize,
  471    },
  472    Update {
  473        position: DisplayPoint,
  474        goal_column: u32,
  475        scroll_delta: gpui::Point<f32>,
  476    },
  477    End,
  478}
  479
  480#[derive(Clone, Debug, PartialEq)]
  481pub enum ColumnarMode {
  482    FromMouse,
  483    FromSelection,
  484}
  485
  486#[derive(Clone, Debug)]
  487pub enum SelectMode {
  488    Character,
  489    Word(Range<Anchor>),
  490    Line(Range<Anchor>),
  491    All,
  492}
  493
  494#[derive(Clone, PartialEq, Eq, Debug)]
  495pub enum EditorMode {
  496    SingleLine,
  497    AutoHeight {
  498        min_lines: usize,
  499        max_lines: Option<usize>,
  500    },
  501    Full {
  502        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  503        scale_ui_elements_with_buffer_font_size: bool,
  504        /// When set to `true`, the editor will render a background for the active line.
  505        show_active_line_background: bool,
  506        /// When set to `true`, the editor's height will be determined by its content.
  507        sized_by_content: bool,
  508    },
  509    Minimap {
  510        parent: WeakEntity<Editor>,
  511    },
  512}
  513
  514impl EditorMode {
  515    pub fn full() -> Self {
  516        Self::Full {
  517            scale_ui_elements_with_buffer_font_size: true,
  518            show_active_line_background: true,
  519            sized_by_content: false,
  520        }
  521    }
  522
  523    #[inline]
  524    pub fn is_full(&self) -> bool {
  525        matches!(self, Self::Full { .. })
  526    }
  527
  528    #[inline]
  529    pub fn is_single_line(&self) -> bool {
  530        matches!(self, Self::SingleLine { .. })
  531    }
  532
  533    #[inline]
  534    fn is_minimap(&self) -> bool {
  535        matches!(self, Self::Minimap { .. })
  536    }
  537}
  538
  539#[derive(Copy, Clone, Debug)]
  540pub enum SoftWrap {
  541    /// Prefer not to wrap at all.
  542    ///
  543    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  544    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  545    GitDiff,
  546    /// Prefer a single line generally, unless an overly long line is encountered.
  547    None,
  548    /// Soft wrap lines that exceed the editor width.
  549    EditorWidth,
  550    /// Soft wrap lines at the preferred line length.
  551    Column(u32),
  552    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  553    Bounded(u32),
  554}
  555
  556#[derive(Clone)]
  557pub struct EditorStyle {
  558    pub background: Hsla,
  559    pub border: Hsla,
  560    pub local_player: PlayerColor,
  561    pub text: TextStyle,
  562    pub scrollbar_width: Pixels,
  563    pub syntax: Arc<SyntaxTheme>,
  564    pub status: StatusColors,
  565    pub inlay_hints_style: HighlightStyle,
  566    pub edit_prediction_styles: EditPredictionStyles,
  567    pub unnecessary_code_fade: f32,
  568    pub show_underlines: bool,
  569}
  570
  571impl Default for EditorStyle {
  572    fn default() -> Self {
  573        Self {
  574            background: Hsla::default(),
  575            border: Hsla::default(),
  576            local_player: PlayerColor::default(),
  577            text: TextStyle::default(),
  578            scrollbar_width: Pixels::default(),
  579            syntax: Default::default(),
  580            // HACK: Status colors don't have a real default.
  581            // We should look into removing the status colors from the editor
  582            // style and retrieve them directly from the theme.
  583            status: StatusColors::dark(),
  584            inlay_hints_style: HighlightStyle::default(),
  585            edit_prediction_styles: EditPredictionStyles {
  586                insertion: HighlightStyle::default(),
  587                whitespace: HighlightStyle::default(),
  588            },
  589            unnecessary_code_fade: Default::default(),
  590            show_underlines: true,
  591        }
  592    }
  593}
  594
  595pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  596    let show_background = language_settings::language_settings(None, None, cx)
  597        .inlay_hints
  598        .show_background;
  599
  600    HighlightStyle {
  601        color: Some(cx.theme().status().hint),
  602        background_color: show_background.then(|| cx.theme().status().hint_background),
  603        ..HighlightStyle::default()
  604    }
  605}
  606
  607pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  608    EditPredictionStyles {
  609        insertion: HighlightStyle {
  610            color: Some(cx.theme().status().predictive),
  611            ..HighlightStyle::default()
  612        },
  613        whitespace: HighlightStyle {
  614            background_color: Some(cx.theme().status().created_background),
  615            ..HighlightStyle::default()
  616        },
  617    }
  618}
  619
  620type CompletionId = usize;
  621
  622pub(crate) enum EditDisplayMode {
  623    TabAccept,
  624    DiffPopover,
  625    Inline,
  626}
  627
  628enum EditPrediction {
  629    Edit {
  630        edits: Vec<(Range<Anchor>, String)>,
  631        edit_preview: Option<EditPreview>,
  632        display_mode: EditDisplayMode,
  633        snapshot: BufferSnapshot,
  634    },
  635    Move {
  636        target: Anchor,
  637        snapshot: BufferSnapshot,
  638    },
  639}
  640
  641struct EditPredictionState {
  642    inlay_ids: Vec<InlayId>,
  643    completion: EditPrediction,
  644    completion_id: Option<SharedString>,
  645    invalidation_range: Range<Anchor>,
  646}
  647
  648enum EditPredictionSettings {
  649    Disabled,
  650    Enabled {
  651        show_in_menu: bool,
  652        preview_requires_modifier: bool,
  653    },
  654}
  655
  656enum EditPredictionHighlight {}
  657
  658#[derive(Debug, Clone)]
  659struct InlineDiagnostic {
  660    message: SharedString,
  661    group_id: usize,
  662    is_primary: bool,
  663    start: Point,
  664    severity: lsp::DiagnosticSeverity,
  665}
  666
  667pub enum MenuEditPredictionsPolicy {
  668    Never,
  669    ByProvider,
  670}
  671
  672pub enum EditPredictionPreview {
  673    /// Modifier is not pressed
  674    Inactive { released_too_fast: bool },
  675    /// Modifier pressed
  676    Active {
  677        since: Instant,
  678        previous_scroll_position: Option<ScrollAnchor>,
  679    },
  680}
  681
  682impl EditPredictionPreview {
  683    pub fn released_too_fast(&self) -> bool {
  684        match self {
  685            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  686            EditPredictionPreview::Active { .. } => false,
  687        }
  688    }
  689
  690    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  691        if let EditPredictionPreview::Active {
  692            previous_scroll_position,
  693            ..
  694        } = self
  695        {
  696            *previous_scroll_position = scroll_position;
  697        }
  698    }
  699}
  700
  701pub struct ContextMenuOptions {
  702    pub min_entries_visible: usize,
  703    pub max_entries_visible: usize,
  704    pub placement: Option<ContextMenuPlacement>,
  705}
  706
  707#[derive(Debug, Clone, PartialEq, Eq)]
  708pub enum ContextMenuPlacement {
  709    Above,
  710    Below,
  711}
  712
  713#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  714struct EditorActionId(usize);
  715
  716impl EditorActionId {
  717    pub fn post_inc(&mut self) -> Self {
  718        let answer = self.0;
  719
  720        *self = Self(answer + 1);
  721
  722        Self(answer)
  723    }
  724}
  725
  726// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  727// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  728
  729type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  730type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  731
  732#[derive(Default)]
  733struct ScrollbarMarkerState {
  734    scrollbar_size: Size<Pixels>,
  735    dirty: bool,
  736    markers: Arc<[PaintQuad]>,
  737    pending_refresh: Option<Task<Result<()>>>,
  738}
  739
  740impl ScrollbarMarkerState {
  741    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  742        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  743    }
  744}
  745
  746#[derive(Clone, Copy, PartialEq, Eq)]
  747pub enum MinimapVisibility {
  748    Disabled,
  749    Enabled {
  750        /// The configuration currently present in the users settings.
  751        setting_configuration: bool,
  752        /// Whether to override the currently set visibility from the users setting.
  753        toggle_override: bool,
  754    },
  755}
  756
  757impl MinimapVisibility {
  758    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  759        if mode.is_full() {
  760            Self::Enabled {
  761                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  762                toggle_override: false,
  763            }
  764        } else {
  765            Self::Disabled
  766        }
  767    }
  768
  769    fn hidden(&self) -> Self {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                ..
  774            } => Self::Enabled {
  775                setting_configuration,
  776                toggle_override: setting_configuration,
  777            },
  778            Self::Disabled => Self::Disabled,
  779        }
  780    }
  781
  782    fn disabled(&self) -> bool {
  783        matches!(*self, Self::Disabled)
  784    }
  785
  786    fn settings_visibility(&self) -> bool {
  787        match *self {
  788            Self::Enabled {
  789                setting_configuration,
  790                ..
  791            } => setting_configuration,
  792            _ => false,
  793        }
  794    }
  795
  796    fn visible(&self) -> bool {
  797        match *self {
  798            Self::Enabled {
  799                setting_configuration,
  800                toggle_override,
  801            } => setting_configuration ^ toggle_override,
  802            _ => false,
  803        }
  804    }
  805
  806    fn toggle_visibility(&self) -> Self {
  807        match *self {
  808            Self::Enabled {
  809                toggle_override,
  810                setting_configuration,
  811            } => Self::Enabled {
  812                setting_configuration,
  813                toggle_override: !toggle_override,
  814            },
  815            Self::Disabled => Self::Disabled,
  816        }
  817    }
  818}
  819
  820#[derive(Clone, Debug)]
  821struct RunnableTasks {
  822    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  823    offset: multi_buffer::Anchor,
  824    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  825    column: u32,
  826    // Values of all named captures, including those starting with '_'
  827    extra_variables: HashMap<String, String>,
  828    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  829    context_range: Range<BufferOffset>,
  830}
  831
  832impl RunnableTasks {
  833    fn resolve<'a>(
  834        &'a self,
  835        cx: &'a task::TaskContext,
  836    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  837        self.templates.iter().filter_map(|(kind, template)| {
  838            template
  839                .resolve_task(&kind.to_id_base(), cx)
  840                .map(|task| (kind.clone(), task))
  841        })
  842    }
  843}
  844
  845#[derive(Clone)]
  846pub struct ResolvedTasks {
  847    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  848    position: Anchor,
  849}
  850
  851#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  852struct BufferOffset(usize);
  853
  854// Addons allow storing per-editor state in other crates (e.g. Vim)
  855pub trait Addon: 'static {
  856    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  857
  858    fn render_buffer_header_controls(
  859        &self,
  860        _: &ExcerptInfo,
  861        _: &Window,
  862        _: &App,
  863    ) -> Option<AnyElement> {
  864        None
  865    }
  866
  867    fn to_any(&self) -> &dyn std::any::Any;
  868
  869    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  870        None
  871    }
  872}
  873
  874struct ChangeLocation {
  875    current: Option<Vec<Anchor>>,
  876    original: Vec<Anchor>,
  877}
  878impl ChangeLocation {
  879    fn locations(&self) -> &[Anchor] {
  880        self.current.as_ref().unwrap_or(&self.original)
  881    }
  882}
  883
  884/// A set of caret positions, registered when the editor was edited.
  885pub struct ChangeList {
  886    changes: Vec<ChangeLocation>,
  887    /// Currently "selected" change.
  888    position: Option<usize>,
  889}
  890
  891impl ChangeList {
  892    pub fn new() -> Self {
  893        Self {
  894            changes: Vec::new(),
  895            position: None,
  896        }
  897    }
  898
  899    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  900    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  901    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  902        if self.changes.is_empty() {
  903            return None;
  904        }
  905
  906        let prev = self.position.unwrap_or(self.changes.len());
  907        let next = if direction == Direction::Prev {
  908            prev.saturating_sub(count)
  909        } else {
  910            (prev + count).min(self.changes.len() - 1)
  911        };
  912        self.position = Some(next);
  913        self.changes.get(next).map(|change| change.locations())
  914    }
  915
  916    /// Adds a new change to the list, resetting the change list position.
  917    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  918        self.position.take();
  919        if let Some(last) = self.changes.last_mut()
  920            && group
  921        {
  922            last.current = Some(new_positions)
  923        } else {
  924            self.changes.push(ChangeLocation {
  925                original: new_positions,
  926                current: None,
  927            });
  928        }
  929    }
  930
  931    pub fn last(&self) -> Option<&[Anchor]> {
  932        self.changes.last().map(|change| change.locations())
  933    }
  934
  935    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  936        self.changes.last().map(|change| change.original.as_slice())
  937    }
  938
  939    pub fn invert_last_group(&mut self) {
  940        if let Some(last) = self.changes.last_mut()
  941            && let Some(current) = last.current.as_mut()
  942        {
  943            mem::swap(&mut last.original, current);
  944        }
  945    }
  946}
  947
  948#[derive(Clone)]
  949struct InlineBlamePopoverState {
  950    scroll_handle: ScrollHandle,
  951    commit_message: Option<ParsedCommitMessage>,
  952    markdown: Entity<Markdown>,
  953}
  954
  955struct InlineBlamePopover {
  956    position: gpui::Point<Pixels>,
  957    hide_task: Option<Task<()>>,
  958    popover_bounds: Option<Bounds<Pixels>>,
  959    popover_state: InlineBlamePopoverState,
  960    keyboard_grace: bool,
  961}
  962
  963enum SelectionDragState {
  964    /// State when no drag related activity is detected.
  965    None,
  966    /// State when the mouse is down on a selection that is about to be dragged.
  967    ReadyToDrag {
  968        selection: Selection<Anchor>,
  969        click_position: gpui::Point<Pixels>,
  970        mouse_down_time: Instant,
  971    },
  972    /// State when the mouse is dragging the selection in the editor.
  973    Dragging {
  974        selection: Selection<Anchor>,
  975        drop_cursor: Selection<Anchor>,
  976        hide_drop_cursor: bool,
  977    },
  978}
  979
  980enum ColumnarSelectionState {
  981    FromMouse {
  982        selection_tail: Anchor,
  983        display_point: Option<DisplayPoint>,
  984    },
  985    FromSelection {
  986        selection_tail: Anchor,
  987    },
  988}
  989
  990/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  991/// a breakpoint on them.
  992#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  993struct PhantomBreakpointIndicator {
  994    display_row: DisplayRow,
  995    /// There's a small debounce between hovering over the line and showing the indicator.
  996    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  997    is_active: bool,
  998    collides_with_existing_breakpoint: bool,
  999}
 1000
 1001/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1002///
 1003/// See the [module level documentation](self) for more information.
 1004pub struct Editor {
 1005    focus_handle: FocusHandle,
 1006    last_focused_descendant: Option<WeakFocusHandle>,
 1007    /// The text buffer being edited
 1008    buffer: Entity<MultiBuffer>,
 1009    /// Map of how text in the buffer should be displayed.
 1010    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1011    pub display_map: Entity<DisplayMap>,
 1012    pub selections: SelectionsCollection,
 1013    pub scroll_manager: ScrollManager,
 1014    /// When inline assist editors are linked, they all render cursors because
 1015    /// typing enters text into each of them, even the ones that aren't focused.
 1016    pub(crate) show_cursor_when_unfocused: bool,
 1017    columnar_selection_state: Option<ColumnarSelectionState>,
 1018    add_selections_state: Option<AddSelectionsState>,
 1019    select_next_state: Option<SelectNextState>,
 1020    select_prev_state: Option<SelectNextState>,
 1021    selection_history: SelectionHistory,
 1022    defer_selection_effects: bool,
 1023    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1024    autoclose_regions: Vec<AutocloseRegion>,
 1025    snippet_stack: InvalidationStack<SnippetState>,
 1026    select_syntax_node_history: SelectSyntaxNodeHistory,
 1027    ime_transaction: Option<TransactionId>,
 1028    pub diagnostics_max_severity: DiagnosticSeverity,
 1029    active_diagnostics: ActiveDiagnostic,
 1030    show_inline_diagnostics: bool,
 1031    inline_diagnostics_update: Task<()>,
 1032    inline_diagnostics_enabled: bool,
 1033    diagnostics_enabled: bool,
 1034    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1035    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1036    hard_wrap: Option<usize>,
 1037    project: Option<Entity<Project>>,
 1038    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1039    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1040    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1041    blink_manager: Entity<BlinkManager>,
 1042    show_cursor_names: bool,
 1043    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1044    pub show_local_selections: bool,
 1045    mode: EditorMode,
 1046    show_breadcrumbs: bool,
 1047    show_gutter: bool,
 1048    show_scrollbars: ScrollbarAxes,
 1049    minimap_visibility: MinimapVisibility,
 1050    offset_content: bool,
 1051    disable_expand_excerpt_buttons: bool,
 1052    show_line_numbers: Option<bool>,
 1053    use_relative_line_numbers: Option<bool>,
 1054    show_git_diff_gutter: Option<bool>,
 1055    show_code_actions: Option<bool>,
 1056    show_runnables: Option<bool>,
 1057    show_breakpoints: Option<bool>,
 1058    show_wrap_guides: Option<bool>,
 1059    show_indent_guides: Option<bool>,
 1060    placeholder_text: Option<Arc<str>>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    collapse_matches: bool,
 1090    autoindent_mode: Option<AutoindentMode>,
 1091    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1092    input_enabled: bool,
 1093    use_modal_editing: bool,
 1094    read_only: bool,
 1095    leader_id: Option<CollaboratorId>,
 1096    remote_id: Option<ViewId>,
 1097    pub hover_state: HoverState,
 1098    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1099    gutter_hovered: bool,
 1100    hovered_link_state: Option<HoveredLinkState>,
 1101    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1102    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1103    active_edit_prediction: Option<EditPredictionState>,
 1104    /// Used to prevent flickering as the user types while the menu is open
 1105    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1106    edit_prediction_settings: EditPredictionSettings,
 1107    edit_predictions_hidden_for_vim_mode: bool,
 1108    show_edit_predictions_override: Option<bool>,
 1109    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1110    edit_prediction_preview: EditPredictionPreview,
 1111    edit_prediction_indent_conflict: bool,
 1112    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1113    inlay_hint_cache: InlayHintCache,
 1114    next_inlay_id: usize,
 1115    _subscriptions: Vec<Subscription>,
 1116    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1117    gutter_dimensions: GutterDimensions,
 1118    style: Option<EditorStyle>,
 1119    text_style_refinement: Option<TextStyleRefinement>,
 1120    next_editor_action_id: EditorActionId,
 1121    editor_actions: Rc<
 1122        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1123    >,
 1124    use_autoclose: bool,
 1125    use_auto_surround: bool,
 1126    auto_replace_emoji_shortcode: bool,
 1127    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1128    show_git_blame_gutter: bool,
 1129    show_git_blame_inline: bool,
 1130    show_git_blame_inline_delay_task: Option<Task<()>>,
 1131    git_blame_inline_enabled: bool,
 1132    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1133    serialize_dirty_buffers: bool,
 1134    show_selection_menu: Option<bool>,
 1135    blame: Option<Entity<GitBlame>>,
 1136    blame_subscription: Option<Subscription>,
 1137    custom_context_menu: Option<
 1138        Box<
 1139            dyn 'static
 1140                + Fn(
 1141                    &mut Self,
 1142                    DisplayPoint,
 1143                    &mut Window,
 1144                    &mut Context<Self>,
 1145                ) -> Option<Entity<ui::ContextMenu>>,
 1146        >,
 1147    >,
 1148    last_bounds: Option<Bounds<Pixels>>,
 1149    last_position_map: Option<Rc<PositionMap>>,
 1150    expect_bounds_change: Option<Bounds<Pixels>>,
 1151    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1152    tasks_update_task: Option<Task<()>>,
 1153    breakpoint_store: Option<Entity<BreakpointStore>>,
 1154    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1155    hovered_diff_hunk_row: Option<DisplayRow>,
 1156    pull_diagnostics_task: Task<()>,
 1157    in_project_search: bool,
 1158    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1159    breadcrumb_header: Option<String>,
 1160    focused_block: Option<FocusedBlock>,
 1161    next_scroll_position: NextScrollCursorCenterTopBottom,
 1162    addons: HashMap<TypeId, Box<dyn Addon>>,
 1163    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1164    load_diff_task: Option<Shared<Task<()>>>,
 1165    /// Whether we are temporarily displaying a diff other than git's
 1166    temporary_diff_override: bool,
 1167    selection_mark_mode: bool,
 1168    toggle_fold_multiple_buffers: Task<()>,
 1169    _scroll_cursor_center_top_bottom_task: Task<()>,
 1170    serialize_selections: Task<()>,
 1171    serialize_folds: Task<()>,
 1172    mouse_cursor_hidden: bool,
 1173    minimap: Option<Entity<Self>>,
 1174    hide_mouse_mode: HideMouseMode,
 1175    pub change_list: ChangeList,
 1176    inline_value_cache: InlineValueCache,
 1177    selection_drag_state: SelectionDragState,
 1178    next_color_inlay_id: usize,
 1179    colors: Option<LspColorData>,
 1180    folding_newlines: Task<()>,
 1181}
 1182
 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1184enum NextScrollCursorCenterTopBottom {
 1185    #[default]
 1186    Center,
 1187    Top,
 1188    Bottom,
 1189}
 1190
 1191impl NextScrollCursorCenterTopBottom {
 1192    fn next(&self) -> Self {
 1193        match self {
 1194            Self::Center => Self::Top,
 1195            Self::Top => Self::Bottom,
 1196            Self::Bottom => Self::Center,
 1197        }
 1198    }
 1199}
 1200
 1201#[derive(Clone)]
 1202pub struct EditorSnapshot {
 1203    pub mode: EditorMode,
 1204    show_gutter: bool,
 1205    show_line_numbers: Option<bool>,
 1206    show_git_diff_gutter: Option<bool>,
 1207    show_code_actions: Option<bool>,
 1208    show_runnables: Option<bool>,
 1209    show_breakpoints: Option<bool>,
 1210    git_blame_gutter_max_author_length: Option<usize>,
 1211    pub display_snapshot: DisplaySnapshot,
 1212    pub placeholder_text: Option<Arc<str>>,
 1213    is_focused: bool,
 1214    scroll_anchor: ScrollAnchor,
 1215    ongoing_scroll: OngoingScroll,
 1216    current_line_highlight: CurrentLineHighlight,
 1217    gutter_hovered: bool,
 1218}
 1219
 1220#[derive(Default, Debug, Clone, Copy)]
 1221pub struct GutterDimensions {
 1222    pub left_padding: Pixels,
 1223    pub right_padding: Pixels,
 1224    pub width: Pixels,
 1225    pub margin: Pixels,
 1226    pub git_blame_entries_width: Option<Pixels>,
 1227}
 1228
 1229impl GutterDimensions {
 1230    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1231        Self {
 1232            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1233            ..Default::default()
 1234        }
 1235    }
 1236
 1237    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1238        -cx.text_system().descent(font_id, font_size)
 1239    }
 1240    /// The full width of the space taken up by the gutter.
 1241    pub fn full_width(&self) -> Pixels {
 1242        self.margin + self.width
 1243    }
 1244
 1245    /// The width of the space reserved for the fold indicators,
 1246    /// use alongside 'justify_end' and `gutter_width` to
 1247    /// right align content with the line numbers
 1248    pub fn fold_area_width(&self) -> Pixels {
 1249        self.margin + self.right_padding
 1250    }
 1251}
 1252
 1253struct CharacterDimensions {
 1254    em_width: Pixels,
 1255    em_advance: Pixels,
 1256    line_height: Pixels,
 1257}
 1258
 1259#[derive(Debug)]
 1260pub struct RemoteSelection {
 1261    pub replica_id: ReplicaId,
 1262    pub selection: Selection<Anchor>,
 1263    pub cursor_shape: CursorShape,
 1264    pub collaborator_id: CollaboratorId,
 1265    pub line_mode: bool,
 1266    pub user_name: Option<SharedString>,
 1267    pub color: PlayerColor,
 1268}
 1269
 1270#[derive(Clone, Debug)]
 1271struct SelectionHistoryEntry {
 1272    selections: Arc<[Selection<Anchor>]>,
 1273    select_next_state: Option<SelectNextState>,
 1274    select_prev_state: Option<SelectNextState>,
 1275    add_selections_state: Option<AddSelectionsState>,
 1276}
 1277
 1278#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1279enum SelectionHistoryMode {
 1280    Normal,
 1281    Undoing,
 1282    Redoing,
 1283    Skipping,
 1284}
 1285
 1286#[derive(Clone, PartialEq, Eq, Hash)]
 1287struct HoveredCursor {
 1288    replica_id: u16,
 1289    selection_id: usize,
 1290}
 1291
 1292impl Default for SelectionHistoryMode {
 1293    fn default() -> Self {
 1294        Self::Normal
 1295    }
 1296}
 1297
 1298#[derive(Debug)]
 1299/// SelectionEffects controls the side-effects of updating the selection.
 1300///
 1301/// The default behaviour does "what you mostly want":
 1302/// - it pushes to the nav history if the cursor moved by >10 lines
 1303/// - it re-triggers completion requests
 1304/// - it scrolls to fit
 1305///
 1306/// You might want to modify these behaviours. For example when doing a "jump"
 1307/// like go to definition, we always want to add to nav history; but when scrolling
 1308/// in vim mode we never do.
 1309///
 1310/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1311/// move.
 1312#[derive(Clone)]
 1313pub struct SelectionEffects {
 1314    nav_history: Option<bool>,
 1315    completions: bool,
 1316    scroll: Option<Autoscroll>,
 1317}
 1318
 1319impl Default for SelectionEffects {
 1320    fn default() -> Self {
 1321        Self {
 1322            nav_history: None,
 1323            completions: true,
 1324            scroll: Some(Autoscroll::fit()),
 1325        }
 1326    }
 1327}
 1328impl SelectionEffects {
 1329    pub fn scroll(scroll: Autoscroll) -> Self {
 1330        Self {
 1331            scroll: Some(scroll),
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn no_scroll() -> Self {
 1337        Self {
 1338            scroll: None,
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn completions(self, completions: bool) -> Self {
 1344        Self {
 1345            completions,
 1346            ..self
 1347        }
 1348    }
 1349
 1350    pub fn nav_history(self, nav_history: bool) -> Self {
 1351        Self {
 1352            nav_history: Some(nav_history),
 1353            ..self
 1354        }
 1355    }
 1356}
 1357
 1358struct DeferredSelectionEffectsState {
 1359    changed: bool,
 1360    effects: SelectionEffects,
 1361    old_cursor_position: Anchor,
 1362    history_entry: SelectionHistoryEntry,
 1363}
 1364
 1365#[derive(Default)]
 1366struct SelectionHistory {
 1367    #[allow(clippy::type_complexity)]
 1368    selections_by_transaction:
 1369        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1370    mode: SelectionHistoryMode,
 1371    undo_stack: VecDeque<SelectionHistoryEntry>,
 1372    redo_stack: VecDeque<SelectionHistoryEntry>,
 1373}
 1374
 1375impl SelectionHistory {
 1376    #[track_caller]
 1377    fn insert_transaction(
 1378        &mut self,
 1379        transaction_id: TransactionId,
 1380        selections: Arc<[Selection<Anchor>]>,
 1381    ) {
 1382        if selections.is_empty() {
 1383            log::error!(
 1384                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1385                std::panic::Location::caller()
 1386            );
 1387            return;
 1388        }
 1389        self.selections_by_transaction
 1390            .insert(transaction_id, (selections, None));
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction(
 1395        &self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get(&transaction_id)
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction_mut(
 1403        &mut self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get_mut(&transaction_id)
 1407    }
 1408
 1409    fn push(&mut self, entry: SelectionHistoryEntry) {
 1410        if !entry.selections.is_empty() {
 1411            match self.mode {
 1412                SelectionHistoryMode::Normal => {
 1413                    self.push_undo(entry);
 1414                    self.redo_stack.clear();
 1415                }
 1416                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1417                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1418                SelectionHistoryMode::Skipping => {}
 1419            }
 1420        }
 1421    }
 1422
 1423    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1424        if self
 1425            .undo_stack
 1426            .back()
 1427            .is_none_or(|e| e.selections != entry.selections)
 1428        {
 1429            self.undo_stack.push_back(entry);
 1430            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1431                self.undo_stack.pop_front();
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .redo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.redo_stack.push_back(entry);
 1443            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.redo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448}
 1449
 1450#[derive(Clone, Copy)]
 1451pub struct RowHighlightOptions {
 1452    pub autoscroll: bool,
 1453    pub include_gutter: bool,
 1454}
 1455
 1456impl Default for RowHighlightOptions {
 1457    fn default() -> Self {
 1458        Self {
 1459            autoscroll: Default::default(),
 1460            include_gutter: true,
 1461        }
 1462    }
 1463}
 1464
 1465struct RowHighlight {
 1466    index: usize,
 1467    range: Range<Anchor>,
 1468    color: Hsla,
 1469    options: RowHighlightOptions,
 1470    type_id: TypeId,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsState {
 1475    groups: Vec<AddSelectionsGroup>,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsGroup {
 1480    above: bool,
 1481    stack: Vec<usize>,
 1482}
 1483
 1484#[derive(Clone)]
 1485struct SelectNextState {
 1486    query: AhoCorasick,
 1487    wordwise: bool,
 1488    done: bool,
 1489}
 1490
 1491impl std::fmt::Debug for SelectNextState {
 1492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1493        f.debug_struct(std::any::type_name::<Self>())
 1494            .field("wordwise", &self.wordwise)
 1495            .field("done", &self.done)
 1496            .finish()
 1497    }
 1498}
 1499
 1500#[derive(Debug)]
 1501struct AutocloseRegion {
 1502    selection_id: usize,
 1503    range: Range<Anchor>,
 1504    pair: BracketPair,
 1505}
 1506
 1507#[derive(Debug)]
 1508struct SnippetState {
 1509    ranges: Vec<Vec<Range<Anchor>>>,
 1510    active_index: usize,
 1511    choices: Vec<Option<Vec<String>>>,
 1512}
 1513
 1514#[doc(hidden)]
 1515pub struct RenameState {
 1516    pub range: Range<Anchor>,
 1517    pub old_name: Arc<str>,
 1518    pub editor: Entity<Editor>,
 1519    block_id: CustomBlockId,
 1520}
 1521
 1522struct InvalidationStack<T>(Vec<T>);
 1523
 1524struct RegisteredEditPredictionProvider {
 1525    provider: Arc<dyn EditPredictionProviderHandle>,
 1526    _subscription: Subscription,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530pub struct ActiveDiagnosticGroup {
 1531    pub active_range: Range<Anchor>,
 1532    pub active_message: String,
 1533    pub group_id: usize,
 1534    pub blocks: HashSet<CustomBlockId>,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538
 1539pub(crate) enum ActiveDiagnostic {
 1540    None,
 1541    All,
 1542    Group(ActiveDiagnosticGroup),
 1543}
 1544
 1545#[derive(Serialize, Deserialize, Clone, Debug)]
 1546pub struct ClipboardSelection {
 1547    /// The number of bytes in this selection.
 1548    pub len: usize,
 1549    /// Whether this was a full-line selection.
 1550    pub is_entire_line: bool,
 1551    /// The indentation of the first line when this content was originally copied.
 1552    pub first_line_indent: u32,
 1553}
 1554
 1555// selections, scroll behavior, was newest selection reversed
 1556type SelectSyntaxNodeHistoryState = (
 1557    Box<[Selection<usize>]>,
 1558    SelectSyntaxNodeScrollBehavior,
 1559    bool,
 1560);
 1561
 1562#[derive(Default)]
 1563struct SelectSyntaxNodeHistory {
 1564    stack: Vec<SelectSyntaxNodeHistoryState>,
 1565    // disable temporarily to allow changing selections without losing the stack
 1566    pub disable_clearing: bool,
 1567}
 1568
 1569impl SelectSyntaxNodeHistory {
 1570    pub fn try_clear(&mut self) {
 1571        if !self.disable_clearing {
 1572            self.stack.clear();
 1573        }
 1574    }
 1575
 1576    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1577        self.stack.push(selection);
 1578    }
 1579
 1580    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1581        self.stack.pop()
 1582    }
 1583}
 1584
 1585enum SelectSyntaxNodeScrollBehavior {
 1586    CursorTop,
 1587    FitSelection,
 1588    CursorBottom,
 1589}
 1590
 1591#[derive(Debug)]
 1592pub(crate) struct NavigationData {
 1593    cursor_anchor: Anchor,
 1594    cursor_position: Point,
 1595    scroll_anchor: ScrollAnchor,
 1596    scroll_top_row: u32,
 1597}
 1598
 1599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1600pub enum GotoDefinitionKind {
 1601    Symbol,
 1602    Declaration,
 1603    Type,
 1604    Implementation,
 1605}
 1606
 1607#[derive(Debug, Clone)]
 1608enum InlayHintRefreshReason {
 1609    ModifiersChanged(bool),
 1610    Toggle(bool),
 1611    SettingsChange(InlayHintSettings),
 1612    NewLinesShown,
 1613    BufferEdited(HashSet<Arc<Language>>),
 1614    RefreshRequested,
 1615    ExcerptsRemoved(Vec<ExcerptId>),
 1616}
 1617
 1618impl InlayHintRefreshReason {
 1619    fn description(&self) -> &'static str {
 1620        match self {
 1621            Self::ModifiersChanged(_) => "modifiers changed",
 1622            Self::Toggle(_) => "toggle",
 1623            Self::SettingsChange(_) => "settings change",
 1624            Self::NewLinesShown => "new lines shown",
 1625            Self::BufferEdited(_) => "buffer edited",
 1626            Self::RefreshRequested => "refresh requested",
 1627            Self::ExcerptsRemoved(_) => "excerpts removed",
 1628        }
 1629    }
 1630}
 1631
 1632pub enum FormatTarget {
 1633    Buffers(HashSet<Entity<Buffer>>),
 1634    Ranges(Vec<Range<MultiBufferPoint>>),
 1635}
 1636
 1637pub(crate) struct FocusedBlock {
 1638    id: BlockId,
 1639    focus_handle: WeakFocusHandle,
 1640}
 1641
 1642#[derive(Clone)]
 1643enum JumpData {
 1644    MultiBufferRow {
 1645        row: MultiBufferRow,
 1646        line_offset_from_top: u32,
 1647    },
 1648    MultiBufferPoint {
 1649        excerpt_id: ExcerptId,
 1650        position: Point,
 1651        anchor: text::Anchor,
 1652        line_offset_from_top: u32,
 1653    },
 1654}
 1655
 1656pub enum MultibufferSelectionMode {
 1657    First,
 1658    All,
 1659}
 1660
 1661#[derive(Clone, Copy, Debug, Default)]
 1662pub struct RewrapOptions {
 1663    pub override_language_settings: bool,
 1664    pub preserve_existing_whitespace: bool,
 1665}
 1666
 1667impl Editor {
 1668    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_height(
 1681        min_lines: usize,
 1682        max_lines: usize,
 1683        window: &mut Window,
 1684        cx: &mut Context<Self>,
 1685    ) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(
 1689            EditorMode::AutoHeight {
 1690                min_lines,
 1691                max_lines: Some(max_lines),
 1692            },
 1693            buffer,
 1694            None,
 1695            window,
 1696            cx,
 1697        )
 1698    }
 1699
 1700    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1701    /// The editor grows as tall as needed to fit its content.
 1702    pub fn auto_height_unbounded(
 1703        min_lines: usize,
 1704        window: &mut Window,
 1705        cx: &mut Context<Self>,
 1706    ) -> Self {
 1707        let buffer = cx.new(|cx| Buffer::local("", cx));
 1708        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1709        Self::new(
 1710            EditorMode::AutoHeight {
 1711                min_lines,
 1712                max_lines: None,
 1713            },
 1714            buffer,
 1715            None,
 1716            window,
 1717            cx,
 1718        )
 1719    }
 1720
 1721    pub fn for_buffer(
 1722        buffer: Entity<Buffer>,
 1723        project: Option<Entity<Project>>,
 1724        window: &mut Window,
 1725        cx: &mut Context<Self>,
 1726    ) -> Self {
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::full(), buffer, project, window, cx)
 1729    }
 1730
 1731    pub fn for_multibuffer(
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Self::new(EditorMode::full(), buffer, project, window, cx)
 1738    }
 1739
 1740    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let mut clone = Self::new(
 1742            self.mode.clone(),
 1743            self.buffer.clone(),
 1744            self.project.clone(),
 1745            window,
 1746            cx,
 1747        );
 1748        self.display_map.update(cx, |display_map, cx| {
 1749            let snapshot = display_map.snapshot(cx);
 1750            clone.display_map.update(cx, |display_map, cx| {
 1751                display_map.set_state(&snapshot, cx);
 1752            });
 1753        });
 1754        clone.folds_did_change(cx);
 1755        clone.selections.clone_state(&self.selections);
 1756        clone.scroll_manager.clone_state(&self.scroll_manager);
 1757        clone.searchable = self.searchable;
 1758        clone.read_only = self.read_only;
 1759        clone
 1760    }
 1761
 1762    pub fn new(
 1763        mode: EditorMode,
 1764        buffer: Entity<MultiBuffer>,
 1765        project: Option<Entity<Project>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        Editor::new_internal(mode, buffer, project, None, window, cx)
 1770    }
 1771
 1772    fn new_internal(
 1773        mode: EditorMode,
 1774        buffer: Entity<MultiBuffer>,
 1775        project: Option<Entity<Project>>,
 1776        display_map: Option<Entity<DisplayMap>>,
 1777        window: &mut Window,
 1778        cx: &mut Context<Self>,
 1779    ) -> Self {
 1780        debug_assert!(
 1781            display_map.is_none() || mode.is_minimap(),
 1782            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1783        );
 1784
 1785        let full_mode = mode.is_full();
 1786        let is_minimap = mode.is_minimap();
 1787        let diagnostics_max_severity = if full_mode {
 1788            EditorSettings::get_global(cx)
 1789                .diagnostics_max_severity
 1790                .unwrap_or(DiagnosticSeverity::Hint)
 1791        } else {
 1792            DiagnosticSeverity::Off
 1793        };
 1794        let style = window.text_style();
 1795        let font_size = style.font_size.to_pixels(window.rem_size());
 1796        let editor = cx.entity().downgrade();
 1797        let fold_placeholder = FoldPlaceholder {
 1798            constrain_width: true,
 1799            render: Arc::new(move |fold_id, fold_range, cx| {
 1800                let editor = editor.clone();
 1801                div()
 1802                    .id(fold_id)
 1803                    .bg(cx.theme().colors().ghost_element_background)
 1804                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1805                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1806                    .rounded_xs()
 1807                    .size_full()
 1808                    .cursor_pointer()
 1809                    .child("")
 1810                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1811                    .on_click(move |_, _window, cx| {
 1812                        editor
 1813                            .update(cx, |editor, cx| {
 1814                                editor.unfold_ranges(
 1815                                    &[fold_range.start..fold_range.end],
 1816                                    true,
 1817                                    false,
 1818                                    cx,
 1819                                );
 1820                                cx.stop_propagation();
 1821                            })
 1822                            .ok();
 1823                    })
 1824                    .into_any()
 1825            }),
 1826            merge_adjacent: true,
 1827            ..FoldPlaceholder::default()
 1828        };
 1829        let display_map = display_map.unwrap_or_else(|| {
 1830            cx.new(|cx| {
 1831                DisplayMap::new(
 1832                    buffer.clone(),
 1833                    style.font(),
 1834                    font_size,
 1835                    None,
 1836                    FILE_HEADER_HEIGHT,
 1837                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1838                    fold_placeholder,
 1839                    diagnostics_max_severity,
 1840                    cx,
 1841                )
 1842            })
 1843        });
 1844
 1845        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1846
 1847        let blink_manager = cx.new(|cx| {
 1848            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1849            if is_minimap {
 1850                blink_manager.disable(cx);
 1851            }
 1852            blink_manager
 1853        });
 1854
 1855        let soft_wrap_mode_override =
 1856            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1857
 1858        let mut project_subscriptions = Vec::new();
 1859        if full_mode && let Some(project) = project.as_ref() {
 1860            project_subscriptions.push(cx.subscribe_in(
 1861                project,
 1862                window,
 1863                |editor, _, event, window, cx| match event {
 1864                    project::Event::RefreshCodeLens => {
 1865                        // we always query lens with actions, without storing them, always refreshing them
 1866                    }
 1867                    project::Event::RefreshInlayHints => {
 1868                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1869                    }
 1870                    project::Event::LanguageServerAdded(..)
 1871                    | project::Event::LanguageServerRemoved(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1898                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1899                        }
 1900                    }
 1901
 1902                    project::Event::EntryRenamed(transaction) => {
 1903                        let Some(workspace) = editor.workspace() else {
 1904                            return;
 1905                        };
 1906                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1907                        else {
 1908                            return;
 1909                        };
 1910                        if active_editor.entity_id() == cx.entity_id() {
 1911                            let edited_buffers_already_open = {
 1912                                let other_editors: Vec<Entity<Editor>> = workspace
 1913                                    .read(cx)
 1914                                    .panes()
 1915                                    .iter()
 1916                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1917                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1918                                    .collect();
 1919
 1920                                transaction.0.keys().all(|buffer| {
 1921                                    other_editors.iter().any(|editor| {
 1922                                        let multi_buffer = editor.read(cx).buffer();
 1923                                        multi_buffer.read(cx).is_singleton()
 1924                                            && multi_buffer.read(cx).as_singleton().map_or(
 1925                                                false,
 1926                                                |singleton| {
 1927                                                    singleton.entity_id() == buffer.entity_id()
 1928                                                },
 1929                                            )
 1930                                    })
 1931                                })
 1932                            };
 1933
 1934                            if !edited_buffers_already_open {
 1935                                let workspace = workspace.downgrade();
 1936                                let transaction = transaction.clone();
 1937                                cx.defer_in(window, move |_, window, cx| {
 1938                                    cx.spawn_in(window, async move |editor, cx| {
 1939                                        Self::open_project_transaction(
 1940                                            &editor,
 1941                                            workspace,
 1942                                            transaction,
 1943                                            "Rename".to_string(),
 1944                                            cx,
 1945                                        )
 1946                                        .await
 1947                                        .ok()
 1948                                    })
 1949                                    .detach();
 1950                                });
 1951                            }
 1952                        }
 1953                    }
 1954
 1955                    _ => {}
 1956                },
 1957            ));
 1958            if let Some(task_inventory) = project
 1959                .read(cx)
 1960                .task_store()
 1961                .read(cx)
 1962                .task_inventory()
 1963                .cloned()
 1964            {
 1965                project_subscriptions.push(cx.observe_in(
 1966                    &task_inventory,
 1967                    window,
 1968                    |editor, _, window, cx| {
 1969                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1970                    },
 1971                ));
 1972            };
 1973
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                &project.read(cx).breakpoint_store(),
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    BreakpointStoreEvent::ClearDebugLines => {
 1979                        editor.clear_row_highlights::<ActiveDebugLine>();
 1980                        editor.refresh_inline_values(cx);
 1981                    }
 1982                    BreakpointStoreEvent::SetDebugLine => {
 1983                        if editor.go_to_active_debug_line(window, cx) {
 1984                            cx.stop_propagation();
 1985                        }
 1986
 1987                        editor.refresh_inline_values(cx);
 1988                    }
 1989                    _ => {}
 1990                },
 1991            ));
 1992            let git_store = project.read(cx).git_store().clone();
 1993            let project = project.clone();
 1994            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1995                if let GitStoreEvent::RepositoryUpdated(
 1996                    _,
 1997                    RepositoryEvent::Updated {
 1998                        new_instance: true, ..
 1999                    },
 2000                    _,
 2001                ) = event
 2002                {
 2003                    this.load_diff_task = Some(
 2004                        update_uncommitted_diff_for_buffer(
 2005                            cx.entity(),
 2006                            &project,
 2007                            this.buffer.read(cx).all_buffers(),
 2008                            this.buffer.clone(),
 2009                            cx,
 2010                        )
 2011                        .shared(),
 2012                    );
 2013                }
 2014            }));
 2015        }
 2016
 2017        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2018
 2019        let inlay_hint_settings =
 2020            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2021        let focus_handle = cx.focus_handle();
 2022        if !is_minimap {
 2023            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2024                .detach();
 2025            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2026                .detach();
 2027            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2028                .detach();
 2029            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2030                .detach();
 2031            cx.observe_pending_input(window, Self::observe_pending_input)
 2032                .detach();
 2033        }
 2034
 2035        let show_indent_guides =
 2036            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2037                Some(false)
 2038            } else {
 2039                None
 2040            };
 2041
 2042        let breakpoint_store = match (&mode, project.as_ref()) {
 2043            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2044            _ => None,
 2045        };
 2046
 2047        let mut code_action_providers = Vec::new();
 2048        let mut load_uncommitted_diff = None;
 2049        if let Some(project) = project.clone() {
 2050            load_uncommitted_diff = Some(
 2051                update_uncommitted_diff_for_buffer(
 2052                    cx.entity(),
 2053                    &project,
 2054                    buffer.read(cx).all_buffers(),
 2055                    buffer.clone(),
 2056                    cx,
 2057                )
 2058                .shared(),
 2059            );
 2060            code_action_providers.push(Rc::new(project) as Rc<_>);
 2061        }
 2062
 2063        let mut editor = Self {
 2064            focus_handle,
 2065            show_cursor_when_unfocused: false,
 2066            last_focused_descendant: None,
 2067            buffer: buffer.clone(),
 2068            display_map: display_map.clone(),
 2069            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            placeholder_text: None,
 2113            highlight_order: 0,
 2114            highlighted_rows: HashMap::default(),
 2115            background_highlights: TreeMap::default(),
 2116            gutter_highlights: TreeMap::default(),
 2117            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2118            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2119            nav_history: None,
 2120            context_menu: RefCell::new(None),
 2121            context_menu_options: None,
 2122            mouse_context_menu: None,
 2123            completion_tasks: Vec::new(),
 2124            inline_blame_popover: None,
 2125            inline_blame_popover_show_task: None,
 2126            signature_help_state: SignatureHelpState::default(),
 2127            auto_signature_help: None,
 2128            find_all_references_task_sources: Vec::new(),
 2129            next_completion_id: 0,
 2130            next_inlay_id: 0,
 2131            code_action_providers,
 2132            available_code_actions: None,
 2133            code_actions_task: None,
 2134            quick_selection_highlight_task: None,
 2135            debounced_selection_highlight_task: None,
 2136            document_highlights_task: None,
 2137            linked_editing_range_task: None,
 2138            pending_rename: None,
 2139            searchable: !is_minimap,
 2140            cursor_shape: EditorSettings::get_global(cx)
 2141                .cursor_shape
 2142                .unwrap_or_default(),
 2143            current_line_highlight: None,
 2144            autoindent_mode: Some(AutoindentMode::EachLine),
 2145            collapse_matches: false,
 2146            workspace: None,
 2147            input_enabled: !is_minimap,
 2148            use_modal_editing: full_mode,
 2149            read_only: is_minimap,
 2150            use_autoclose: true,
 2151            use_auto_surround: true,
 2152            auto_replace_emoji_shortcode: false,
 2153            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2154            leader_id: None,
 2155            remote_id: None,
 2156            hover_state: HoverState::default(),
 2157            pending_mouse_down: None,
 2158            hovered_link_state: None,
 2159            edit_prediction_provider: None,
 2160            active_edit_prediction: None,
 2161            stale_edit_prediction_in_menu: None,
 2162            edit_prediction_preview: EditPredictionPreview::Inactive {
 2163                released_too_fast: false,
 2164            },
 2165            inline_diagnostics_enabled: full_mode,
 2166            diagnostics_enabled: full_mode,
 2167            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        };
 2260
 2261        if is_minimap {
 2262            return editor;
 2263        }
 2264
 2265        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2266            editor
 2267                ._subscriptions
 2268                .push(cx.observe(breakpoints, |_, _, cx| {
 2269                    cx.notify();
 2270                }));
 2271        }
 2272        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2273        editor._subscriptions.extend(project_subscriptions);
 2274
 2275        editor._subscriptions.push(cx.subscribe_in(
 2276            &cx.entity(),
 2277            window,
 2278            |editor, _, e: &EditorEvent, window, cx| match e {
 2279                EditorEvent::ScrollPositionChanged { local, .. } => {
 2280                    if *local {
 2281                        let new_anchor = editor.scroll_manager.anchor();
 2282                        let snapshot = editor.snapshot(window, cx);
 2283                        editor.update_restoration_data(cx, move |data| {
 2284                            data.scroll_position = (
 2285                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2286                                new_anchor.offset,
 2287                            );
 2288                        });
 2289                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2290                        editor.inline_blame_popover.take();
 2291                    }
 2292                }
 2293                EditorEvent::Edited { .. } => {
 2294                    if !vim_enabled(cx) {
 2295                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2296                        let pop_state = editor
 2297                            .change_list
 2298                            .last()
 2299                            .map(|previous| {
 2300                                previous.len() == selections.len()
 2301                                    && previous.iter().enumerate().all(|(ix, p)| {
 2302                                        p.to_display_point(&map).row()
 2303                                            == selections[ix].head().row()
 2304                                    })
 2305                            })
 2306                            .unwrap_or(false);
 2307                        let new_positions = selections
 2308                            .into_iter()
 2309                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2310                            .collect();
 2311                        editor
 2312                            .change_list
 2313                            .push_to_change_list(pop_state, new_positions);
 2314                    }
 2315                }
 2316                _ => (),
 2317            },
 2318        ));
 2319
 2320        if let Some(dap_store) = editor
 2321            .project
 2322            .as_ref()
 2323            .map(|project| project.read(cx).dap_store())
 2324        {
 2325            let weak_editor = cx.weak_entity();
 2326
 2327            editor
 2328                ._subscriptions
 2329                .push(
 2330                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2331                        let session_entity = cx.entity();
 2332                        weak_editor
 2333                            .update(cx, |editor, cx| {
 2334                                editor._subscriptions.push(
 2335                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2336                                );
 2337                            })
 2338                            .ok();
 2339                    }),
 2340                );
 2341
 2342            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2343                editor
 2344                    ._subscriptions
 2345                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2346            }
 2347        }
 2348
 2349        // skip adding the initial selection to selection history
 2350        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2351        editor.end_selection(window, cx);
 2352        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2353
 2354        editor.scroll_manager.show_scrollbars(window, cx);
 2355        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2356
 2357        if full_mode {
 2358            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2359            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2360
 2361            if editor.git_blame_inline_enabled {
 2362                editor.start_git_blame_inline(false, window, cx);
 2363            }
 2364
 2365            editor.go_to_active_debug_line(window, cx);
 2366
 2367            if let Some(buffer) = buffer.read(cx).as_singleton()
 2368                && let Some(project) = editor.project()
 2369            {
 2370                let handle = project.update(cx, |project, cx| {
 2371                    project.register_buffer_with_language_servers(&buffer, cx)
 2372                });
 2373                editor
 2374                    .registered_buffers
 2375                    .insert(buffer.read(cx).remote_id(), handle);
 2376            }
 2377
 2378            editor.minimap =
 2379                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2380            editor.colors = Some(LspColorData::new(cx));
 2381            editor.update_lsp_data(false, None, window, cx);
 2382        }
 2383
 2384        if editor.mode.is_full() {
 2385            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2386        }
 2387
 2388        editor
 2389    }
 2390
 2391    pub fn deploy_mouse_context_menu(
 2392        &mut self,
 2393        position: gpui::Point<Pixels>,
 2394        context_menu: Entity<ContextMenu>,
 2395        window: &mut Window,
 2396        cx: &mut Context<Self>,
 2397    ) {
 2398        self.mouse_context_menu = Some(MouseContextMenu::new(
 2399            self,
 2400            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2401            context_menu,
 2402            window,
 2403            cx,
 2404        ));
 2405    }
 2406
 2407    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2408        self.mouse_context_menu
 2409            .as_ref()
 2410            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2411    }
 2412
 2413    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2414        if self
 2415            .selections
 2416            .pending
 2417            .as_ref()
 2418            .is_some_and(|pending_selection| {
 2419                let snapshot = self.buffer().read(cx).snapshot(cx);
 2420                pending_selection
 2421                    .selection
 2422                    .range()
 2423                    .includes(range, &snapshot)
 2424            })
 2425        {
 2426            return true;
 2427        }
 2428
 2429        self.selections
 2430            .disjoint_in_range::<usize>(range.clone(), cx)
 2431            .into_iter()
 2432            .any(|selection| {
 2433                // This is needed to cover a corner case, if we just check for an existing
 2434                // selection in the fold range, having a cursor at the start of the fold
 2435                // marks it as selected. Non-empty selections don't cause this.
 2436                let length = selection.end - selection.start;
 2437                length > 0
 2438            })
 2439    }
 2440
 2441    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2442        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2443    }
 2444
 2445    fn key_context_internal(
 2446        &self,
 2447        has_active_edit_prediction: bool,
 2448        window: &Window,
 2449        cx: &App,
 2450    ) -> KeyContext {
 2451        let mut key_context = KeyContext::new_with_defaults();
 2452        key_context.add("Editor");
 2453        let mode = match self.mode {
 2454            EditorMode::SingleLine => "single_line",
 2455            EditorMode::AutoHeight { .. } => "auto_height",
 2456            EditorMode::Minimap { .. } => "minimap",
 2457            EditorMode::Full { .. } => "full",
 2458        };
 2459
 2460        if EditorSettings::jupyter_enabled(cx) {
 2461            key_context.add("jupyter");
 2462        }
 2463
 2464        key_context.set("mode", mode);
 2465        if self.pending_rename.is_some() {
 2466            key_context.add("renaming");
 2467        }
 2468
 2469        match self.context_menu.borrow().as_ref() {
 2470            Some(CodeContextMenu::Completions(menu)) => {
 2471                if menu.visible() {
 2472                    key_context.add("menu");
 2473                    key_context.add("showing_completions");
 2474                }
 2475            }
 2476            Some(CodeContextMenu::CodeActions(menu)) => {
 2477                if menu.visible() {
 2478                    key_context.add("menu");
 2479                    key_context.add("showing_code_actions")
 2480                }
 2481            }
 2482            None => {}
 2483        }
 2484
 2485        if self.signature_help_state.has_multiple_signatures() {
 2486            key_context.add("showing_signature_help");
 2487        }
 2488
 2489        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2490        if !self.focus_handle(cx).contains_focused(window, cx)
 2491            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2492        {
 2493            for addon in self.addons.values() {
 2494                addon.extend_key_context(&mut key_context, cx)
 2495            }
 2496        }
 2497
 2498        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2499            if let Some(extension) = singleton_buffer
 2500                .read(cx)
 2501                .file()
 2502                .and_then(|file| file.path().extension()?.to_str())
 2503            {
 2504                key_context.set("extension", extension.to_string());
 2505            }
 2506        } else {
 2507            key_context.add("multibuffer");
 2508        }
 2509
 2510        if has_active_edit_prediction {
 2511            if self.edit_prediction_in_conflict() {
 2512                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2513            } else {
 2514                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2515                key_context.add("copilot_suggestion");
 2516            }
 2517        }
 2518
 2519        if self.selection_mark_mode {
 2520            key_context.add("selection_mode");
 2521        }
 2522
 2523        key_context
 2524    }
 2525
 2526    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2527        if self.mouse_cursor_hidden {
 2528            self.mouse_cursor_hidden = false;
 2529            cx.notify();
 2530        }
 2531    }
 2532
 2533    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2534        let hide_mouse_cursor = match origin {
 2535            HideMouseCursorOrigin::TypingAction => {
 2536                matches!(
 2537                    self.hide_mouse_mode,
 2538                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2539                )
 2540            }
 2541            HideMouseCursorOrigin::MovementAction => {
 2542                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2543            }
 2544        };
 2545        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2546            self.mouse_cursor_hidden = hide_mouse_cursor;
 2547            cx.notify();
 2548        }
 2549    }
 2550
 2551    pub fn edit_prediction_in_conflict(&self) -> bool {
 2552        if !self.show_edit_predictions_in_menu() {
 2553            return false;
 2554        }
 2555
 2556        let showing_completions = self
 2557            .context_menu
 2558            .borrow()
 2559            .as_ref()
 2560            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2561
 2562        showing_completions
 2563            || self.edit_prediction_requires_modifier()
 2564            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2565            // bindings to insert tab characters.
 2566            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2567    }
 2568
 2569    pub fn accept_edit_prediction_keybind(
 2570        &self,
 2571        accept_partial: bool,
 2572        window: &Window,
 2573        cx: &App,
 2574    ) -> AcceptEditPredictionBinding {
 2575        let key_context = self.key_context_internal(true, window, cx);
 2576        let in_conflict = self.edit_prediction_in_conflict();
 2577
 2578        let bindings = if accept_partial {
 2579            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2580        } else {
 2581            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2582        };
 2583
 2584        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2585        // just the first one.
 2586        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2587            !in_conflict
 2588                || binding
 2589                    .keystrokes()
 2590                    .first()
 2591                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2592        }))
 2593    }
 2594
 2595    pub fn new_file(
 2596        workspace: &mut Workspace,
 2597        _: &workspace::NewFile,
 2598        window: &mut Window,
 2599        cx: &mut Context<Workspace>,
 2600    ) {
 2601        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2602            "Failed to create buffer",
 2603            window,
 2604            cx,
 2605            |e, _, _| match e.error_code() {
 2606                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2607                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2608                e.error_tag("required").unwrap_or("the latest version")
 2609            )),
 2610                _ => None,
 2611            },
 2612        );
 2613    }
 2614
 2615    pub fn new_in_workspace(
 2616        workspace: &mut Workspace,
 2617        window: &mut Window,
 2618        cx: &mut Context<Workspace>,
 2619    ) -> Task<Result<Entity<Editor>>> {
 2620        let project = workspace.project().clone();
 2621        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2622
 2623        cx.spawn_in(window, async move |workspace, cx| {
 2624            let buffer = create.await?;
 2625            workspace.update_in(cx, |workspace, window, cx| {
 2626                let editor =
 2627                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2628                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2629                editor
 2630            })
 2631        })
 2632    }
 2633
 2634    fn new_file_vertical(
 2635        workspace: &mut Workspace,
 2636        _: &workspace::NewFileSplitVertical,
 2637        window: &mut Window,
 2638        cx: &mut Context<Workspace>,
 2639    ) {
 2640        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2641    }
 2642
 2643    fn new_file_horizontal(
 2644        workspace: &mut Workspace,
 2645        _: &workspace::NewFileSplitHorizontal,
 2646        window: &mut Window,
 2647        cx: &mut Context<Workspace>,
 2648    ) {
 2649        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2650    }
 2651
 2652    fn new_file_in_direction(
 2653        workspace: &mut Workspace,
 2654        direction: SplitDirection,
 2655        window: &mut Window,
 2656        cx: &mut Context<Workspace>,
 2657    ) {
 2658        let project = workspace.project().clone();
 2659        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2660
 2661        cx.spawn_in(window, async move |workspace, cx| {
 2662            let buffer = create.await?;
 2663            workspace.update_in(cx, move |workspace, window, cx| {
 2664                workspace.split_item(
 2665                    direction,
 2666                    Box::new(
 2667                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2668                    ),
 2669                    window,
 2670                    cx,
 2671                )
 2672            })?;
 2673            anyhow::Ok(())
 2674        })
 2675        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2676            match e.error_code() {
 2677                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2678                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2679                e.error_tag("required").unwrap_or("the latest version")
 2680            )),
 2681                _ => None,
 2682            }
 2683        });
 2684    }
 2685
 2686    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2687        self.leader_id
 2688    }
 2689
 2690    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2691        &self.buffer
 2692    }
 2693
 2694    pub fn project(&self) -> Option<&Entity<Project>> {
 2695        self.project.as_ref()
 2696    }
 2697
 2698    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2699        self.workspace.as_ref()?.0.upgrade()
 2700    }
 2701
 2702    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2703        self.buffer().read(cx).title(cx)
 2704    }
 2705
 2706    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2707        let git_blame_gutter_max_author_length = self
 2708            .render_git_blame_gutter(cx)
 2709            .then(|| {
 2710                if let Some(blame) = self.blame.as_ref() {
 2711                    let max_author_length =
 2712                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2713                    Some(max_author_length)
 2714                } else {
 2715                    None
 2716                }
 2717            })
 2718            .flatten();
 2719
 2720        EditorSnapshot {
 2721            mode: self.mode.clone(),
 2722            show_gutter: self.show_gutter,
 2723            show_line_numbers: self.show_line_numbers,
 2724            show_git_diff_gutter: self.show_git_diff_gutter,
 2725            show_code_actions: self.show_code_actions,
 2726            show_runnables: self.show_runnables,
 2727            show_breakpoints: self.show_breakpoints,
 2728            git_blame_gutter_max_author_length,
 2729            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2730            scroll_anchor: self.scroll_manager.anchor(),
 2731            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2732            placeholder_text: self.placeholder_text.clone(),
 2733            is_focused: self.focus_handle.is_focused(window),
 2734            current_line_highlight: self
 2735                .current_line_highlight
 2736                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2737            gutter_hovered: self.gutter_hovered,
 2738        }
 2739    }
 2740
 2741    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2742        self.buffer.read(cx).language_at(point, cx)
 2743    }
 2744
 2745    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2746        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2747    }
 2748
 2749    pub fn active_excerpt(
 2750        &self,
 2751        cx: &App,
 2752    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2753        self.buffer
 2754            .read(cx)
 2755            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2756    }
 2757
 2758    pub fn mode(&self) -> &EditorMode {
 2759        &self.mode
 2760    }
 2761
 2762    pub fn set_mode(&mut self, mode: EditorMode) {
 2763        self.mode = mode;
 2764    }
 2765
 2766    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2767        self.collaboration_hub.as_deref()
 2768    }
 2769
 2770    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2771        self.collaboration_hub = Some(hub);
 2772    }
 2773
 2774    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2775        self.in_project_search = in_project_search;
 2776    }
 2777
 2778    pub fn set_custom_context_menu(
 2779        &mut self,
 2780        f: impl 'static
 2781        + Fn(
 2782            &mut Self,
 2783            DisplayPoint,
 2784            &mut Window,
 2785            &mut Context<Self>,
 2786        ) -> Option<Entity<ui::ContextMenu>>,
 2787    ) {
 2788        self.custom_context_menu = Some(Box::new(f))
 2789    }
 2790
 2791    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2792        self.completion_provider = provider;
 2793    }
 2794
 2795    #[cfg(any(test, feature = "test-support"))]
 2796    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2797        self.completion_provider.clone()
 2798    }
 2799
 2800    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2801        self.semantics_provider.clone()
 2802    }
 2803
 2804    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2805        self.semantics_provider = provider;
 2806    }
 2807
 2808    pub fn set_edit_prediction_provider<T>(
 2809        &mut self,
 2810        provider: Option<Entity<T>>,
 2811        window: &mut Window,
 2812        cx: &mut Context<Self>,
 2813    ) where
 2814        T: EditPredictionProvider,
 2815    {
 2816        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2817            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2818                if this.focus_handle.is_focused(window) {
 2819                    this.update_visible_edit_prediction(window, cx);
 2820                }
 2821            }),
 2822            provider: Arc::new(provider),
 2823        });
 2824        self.update_edit_prediction_settings(cx);
 2825        self.refresh_edit_prediction(false, false, window, cx);
 2826    }
 2827
 2828    pub fn placeholder_text(&self) -> Option<&str> {
 2829        self.placeholder_text.as_deref()
 2830    }
 2831
 2832    pub fn set_placeholder_text(
 2833        &mut self,
 2834        placeholder_text: impl Into<Arc<str>>,
 2835        cx: &mut Context<Self>,
 2836    ) {
 2837        let placeholder_text = Some(placeholder_text.into());
 2838        if self.placeholder_text != placeholder_text {
 2839            self.placeholder_text = placeholder_text;
 2840            cx.notify();
 2841        }
 2842    }
 2843
 2844    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2845        self.cursor_shape = cursor_shape;
 2846
 2847        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2848        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2849
 2850        cx.notify();
 2851    }
 2852
 2853    pub fn set_current_line_highlight(
 2854        &mut self,
 2855        current_line_highlight: Option<CurrentLineHighlight>,
 2856    ) {
 2857        self.current_line_highlight = current_line_highlight;
 2858    }
 2859
 2860    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2861        self.collapse_matches = collapse_matches;
 2862    }
 2863
 2864    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2865        let buffers = self.buffer.read(cx).all_buffers();
 2866        let Some(project) = self.project.as_ref() else {
 2867            return;
 2868        };
 2869        project.update(cx, |project, cx| {
 2870            for buffer in buffers {
 2871                self.registered_buffers
 2872                    .entry(buffer.read(cx).remote_id())
 2873                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2874            }
 2875        })
 2876    }
 2877
 2878    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2879        if self.collapse_matches {
 2880            return range.start..range.start;
 2881        }
 2882        range.clone()
 2883    }
 2884
 2885    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2886        if self.display_map.read(cx).clip_at_line_ends != clip {
 2887            self.display_map
 2888                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2889        }
 2890    }
 2891
 2892    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2893        self.input_enabled = input_enabled;
 2894    }
 2895
 2896    pub fn set_edit_predictions_hidden_for_vim_mode(
 2897        &mut self,
 2898        hidden: bool,
 2899        window: &mut Window,
 2900        cx: &mut Context<Self>,
 2901    ) {
 2902        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2903            self.edit_predictions_hidden_for_vim_mode = hidden;
 2904            if hidden {
 2905                self.update_visible_edit_prediction(window, cx);
 2906            } else {
 2907                self.refresh_edit_prediction(true, false, window, cx);
 2908            }
 2909        }
 2910    }
 2911
 2912    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2913        self.menu_edit_predictions_policy = value;
 2914    }
 2915
 2916    pub fn set_autoindent(&mut self, autoindent: bool) {
 2917        if autoindent {
 2918            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2919        } else {
 2920            self.autoindent_mode = None;
 2921        }
 2922    }
 2923
 2924    pub fn read_only(&self, cx: &App) -> bool {
 2925        self.read_only || self.buffer.read(cx).read_only()
 2926    }
 2927
 2928    pub fn set_read_only(&mut self, read_only: bool) {
 2929        self.read_only = read_only;
 2930    }
 2931
 2932    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2933        self.use_autoclose = autoclose;
 2934    }
 2935
 2936    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2937        self.use_auto_surround = auto_surround;
 2938    }
 2939
 2940    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2941        self.auto_replace_emoji_shortcode = auto_replace;
 2942    }
 2943
 2944    pub fn toggle_edit_predictions(
 2945        &mut self,
 2946        _: &ToggleEditPrediction,
 2947        window: &mut Window,
 2948        cx: &mut Context<Self>,
 2949    ) {
 2950        if self.show_edit_predictions_override.is_some() {
 2951            self.set_show_edit_predictions(None, window, cx);
 2952        } else {
 2953            let show_edit_predictions = !self.edit_predictions_enabled();
 2954            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2955        }
 2956    }
 2957
 2958    pub fn set_show_edit_predictions(
 2959        &mut self,
 2960        show_edit_predictions: Option<bool>,
 2961        window: &mut Window,
 2962        cx: &mut Context<Self>,
 2963    ) {
 2964        self.show_edit_predictions_override = show_edit_predictions;
 2965        self.update_edit_prediction_settings(cx);
 2966
 2967        if let Some(false) = show_edit_predictions {
 2968            self.discard_edit_prediction(false, cx);
 2969        } else {
 2970            self.refresh_edit_prediction(false, true, window, cx);
 2971        }
 2972    }
 2973
 2974    fn edit_predictions_disabled_in_scope(
 2975        &self,
 2976        buffer: &Entity<Buffer>,
 2977        buffer_position: language::Anchor,
 2978        cx: &App,
 2979    ) -> bool {
 2980        let snapshot = buffer.read(cx).snapshot();
 2981        let settings = snapshot.settings_at(buffer_position, cx);
 2982
 2983        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2984            return false;
 2985        };
 2986
 2987        scope.override_name().is_some_and(|scope_name| {
 2988            settings
 2989                .edit_predictions_disabled_in
 2990                .iter()
 2991                .any(|s| s == scope_name)
 2992        })
 2993    }
 2994
 2995    pub fn set_use_modal_editing(&mut self, to: bool) {
 2996        self.use_modal_editing = to;
 2997    }
 2998
 2999    pub fn use_modal_editing(&self) -> bool {
 3000        self.use_modal_editing
 3001    }
 3002
 3003    fn selections_did_change(
 3004        &mut self,
 3005        local: bool,
 3006        old_cursor_position: &Anchor,
 3007        effects: SelectionEffects,
 3008        window: &mut Window,
 3009        cx: &mut Context<Self>,
 3010    ) {
 3011        window.invalidate_character_coordinates();
 3012
 3013        // Copy selections to primary selection buffer
 3014        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3015        if local {
 3016            let selections = self.selections.all::<usize>(cx);
 3017            let buffer_handle = self.buffer.read(cx).read(cx);
 3018
 3019            let mut text = String::new();
 3020            for (index, selection) in selections.iter().enumerate() {
 3021                let text_for_selection = buffer_handle
 3022                    .text_for_range(selection.start..selection.end)
 3023                    .collect::<String>();
 3024
 3025                text.push_str(&text_for_selection);
 3026                if index != selections.len() - 1 {
 3027                    text.push('\n');
 3028                }
 3029            }
 3030
 3031            if !text.is_empty() {
 3032                cx.write_to_primary(ClipboardItem::new_string(text));
 3033            }
 3034        }
 3035
 3036        let selection_anchors = self.selections.disjoint_anchors();
 3037
 3038        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3039            self.buffer.update(cx, |buffer, cx| {
 3040                buffer.set_active_selections(
 3041                    &selection_anchors,
 3042                    self.selections.line_mode,
 3043                    self.cursor_shape,
 3044                    cx,
 3045                )
 3046            });
 3047        }
 3048        let display_map = self
 3049            .display_map
 3050            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3051        let buffer = &display_map.buffer_snapshot;
 3052        if self.selections.count() == 1 {
 3053            self.add_selections_state = None;
 3054        }
 3055        self.select_next_state = None;
 3056        self.select_prev_state = None;
 3057        self.select_syntax_node_history.try_clear();
 3058        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3059        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3060        self.take_rename(false, window, cx);
 3061
 3062        let newest_selection = self.selections.newest_anchor();
 3063        let new_cursor_position = newest_selection.head();
 3064        let selection_start = newest_selection.start;
 3065
 3066        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3067            self.push_to_nav_history(
 3068                *old_cursor_position,
 3069                Some(new_cursor_position.to_point(buffer)),
 3070                false,
 3071                effects.nav_history == Some(true),
 3072                cx,
 3073            );
 3074        }
 3075
 3076        if local {
 3077            if let Some(buffer_id) = new_cursor_position.buffer_id
 3078                && !self.registered_buffers.contains_key(&buffer_id)
 3079                && let Some(project) = self.project.as_ref()
 3080            {
 3081                project.update(cx, |project, cx| {
 3082                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3083                        return;
 3084                    };
 3085                    self.registered_buffers.insert(
 3086                        buffer_id,
 3087                        project.register_buffer_with_language_servers(&buffer, cx),
 3088                    );
 3089                })
 3090            }
 3091
 3092            let mut context_menu = self.context_menu.borrow_mut();
 3093            let completion_menu = match context_menu.as_ref() {
 3094                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3095                Some(CodeContextMenu::CodeActions(_)) => {
 3096                    *context_menu = None;
 3097                    None
 3098                }
 3099                None => None,
 3100            };
 3101            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3102            drop(context_menu);
 3103
 3104            if effects.completions
 3105                && let Some(completion_position) = completion_position
 3106            {
 3107                let start_offset = selection_start.to_offset(buffer);
 3108                let position_matches = start_offset == completion_position.to_offset(buffer);
 3109                let continue_showing = if position_matches {
 3110                    if self.snippet_stack.is_empty() {
 3111                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3112                    } else {
 3113                        // Snippet choices can be shown even when the cursor is in whitespace.
 3114                        // Dismissing the menu with actions like backspace is handled by
 3115                        // invalidation regions.
 3116                        true
 3117                    }
 3118                } else {
 3119                    false
 3120                };
 3121
 3122                if continue_showing {
 3123                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3124                } else {
 3125                    self.hide_context_menu(window, cx);
 3126                }
 3127            }
 3128
 3129            hide_hover(self, cx);
 3130
 3131            if old_cursor_position.to_display_point(&display_map).row()
 3132                != new_cursor_position.to_display_point(&display_map).row()
 3133            {
 3134                self.available_code_actions.take();
 3135            }
 3136            self.refresh_code_actions(window, cx);
 3137            self.refresh_document_highlights(cx);
 3138            self.refresh_selected_text_highlights(false, window, cx);
 3139            refresh_matching_bracket_highlights(self, window, cx);
 3140            self.update_visible_edit_prediction(window, cx);
 3141            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3142            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3143            self.inline_blame_popover.take();
 3144            if self.git_blame_inline_enabled {
 3145                self.start_inline_blame_timer(window, cx);
 3146            }
 3147        }
 3148
 3149        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3150        cx.emit(EditorEvent::SelectionsChanged { local });
 3151
 3152        let selections = &self.selections.disjoint;
 3153        if selections.len() == 1 {
 3154            cx.emit(SearchEvent::ActiveMatchChanged)
 3155        }
 3156        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3157            let inmemory_selections = selections
 3158                .iter()
 3159                .map(|s| {
 3160                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3161                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3162                })
 3163                .collect();
 3164            self.update_restoration_data(cx, |data| {
 3165                data.selections = inmemory_selections;
 3166            });
 3167
 3168            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3169                && let Some(workspace_id) =
 3170                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3171            {
 3172                let snapshot = self.buffer().read(cx).snapshot(cx);
 3173                let selections = selections.clone();
 3174                let background_executor = cx.background_executor().clone();
 3175                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3176                self.serialize_selections = cx.background_spawn(async move {
 3177                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3178                            let db_selections = selections
 3179                                .iter()
 3180                                .map(|selection| {
 3181                                    (
 3182                                        selection.start.to_offset(&snapshot),
 3183                                        selection.end.to_offset(&snapshot),
 3184                                    )
 3185                                })
 3186                                .collect();
 3187
 3188                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3189                                .await
 3190                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3191                                .log_err();
 3192                        });
 3193            }
 3194        }
 3195
 3196        cx.notify();
 3197    }
 3198
 3199    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3200        use text::ToOffset as _;
 3201        use text::ToPoint as _;
 3202
 3203        if self.mode.is_minimap()
 3204            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3205        {
 3206            return;
 3207        }
 3208
 3209        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3210            return;
 3211        };
 3212
 3213        let snapshot = singleton.read(cx).snapshot();
 3214        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3215            let display_snapshot = display_map.snapshot(cx);
 3216
 3217            display_snapshot
 3218                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3219                .map(|fold| {
 3220                    fold.range.start.text_anchor.to_point(&snapshot)
 3221                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3222                })
 3223                .collect()
 3224        });
 3225        self.update_restoration_data(cx, |data| {
 3226            data.folds = inmemory_folds;
 3227        });
 3228
 3229        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3230            return;
 3231        };
 3232        let background_executor = cx.background_executor().clone();
 3233        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3234        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3235            display_map
 3236                .snapshot(cx)
 3237                .folds_in_range(0..snapshot.len())
 3238                .map(|fold| {
 3239                    (
 3240                        fold.range.start.text_anchor.to_offset(&snapshot),
 3241                        fold.range.end.text_anchor.to_offset(&snapshot),
 3242                    )
 3243                })
 3244                .collect()
 3245        });
 3246        self.serialize_folds = cx.background_spawn(async move {
 3247            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3248            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3249                .await
 3250                .with_context(|| {
 3251                    format!(
 3252                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3253                    )
 3254                })
 3255                .log_err();
 3256        });
 3257    }
 3258
 3259    pub fn sync_selections(
 3260        &mut self,
 3261        other: Entity<Editor>,
 3262        cx: &mut Context<Self>,
 3263    ) -> gpui::Subscription {
 3264        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3265        self.selections.change_with(cx, |selections| {
 3266            selections.select_anchors(other_selections);
 3267        });
 3268
 3269        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3270            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3271                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3272                if other_selections.is_empty() {
 3273                    return;
 3274                }
 3275                this.selections.change_with(cx, |selections| {
 3276                    selections.select_anchors(other_selections);
 3277                });
 3278            }
 3279        });
 3280
 3281        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3282            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3283                let these_selections = this.selections.disjoint.to_vec();
 3284                if these_selections.is_empty() {
 3285                    return;
 3286                }
 3287                other.update(cx, |other_editor, cx| {
 3288                    other_editor.selections.change_with(cx, |selections| {
 3289                        selections.select_anchors(these_selections);
 3290                    })
 3291                });
 3292            }
 3293        });
 3294
 3295        Subscription::join(other_subscription, this_subscription)
 3296    }
 3297
 3298    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3299    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3300    /// effects of selection change occur at the end of the transaction.
 3301    pub fn change_selections<R>(
 3302        &mut self,
 3303        effects: SelectionEffects,
 3304        window: &mut Window,
 3305        cx: &mut Context<Self>,
 3306        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3307    ) -> R {
 3308        if let Some(state) = &mut self.deferred_selection_effects_state {
 3309            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3310            state.effects.completions = effects.completions;
 3311            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3312            let (changed, result) = self.selections.change_with(cx, change);
 3313            state.changed |= changed;
 3314            return result;
 3315        }
 3316        let mut state = DeferredSelectionEffectsState {
 3317            changed: false,
 3318            effects,
 3319            old_cursor_position: self.selections.newest_anchor().head(),
 3320            history_entry: SelectionHistoryEntry {
 3321                selections: self.selections.disjoint_anchors(),
 3322                select_next_state: self.select_next_state.clone(),
 3323                select_prev_state: self.select_prev_state.clone(),
 3324                add_selections_state: self.add_selections_state.clone(),
 3325            },
 3326        };
 3327        let (changed, result) = self.selections.change_with(cx, change);
 3328        state.changed = state.changed || changed;
 3329        if self.defer_selection_effects {
 3330            self.deferred_selection_effects_state = Some(state);
 3331        } else {
 3332            self.apply_selection_effects(state, window, cx);
 3333        }
 3334        result
 3335    }
 3336
 3337    /// Defers the effects of selection change, so that the effects of multiple calls to
 3338    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3339    /// to selection history and the state of popovers based on selection position aren't
 3340    /// erroneously updated.
 3341    pub fn with_selection_effects_deferred<R>(
 3342        &mut self,
 3343        window: &mut Window,
 3344        cx: &mut Context<Self>,
 3345        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3346    ) -> R {
 3347        let already_deferred = self.defer_selection_effects;
 3348        self.defer_selection_effects = true;
 3349        let result = update(self, window, cx);
 3350        if !already_deferred {
 3351            self.defer_selection_effects = false;
 3352            if let Some(state) = self.deferred_selection_effects_state.take() {
 3353                self.apply_selection_effects(state, window, cx);
 3354            }
 3355        }
 3356        result
 3357    }
 3358
 3359    fn apply_selection_effects(
 3360        &mut self,
 3361        state: DeferredSelectionEffectsState,
 3362        window: &mut Window,
 3363        cx: &mut Context<Self>,
 3364    ) {
 3365        if state.changed {
 3366            self.selection_history.push(state.history_entry);
 3367
 3368            if let Some(autoscroll) = state.effects.scroll {
 3369                self.request_autoscroll(autoscroll, cx);
 3370            }
 3371
 3372            let old_cursor_position = &state.old_cursor_position;
 3373
 3374            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3375
 3376            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3377                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3378            }
 3379        }
 3380    }
 3381
 3382    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3383    where
 3384        I: IntoIterator<Item = (Range<S>, T)>,
 3385        S: ToOffset,
 3386        T: Into<Arc<str>>,
 3387    {
 3388        if self.read_only(cx) {
 3389            return;
 3390        }
 3391
 3392        self.buffer
 3393            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3394    }
 3395
 3396    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3397    where
 3398        I: IntoIterator<Item = (Range<S>, T)>,
 3399        S: ToOffset,
 3400        T: Into<Arc<str>>,
 3401    {
 3402        if self.read_only(cx) {
 3403            return;
 3404        }
 3405
 3406        self.buffer.update(cx, |buffer, cx| {
 3407            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3408        });
 3409    }
 3410
 3411    pub fn edit_with_block_indent<I, S, T>(
 3412        &mut self,
 3413        edits: I,
 3414        original_indent_columns: Vec<Option<u32>>,
 3415        cx: &mut Context<Self>,
 3416    ) where
 3417        I: IntoIterator<Item = (Range<S>, T)>,
 3418        S: ToOffset,
 3419        T: Into<Arc<str>>,
 3420    {
 3421        if self.read_only(cx) {
 3422            return;
 3423        }
 3424
 3425        self.buffer.update(cx, |buffer, cx| {
 3426            buffer.edit(
 3427                edits,
 3428                Some(AutoindentMode::Block {
 3429                    original_indent_columns,
 3430                }),
 3431                cx,
 3432            )
 3433        });
 3434    }
 3435
 3436    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3437        self.hide_context_menu(window, cx);
 3438
 3439        match phase {
 3440            SelectPhase::Begin {
 3441                position,
 3442                add,
 3443                click_count,
 3444            } => self.begin_selection(position, add, click_count, window, cx),
 3445            SelectPhase::BeginColumnar {
 3446                position,
 3447                goal_column,
 3448                reset,
 3449                mode,
 3450            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3451            SelectPhase::Extend {
 3452                position,
 3453                click_count,
 3454            } => self.extend_selection(position, click_count, window, cx),
 3455            SelectPhase::Update {
 3456                position,
 3457                goal_column,
 3458                scroll_delta,
 3459            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3460            SelectPhase::End => self.end_selection(window, cx),
 3461        }
 3462    }
 3463
 3464    fn extend_selection(
 3465        &mut self,
 3466        position: DisplayPoint,
 3467        click_count: usize,
 3468        window: &mut Window,
 3469        cx: &mut Context<Self>,
 3470    ) {
 3471        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3472        let tail = self.selections.newest::<usize>(cx).tail();
 3473        self.begin_selection(position, false, click_count, window, cx);
 3474
 3475        let position = position.to_offset(&display_map, Bias::Left);
 3476        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3477
 3478        let mut pending_selection = self
 3479            .selections
 3480            .pending_anchor()
 3481            .expect("extend_selection not called with pending selection");
 3482        if position >= tail {
 3483            pending_selection.start = tail_anchor;
 3484        } else {
 3485            pending_selection.end = tail_anchor;
 3486            pending_selection.reversed = true;
 3487        }
 3488
 3489        let mut pending_mode = self.selections.pending_mode().unwrap();
 3490        match &mut pending_mode {
 3491            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3492            _ => {}
 3493        }
 3494
 3495        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3496            SelectionEffects::scroll(Autoscroll::fit())
 3497        } else {
 3498            SelectionEffects::no_scroll()
 3499        };
 3500
 3501        self.change_selections(effects, window, cx, |s| {
 3502            s.set_pending(pending_selection, pending_mode)
 3503        });
 3504    }
 3505
 3506    fn begin_selection(
 3507        &mut self,
 3508        position: DisplayPoint,
 3509        add: bool,
 3510        click_count: usize,
 3511        window: &mut Window,
 3512        cx: &mut Context<Self>,
 3513    ) {
 3514        if !self.focus_handle.is_focused(window) {
 3515            self.last_focused_descendant = None;
 3516            window.focus(&self.focus_handle);
 3517        }
 3518
 3519        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3520        let buffer = &display_map.buffer_snapshot;
 3521        let position = display_map.clip_point(position, Bias::Left);
 3522
 3523        let start;
 3524        let end;
 3525        let mode;
 3526        let mut auto_scroll;
 3527        match click_count {
 3528            1 => {
 3529                start = buffer.anchor_before(position.to_point(&display_map));
 3530                end = start;
 3531                mode = SelectMode::Character;
 3532                auto_scroll = true;
 3533            }
 3534            2 => {
 3535                let position = display_map
 3536                    .clip_point(position, Bias::Left)
 3537                    .to_offset(&display_map, Bias::Left);
 3538                let (range, _) = buffer.surrounding_word(position, false);
 3539                start = buffer.anchor_before(range.start);
 3540                end = buffer.anchor_before(range.end);
 3541                mode = SelectMode::Word(start..end);
 3542                auto_scroll = true;
 3543            }
 3544            3 => {
 3545                let position = display_map
 3546                    .clip_point(position, Bias::Left)
 3547                    .to_point(&display_map);
 3548                let line_start = display_map.prev_line_boundary(position).0;
 3549                let next_line_start = buffer.clip_point(
 3550                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3551                    Bias::Left,
 3552                );
 3553                start = buffer.anchor_before(line_start);
 3554                end = buffer.anchor_before(next_line_start);
 3555                mode = SelectMode::Line(start..end);
 3556                auto_scroll = true;
 3557            }
 3558            _ => {
 3559                start = buffer.anchor_before(0);
 3560                end = buffer.anchor_before(buffer.len());
 3561                mode = SelectMode::All;
 3562                auto_scroll = false;
 3563            }
 3564        }
 3565        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3566
 3567        let point_to_delete: Option<usize> = {
 3568            let selected_points: Vec<Selection<Point>> =
 3569                self.selections.disjoint_in_range(start..end, cx);
 3570
 3571            if !add || click_count > 1 {
 3572                None
 3573            } else if !selected_points.is_empty() {
 3574                Some(selected_points[0].id)
 3575            } else {
 3576                let clicked_point_already_selected =
 3577                    self.selections.disjoint.iter().find(|selection| {
 3578                        selection.start.to_point(buffer) == start.to_point(buffer)
 3579                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3580                    });
 3581
 3582                clicked_point_already_selected.map(|selection| selection.id)
 3583            }
 3584        };
 3585
 3586        let selections_count = self.selections.count();
 3587        let effects = if auto_scroll {
 3588            SelectionEffects::default()
 3589        } else {
 3590            SelectionEffects::no_scroll()
 3591        };
 3592
 3593        self.change_selections(effects, window, cx, |s| {
 3594            if let Some(point_to_delete) = point_to_delete {
 3595                s.delete(point_to_delete);
 3596
 3597                if selections_count == 1 {
 3598                    s.set_pending_anchor_range(start..end, mode);
 3599                }
 3600            } else {
 3601                if !add {
 3602                    s.clear_disjoint();
 3603                }
 3604
 3605                s.set_pending_anchor_range(start..end, mode);
 3606            }
 3607        });
 3608    }
 3609
 3610    fn begin_columnar_selection(
 3611        &mut self,
 3612        position: DisplayPoint,
 3613        goal_column: u32,
 3614        reset: bool,
 3615        mode: ColumnarMode,
 3616        window: &mut Window,
 3617        cx: &mut Context<Self>,
 3618    ) {
 3619        if !self.focus_handle.is_focused(window) {
 3620            self.last_focused_descendant = None;
 3621            window.focus(&self.focus_handle);
 3622        }
 3623
 3624        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3625
 3626        if reset {
 3627            let pointer_position = display_map
 3628                .buffer_snapshot
 3629                .anchor_before(position.to_point(&display_map));
 3630
 3631            self.change_selections(
 3632                SelectionEffects::scroll(Autoscroll::newest()),
 3633                window,
 3634                cx,
 3635                |s| {
 3636                    s.clear_disjoint();
 3637                    s.set_pending_anchor_range(
 3638                        pointer_position..pointer_position,
 3639                        SelectMode::Character,
 3640                    );
 3641                },
 3642            );
 3643        };
 3644
 3645        let tail = self.selections.newest::<Point>(cx).tail();
 3646        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3647        self.columnar_selection_state = match mode {
 3648            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3649                selection_tail: selection_anchor,
 3650                display_point: if reset {
 3651                    if position.column() != goal_column {
 3652                        Some(DisplayPoint::new(position.row(), goal_column))
 3653                    } else {
 3654                        None
 3655                    }
 3656                } else {
 3657                    None
 3658                },
 3659            }),
 3660            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3661                selection_tail: selection_anchor,
 3662            }),
 3663        };
 3664
 3665        if !reset {
 3666            self.select_columns(position, goal_column, &display_map, window, cx);
 3667        }
 3668    }
 3669
 3670    fn update_selection(
 3671        &mut self,
 3672        position: DisplayPoint,
 3673        goal_column: u32,
 3674        scroll_delta: gpui::Point<f32>,
 3675        window: &mut Window,
 3676        cx: &mut Context<Self>,
 3677    ) {
 3678        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3679
 3680        if self.columnar_selection_state.is_some() {
 3681            self.select_columns(position, goal_column, &display_map, window, cx);
 3682        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3683            let buffer = &display_map.buffer_snapshot;
 3684            let head;
 3685            let tail;
 3686            let mode = self.selections.pending_mode().unwrap();
 3687            match &mode {
 3688                SelectMode::Character => {
 3689                    head = position.to_point(&display_map);
 3690                    tail = pending.tail().to_point(buffer);
 3691                }
 3692                SelectMode::Word(original_range) => {
 3693                    let offset = display_map
 3694                        .clip_point(position, Bias::Left)
 3695                        .to_offset(&display_map, Bias::Left);
 3696                    let original_range = original_range.to_offset(buffer);
 3697
 3698                    let head_offset = if buffer.is_inside_word(offset, false)
 3699                        || original_range.contains(&offset)
 3700                    {
 3701                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3702                        if word_range.start < original_range.start {
 3703                            word_range.start
 3704                        } else {
 3705                            word_range.end
 3706                        }
 3707                    } else {
 3708                        offset
 3709                    };
 3710
 3711                    head = head_offset.to_point(buffer);
 3712                    if head_offset <= original_range.start {
 3713                        tail = original_range.end.to_point(buffer);
 3714                    } else {
 3715                        tail = original_range.start.to_point(buffer);
 3716                    }
 3717                }
 3718                SelectMode::Line(original_range) => {
 3719                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3720
 3721                    let position = display_map
 3722                        .clip_point(position, Bias::Left)
 3723                        .to_point(&display_map);
 3724                    let line_start = display_map.prev_line_boundary(position).0;
 3725                    let next_line_start = buffer.clip_point(
 3726                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3727                        Bias::Left,
 3728                    );
 3729
 3730                    if line_start < original_range.start {
 3731                        head = line_start
 3732                    } else {
 3733                        head = next_line_start
 3734                    }
 3735
 3736                    if head <= original_range.start {
 3737                        tail = original_range.end;
 3738                    } else {
 3739                        tail = original_range.start;
 3740                    }
 3741                }
 3742                SelectMode::All => {
 3743                    return;
 3744                }
 3745            };
 3746
 3747            if head < tail {
 3748                pending.start = buffer.anchor_before(head);
 3749                pending.end = buffer.anchor_before(tail);
 3750                pending.reversed = true;
 3751            } else {
 3752                pending.start = buffer.anchor_before(tail);
 3753                pending.end = buffer.anchor_before(head);
 3754                pending.reversed = false;
 3755            }
 3756
 3757            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3758                s.set_pending(pending, mode);
 3759            });
 3760        } else {
 3761            log::error!("update_selection dispatched with no pending selection");
 3762            return;
 3763        }
 3764
 3765        self.apply_scroll_delta(scroll_delta, window, cx);
 3766        cx.notify();
 3767    }
 3768
 3769    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3770        self.columnar_selection_state.take();
 3771        if self.selections.pending_anchor().is_some() {
 3772            let selections = self.selections.all::<usize>(cx);
 3773            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3774                s.select(selections);
 3775                s.clear_pending();
 3776            });
 3777        }
 3778    }
 3779
 3780    fn select_columns(
 3781        &mut self,
 3782        head: DisplayPoint,
 3783        goal_column: u32,
 3784        display_map: &DisplaySnapshot,
 3785        window: &mut Window,
 3786        cx: &mut Context<Self>,
 3787    ) {
 3788        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3789            return;
 3790        };
 3791
 3792        let tail = match columnar_state {
 3793            ColumnarSelectionState::FromMouse {
 3794                selection_tail,
 3795                display_point,
 3796            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3797            ColumnarSelectionState::FromSelection { selection_tail } => {
 3798                selection_tail.to_display_point(display_map)
 3799            }
 3800        };
 3801
 3802        let start_row = cmp::min(tail.row(), head.row());
 3803        let end_row = cmp::max(tail.row(), head.row());
 3804        let start_column = cmp::min(tail.column(), goal_column);
 3805        let end_column = cmp::max(tail.column(), goal_column);
 3806        let reversed = start_column < tail.column();
 3807
 3808        let selection_ranges = (start_row.0..=end_row.0)
 3809            .map(DisplayRow)
 3810            .filter_map(|row| {
 3811                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3812                    || start_column <= display_map.line_len(row))
 3813                    && !display_map.is_block_line(row)
 3814                {
 3815                    let start = display_map
 3816                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3817                        .to_point(display_map);
 3818                    let end = display_map
 3819                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3820                        .to_point(display_map);
 3821                    if reversed {
 3822                        Some(end..start)
 3823                    } else {
 3824                        Some(start..end)
 3825                    }
 3826                } else {
 3827                    None
 3828                }
 3829            })
 3830            .collect::<Vec<_>>();
 3831
 3832        let ranges = match columnar_state {
 3833            ColumnarSelectionState::FromMouse { .. } => {
 3834                let mut non_empty_ranges = selection_ranges
 3835                    .iter()
 3836                    .filter(|selection_range| selection_range.start != selection_range.end)
 3837                    .peekable();
 3838                if non_empty_ranges.peek().is_some() {
 3839                    non_empty_ranges.cloned().collect()
 3840                } else {
 3841                    selection_ranges
 3842                }
 3843            }
 3844            _ => selection_ranges,
 3845        };
 3846
 3847        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3848            s.select_ranges(ranges);
 3849        });
 3850        cx.notify();
 3851    }
 3852
 3853    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3854        self.selections
 3855            .all_adjusted(cx)
 3856            .iter()
 3857            .any(|selection| !selection.is_empty())
 3858    }
 3859
 3860    pub fn has_pending_nonempty_selection(&self) -> bool {
 3861        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3862            Some(Selection { start, end, .. }) => start != end,
 3863            None => false,
 3864        };
 3865
 3866        pending_nonempty_selection
 3867            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3868    }
 3869
 3870    pub fn has_pending_selection(&self) -> bool {
 3871        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3872    }
 3873
 3874    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3875        self.selection_mark_mode = false;
 3876        self.selection_drag_state = SelectionDragState::None;
 3877
 3878        if self.clear_expanded_diff_hunks(cx) {
 3879            cx.notify();
 3880            return;
 3881        }
 3882        if self.dismiss_menus_and_popups(true, window, cx) {
 3883            return;
 3884        }
 3885
 3886        if self.mode.is_full()
 3887            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3888        {
 3889            return;
 3890        }
 3891
 3892        cx.propagate();
 3893    }
 3894
 3895    pub fn dismiss_menus_and_popups(
 3896        &mut self,
 3897        is_user_requested: bool,
 3898        window: &mut Window,
 3899        cx: &mut Context<Self>,
 3900    ) -> bool {
 3901        if self.take_rename(false, window, cx).is_some() {
 3902            return true;
 3903        }
 3904
 3905        if hide_hover(self, cx) {
 3906            return true;
 3907        }
 3908
 3909        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3910            return true;
 3911        }
 3912
 3913        if self.hide_context_menu(window, cx).is_some() {
 3914            return true;
 3915        }
 3916
 3917        if self.mouse_context_menu.take().is_some() {
 3918            return true;
 3919        }
 3920
 3921        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3922            return true;
 3923        }
 3924
 3925        if self.snippet_stack.pop().is_some() {
 3926            return true;
 3927        }
 3928
 3929        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3930            self.dismiss_diagnostics(cx);
 3931            return true;
 3932        }
 3933
 3934        false
 3935    }
 3936
 3937    fn linked_editing_ranges_for(
 3938        &self,
 3939        selection: Range<text::Anchor>,
 3940        cx: &App,
 3941    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3942        if self.linked_edit_ranges.is_empty() {
 3943            return None;
 3944        }
 3945        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3946            selection.end.buffer_id.and_then(|end_buffer_id| {
 3947                if selection.start.buffer_id != Some(end_buffer_id) {
 3948                    return None;
 3949                }
 3950                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3951                let snapshot = buffer.read(cx).snapshot();
 3952                self.linked_edit_ranges
 3953                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3954                    .map(|ranges| (ranges, snapshot, buffer))
 3955            })?;
 3956        use text::ToOffset as TO;
 3957        // find offset from the start of current range to current cursor position
 3958        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3959
 3960        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3961        let start_difference = start_offset - start_byte_offset;
 3962        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3963        let end_difference = end_offset - start_byte_offset;
 3964        // Current range has associated linked ranges.
 3965        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3966        for range in linked_ranges.iter() {
 3967            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3968            let end_offset = start_offset + end_difference;
 3969            let start_offset = start_offset + start_difference;
 3970            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3971                continue;
 3972            }
 3973            if self.selections.disjoint_anchor_ranges().any(|s| {
 3974                if s.start.buffer_id != selection.start.buffer_id
 3975                    || s.end.buffer_id != selection.end.buffer_id
 3976                {
 3977                    return false;
 3978                }
 3979                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3980                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3981            }) {
 3982                continue;
 3983            }
 3984            let start = buffer_snapshot.anchor_after(start_offset);
 3985            let end = buffer_snapshot.anchor_after(end_offset);
 3986            linked_edits
 3987                .entry(buffer.clone())
 3988                .or_default()
 3989                .push(start..end);
 3990        }
 3991        Some(linked_edits)
 3992    }
 3993
 3994    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3995        let text: Arc<str> = text.into();
 3996
 3997        if self.read_only(cx) {
 3998            return;
 3999        }
 4000
 4001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4002
 4003        let selections = self.selections.all_adjusted(cx);
 4004        let mut bracket_inserted = false;
 4005        let mut edits = Vec::new();
 4006        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4007        let mut new_selections = Vec::with_capacity(selections.len());
 4008        let mut new_autoclose_regions = Vec::new();
 4009        let snapshot = self.buffer.read(cx).read(cx);
 4010        let mut clear_linked_edit_ranges = false;
 4011
 4012        for (selection, autoclose_region) in
 4013            self.selections_with_autoclose_regions(selections, &snapshot)
 4014        {
 4015            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4016                // Determine if the inserted text matches the opening or closing
 4017                // bracket of any of this language's bracket pairs.
 4018                let mut bracket_pair = None;
 4019                let mut is_bracket_pair_start = false;
 4020                let mut is_bracket_pair_end = false;
 4021                if !text.is_empty() {
 4022                    let mut bracket_pair_matching_end = None;
 4023                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4024                    //  and they are removing the character that triggered IME popup.
 4025                    for (pair, enabled) in scope.brackets() {
 4026                        if !pair.close && !pair.surround {
 4027                            continue;
 4028                        }
 4029
 4030                        if enabled && pair.start.ends_with(text.as_ref()) {
 4031                            let prefix_len = pair.start.len() - text.len();
 4032                            let preceding_text_matches_prefix = prefix_len == 0
 4033                                || (selection.start.column >= (prefix_len as u32)
 4034                                    && snapshot.contains_str_at(
 4035                                        Point::new(
 4036                                            selection.start.row,
 4037                                            selection.start.column - (prefix_len as u32),
 4038                                        ),
 4039                                        &pair.start[..prefix_len],
 4040                                    ));
 4041                            if preceding_text_matches_prefix {
 4042                                bracket_pair = Some(pair.clone());
 4043                                is_bracket_pair_start = true;
 4044                                break;
 4045                            }
 4046                        }
 4047                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4048                        {
 4049                            // take first bracket pair matching end, but don't break in case a later bracket
 4050                            // pair matches start
 4051                            bracket_pair_matching_end = Some(pair.clone());
 4052                        }
 4053                    }
 4054                    if let Some(end) = bracket_pair_matching_end
 4055                        && bracket_pair.is_none()
 4056                    {
 4057                        bracket_pair = Some(end);
 4058                        is_bracket_pair_end = true;
 4059                    }
 4060                }
 4061
 4062                if let Some(bracket_pair) = bracket_pair {
 4063                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4064                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4065                    let auto_surround =
 4066                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4067                    if selection.is_empty() {
 4068                        if is_bracket_pair_start {
 4069                            // If the inserted text is a suffix of an opening bracket and the
 4070                            // selection is preceded by the rest of the opening bracket, then
 4071                            // insert the closing bracket.
 4072                            let following_text_allows_autoclose = snapshot
 4073                                .chars_at(selection.start)
 4074                                .next()
 4075                                .is_none_or(|c| scope.should_autoclose_before(c));
 4076
 4077                            let preceding_text_allows_autoclose = selection.start.column == 0
 4078                                || snapshot
 4079                                    .reversed_chars_at(selection.start)
 4080                                    .next()
 4081                                    .is_none_or(|c| {
 4082                                        bracket_pair.start != bracket_pair.end
 4083                                            || !snapshot
 4084                                                .char_classifier_at(selection.start)
 4085                                                .is_word(c)
 4086                                    });
 4087
 4088                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4089                                && bracket_pair.start.len() == 1
 4090                            {
 4091                                let target = bracket_pair.start.chars().next().unwrap();
 4092                                let current_line_count = snapshot
 4093                                    .reversed_chars_at(selection.start)
 4094                                    .take_while(|&c| c != '\n')
 4095                                    .filter(|&c| c == target)
 4096                                    .count();
 4097                                current_line_count % 2 == 1
 4098                            } else {
 4099                                false
 4100                            };
 4101
 4102                            if autoclose
 4103                                && bracket_pair.close
 4104                                && following_text_allows_autoclose
 4105                                && preceding_text_allows_autoclose
 4106                                && !is_closing_quote
 4107                            {
 4108                                let anchor = snapshot.anchor_before(selection.end);
 4109                                new_selections.push((selection.map(|_| anchor), text.len()));
 4110                                new_autoclose_regions.push((
 4111                                    anchor,
 4112                                    text.len(),
 4113                                    selection.id,
 4114                                    bracket_pair.clone(),
 4115                                ));
 4116                                edits.push((
 4117                                    selection.range(),
 4118                                    format!("{}{}", text, bracket_pair.end).into(),
 4119                                ));
 4120                                bracket_inserted = true;
 4121                                continue;
 4122                            }
 4123                        }
 4124
 4125                        if let Some(region) = autoclose_region {
 4126                            // If the selection is followed by an auto-inserted closing bracket,
 4127                            // then don't insert that closing bracket again; just move the selection
 4128                            // past the closing bracket.
 4129                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4130                                && text.as_ref() == region.pair.end.as_str()
 4131                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4132                            if should_skip {
 4133                                let anchor = snapshot.anchor_after(selection.end);
 4134                                new_selections
 4135                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4136                                continue;
 4137                            }
 4138                        }
 4139
 4140                        let always_treat_brackets_as_autoclosed = snapshot
 4141                            .language_settings_at(selection.start, cx)
 4142                            .always_treat_brackets_as_autoclosed;
 4143                        if always_treat_brackets_as_autoclosed
 4144                            && is_bracket_pair_end
 4145                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4146                        {
 4147                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4148                            // and the inserted text is a closing bracket and the selection is followed
 4149                            // by the closing bracket then move the selection past the closing bracket.
 4150                            let anchor = snapshot.anchor_after(selection.end);
 4151                            new_selections.push((selection.map(|_| anchor), text.len()));
 4152                            continue;
 4153                        }
 4154                    }
 4155                    // If an opening bracket is 1 character long and is typed while
 4156                    // text is selected, then surround that text with the bracket pair.
 4157                    else if auto_surround
 4158                        && bracket_pair.surround
 4159                        && is_bracket_pair_start
 4160                        && bracket_pair.start.chars().count() == 1
 4161                    {
 4162                        edits.push((selection.start..selection.start, text.clone()));
 4163                        edits.push((
 4164                            selection.end..selection.end,
 4165                            bracket_pair.end.as_str().into(),
 4166                        ));
 4167                        bracket_inserted = true;
 4168                        new_selections.push((
 4169                            Selection {
 4170                                id: selection.id,
 4171                                start: snapshot.anchor_after(selection.start),
 4172                                end: snapshot.anchor_before(selection.end),
 4173                                reversed: selection.reversed,
 4174                                goal: selection.goal,
 4175                            },
 4176                            0,
 4177                        ));
 4178                        continue;
 4179                    }
 4180                }
 4181            }
 4182
 4183            if self.auto_replace_emoji_shortcode
 4184                && selection.is_empty()
 4185                && text.as_ref().ends_with(':')
 4186                && let Some(possible_emoji_short_code) =
 4187                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4188                && !possible_emoji_short_code.is_empty()
 4189                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4190            {
 4191                let emoji_shortcode_start = Point::new(
 4192                    selection.start.row,
 4193                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4194                );
 4195
 4196                // Remove shortcode from buffer
 4197                edits.push((
 4198                    emoji_shortcode_start..selection.start,
 4199                    "".to_string().into(),
 4200                ));
 4201                new_selections.push((
 4202                    Selection {
 4203                        id: selection.id,
 4204                        start: snapshot.anchor_after(emoji_shortcode_start),
 4205                        end: snapshot.anchor_before(selection.start),
 4206                        reversed: selection.reversed,
 4207                        goal: selection.goal,
 4208                    },
 4209                    0,
 4210                ));
 4211
 4212                // Insert emoji
 4213                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4214                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4215                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4216
 4217                continue;
 4218            }
 4219
 4220            // If not handling any auto-close operation, then just replace the selected
 4221            // text with the given input and move the selection to the end of the
 4222            // newly inserted text.
 4223            let anchor = snapshot.anchor_after(selection.end);
 4224            if !self.linked_edit_ranges.is_empty() {
 4225                let start_anchor = snapshot.anchor_before(selection.start);
 4226
 4227                let is_word_char = text.chars().next().is_none_or(|char| {
 4228                    let classifier = snapshot
 4229                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4230                        .ignore_punctuation(true);
 4231                    classifier.is_word(char)
 4232                });
 4233
 4234                if is_word_char {
 4235                    if let Some(ranges) = self
 4236                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4237                    {
 4238                        for (buffer, edits) in ranges {
 4239                            linked_edits
 4240                                .entry(buffer.clone())
 4241                                .or_default()
 4242                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4243                        }
 4244                    }
 4245                } else {
 4246                    clear_linked_edit_ranges = true;
 4247                }
 4248            }
 4249
 4250            new_selections.push((selection.map(|_| anchor), 0));
 4251            edits.push((selection.start..selection.end, text.clone()));
 4252        }
 4253
 4254        drop(snapshot);
 4255
 4256        self.transact(window, cx, |this, window, cx| {
 4257            if clear_linked_edit_ranges {
 4258                this.linked_edit_ranges.clear();
 4259            }
 4260            let initial_buffer_versions =
 4261                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4262
 4263            this.buffer.update(cx, |buffer, cx| {
 4264                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4265            });
 4266            for (buffer, edits) in linked_edits {
 4267                buffer.update(cx, |buffer, cx| {
 4268                    let snapshot = buffer.snapshot();
 4269                    let edits = edits
 4270                        .into_iter()
 4271                        .map(|(range, text)| {
 4272                            use text::ToPoint as TP;
 4273                            let end_point = TP::to_point(&range.end, &snapshot);
 4274                            let start_point = TP::to_point(&range.start, &snapshot);
 4275                            (start_point..end_point, text)
 4276                        })
 4277                        .sorted_by_key(|(range, _)| range.start);
 4278                    buffer.edit(edits, None, cx);
 4279                })
 4280            }
 4281            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4282            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4283            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4284            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4285                .zip(new_selection_deltas)
 4286                .map(|(selection, delta)| Selection {
 4287                    id: selection.id,
 4288                    start: selection.start + delta,
 4289                    end: selection.end + delta,
 4290                    reversed: selection.reversed,
 4291                    goal: SelectionGoal::None,
 4292                })
 4293                .collect::<Vec<_>>();
 4294
 4295            let mut i = 0;
 4296            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4297                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4298                let start = map.buffer_snapshot.anchor_before(position);
 4299                let end = map.buffer_snapshot.anchor_after(position);
 4300                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4301                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4302                        Ordering::Less => i += 1,
 4303                        Ordering::Greater => break,
 4304                        Ordering::Equal => {
 4305                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4306                                Ordering::Less => i += 1,
 4307                                Ordering::Equal => break,
 4308                                Ordering::Greater => break,
 4309                            }
 4310                        }
 4311                    }
 4312                }
 4313                this.autoclose_regions.insert(
 4314                    i,
 4315                    AutocloseRegion {
 4316                        selection_id,
 4317                        range: start..end,
 4318                        pair,
 4319                    },
 4320                );
 4321            }
 4322
 4323            let had_active_edit_prediction = this.has_active_edit_prediction();
 4324            this.change_selections(
 4325                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4326                window,
 4327                cx,
 4328                |s| s.select(new_selections),
 4329            );
 4330
 4331            if !bracket_inserted
 4332                && let Some(on_type_format_task) =
 4333                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4334            {
 4335                on_type_format_task.detach_and_log_err(cx);
 4336            }
 4337
 4338            let editor_settings = EditorSettings::get_global(cx);
 4339            if bracket_inserted
 4340                && (editor_settings.auto_signature_help
 4341                    || editor_settings.show_signature_help_after_edits)
 4342            {
 4343                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4344            }
 4345
 4346            let trigger_in_words =
 4347                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4348            if this.hard_wrap.is_some() {
 4349                let latest: Range<Point> = this.selections.newest(cx).range();
 4350                if latest.is_empty()
 4351                    && this
 4352                        .buffer()
 4353                        .read(cx)
 4354                        .snapshot(cx)
 4355                        .line_len(MultiBufferRow(latest.start.row))
 4356                        == latest.start.column
 4357                {
 4358                    this.rewrap_impl(
 4359                        RewrapOptions {
 4360                            override_language_settings: true,
 4361                            preserve_existing_whitespace: true,
 4362                        },
 4363                        cx,
 4364                    )
 4365                }
 4366            }
 4367            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4368            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4369            this.refresh_edit_prediction(true, false, window, cx);
 4370            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4371        });
 4372    }
 4373
 4374    fn find_possible_emoji_shortcode_at_position(
 4375        snapshot: &MultiBufferSnapshot,
 4376        position: Point,
 4377    ) -> Option<String> {
 4378        let mut chars = Vec::new();
 4379        let mut found_colon = false;
 4380        for char in snapshot.reversed_chars_at(position).take(100) {
 4381            // Found a possible emoji shortcode in the middle of the buffer
 4382            if found_colon {
 4383                if char.is_whitespace() {
 4384                    chars.reverse();
 4385                    return Some(chars.iter().collect());
 4386                }
 4387                // If the previous character is not a whitespace, we are in the middle of a word
 4388                // and we only want to complete the shortcode if the word is made up of other emojis
 4389                let mut containing_word = String::new();
 4390                for ch in snapshot
 4391                    .reversed_chars_at(position)
 4392                    .skip(chars.len() + 1)
 4393                    .take(100)
 4394                {
 4395                    if ch.is_whitespace() {
 4396                        break;
 4397                    }
 4398                    containing_word.push(ch);
 4399                }
 4400                let containing_word = containing_word.chars().rev().collect::<String>();
 4401                if util::word_consists_of_emojis(containing_word.as_str()) {
 4402                    chars.reverse();
 4403                    return Some(chars.iter().collect());
 4404                }
 4405            }
 4406
 4407            if char.is_whitespace() || !char.is_ascii() {
 4408                return None;
 4409            }
 4410            if char == ':' {
 4411                found_colon = true;
 4412            } else {
 4413                chars.push(char);
 4414            }
 4415        }
 4416        // Found a possible emoji shortcode at the beginning of the buffer
 4417        chars.reverse();
 4418        Some(chars.iter().collect())
 4419    }
 4420
 4421    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4423        self.transact(window, cx, |this, window, cx| {
 4424            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4425                let selections = this.selections.all::<usize>(cx);
 4426                let multi_buffer = this.buffer.read(cx);
 4427                let buffer = multi_buffer.snapshot(cx);
 4428                selections
 4429                    .iter()
 4430                    .map(|selection| {
 4431                        let start_point = selection.start.to_point(&buffer);
 4432                        let mut existing_indent =
 4433                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4434                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4435                        let start = selection.start;
 4436                        let end = selection.end;
 4437                        let selection_is_empty = start == end;
 4438                        let language_scope = buffer.language_scope_at(start);
 4439                        let (
 4440                            comment_delimiter,
 4441                            doc_delimiter,
 4442                            insert_extra_newline,
 4443                            indent_on_newline,
 4444                            indent_on_extra_newline,
 4445                        ) = if let Some(language) = &language_scope {
 4446                            let mut insert_extra_newline =
 4447                                insert_extra_newline_brackets(&buffer, start..end, language)
 4448                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4449
 4450                            // Comment extension on newline is allowed only for cursor selections
 4451                            let comment_delimiter = maybe!({
 4452                                if !selection_is_empty {
 4453                                    return None;
 4454                                }
 4455
 4456                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4457                                    return None;
 4458                                }
 4459
 4460                                let delimiters = language.line_comment_prefixes();
 4461                                let max_len_of_delimiter =
 4462                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4463                                let (snapshot, range) =
 4464                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4465
 4466                                let num_of_whitespaces = snapshot
 4467                                    .chars_for_range(range.clone())
 4468                                    .take_while(|c| c.is_whitespace())
 4469                                    .count();
 4470                                let comment_candidate = snapshot
 4471                                    .chars_for_range(range.clone())
 4472                                    .skip(num_of_whitespaces)
 4473                                    .take(max_len_of_delimiter)
 4474                                    .collect::<String>();
 4475                                let (delimiter, trimmed_len) = delimiters
 4476                                    .iter()
 4477                                    .filter_map(|delimiter| {
 4478                                        let prefix = delimiter.trim_end();
 4479                                        if comment_candidate.starts_with(prefix) {
 4480                                            Some((delimiter, prefix.len()))
 4481                                        } else {
 4482                                            None
 4483                                        }
 4484                                    })
 4485                                    .max_by_key(|(_, len)| *len)?;
 4486
 4487                                if let Some(BlockCommentConfig {
 4488                                    start: block_start, ..
 4489                                }) = language.block_comment()
 4490                                {
 4491                                    let block_start_trimmed = block_start.trim_end();
 4492                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4493                                        let line_content = snapshot
 4494                                            .chars_for_range(range)
 4495                                            .skip(num_of_whitespaces)
 4496                                            .take(block_start_trimmed.len())
 4497                                            .collect::<String>();
 4498
 4499                                        if line_content.starts_with(block_start_trimmed) {
 4500                                            return None;
 4501                                        }
 4502                                    }
 4503                                }
 4504
 4505                                let cursor_is_placed_after_comment_marker =
 4506                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4507                                if cursor_is_placed_after_comment_marker {
 4508                                    Some(delimiter.clone())
 4509                                } else {
 4510                                    None
 4511                                }
 4512                            });
 4513
 4514                            let mut indent_on_newline = IndentSize::spaces(0);
 4515                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4516
 4517                            let doc_delimiter = maybe!({
 4518                                if !selection_is_empty {
 4519                                    return None;
 4520                                }
 4521
 4522                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4523                                    return None;
 4524                                }
 4525
 4526                                let BlockCommentConfig {
 4527                                    start: start_tag,
 4528                                    end: end_tag,
 4529                                    prefix: delimiter,
 4530                                    tab_size: len,
 4531                                } = language.documentation_comment()?;
 4532                                let is_within_block_comment = buffer
 4533                                    .language_scope_at(start_point)
 4534                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4535                                if !is_within_block_comment {
 4536                                    return None;
 4537                                }
 4538
 4539                                let (snapshot, range) =
 4540                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4541
 4542                                let num_of_whitespaces = snapshot
 4543                                    .chars_for_range(range.clone())
 4544                                    .take_while(|c| c.is_whitespace())
 4545                                    .count();
 4546
 4547                                // 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.
 4548                                let column = start_point.column;
 4549                                let cursor_is_after_start_tag = {
 4550                                    let start_tag_len = start_tag.len();
 4551                                    let start_tag_line = snapshot
 4552                                        .chars_for_range(range.clone())
 4553                                        .skip(num_of_whitespaces)
 4554                                        .take(start_tag_len)
 4555                                        .collect::<String>();
 4556                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4557                                        num_of_whitespaces + start_tag_len <= column as usize
 4558                                    } else {
 4559                                        false
 4560                                    }
 4561                                };
 4562
 4563                                let cursor_is_after_delimiter = {
 4564                                    let delimiter_trim = delimiter.trim_end();
 4565                                    let delimiter_line = snapshot
 4566                                        .chars_for_range(range.clone())
 4567                                        .skip(num_of_whitespaces)
 4568                                        .take(delimiter_trim.len())
 4569                                        .collect::<String>();
 4570                                    if delimiter_line.starts_with(delimiter_trim) {
 4571                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4572                                    } else {
 4573                                        false
 4574                                    }
 4575                                };
 4576
 4577                                let cursor_is_before_end_tag_if_exists = {
 4578                                    let mut char_position = 0u32;
 4579                                    let mut end_tag_offset = None;
 4580
 4581                                    'outer: for chunk in snapshot.text_for_range(range) {
 4582                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4583                                            let chars_before_match =
 4584                                                chunk[..byte_pos].chars().count() as u32;
 4585                                            end_tag_offset =
 4586                                                Some(char_position + chars_before_match);
 4587                                            break 'outer;
 4588                                        }
 4589                                        char_position += chunk.chars().count() as u32;
 4590                                    }
 4591
 4592                                    if let Some(end_tag_offset) = end_tag_offset {
 4593                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4594                                        if cursor_is_after_start_tag {
 4595                                            if cursor_is_before_end_tag {
 4596                                                insert_extra_newline = true;
 4597                                            }
 4598                                            let cursor_is_at_start_of_end_tag =
 4599                                                column == end_tag_offset;
 4600                                            if cursor_is_at_start_of_end_tag {
 4601                                                indent_on_extra_newline.len = *len;
 4602                                            }
 4603                                        }
 4604                                        cursor_is_before_end_tag
 4605                                    } else {
 4606                                        true
 4607                                    }
 4608                                };
 4609
 4610                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4611                                    && cursor_is_before_end_tag_if_exists
 4612                                {
 4613                                    if cursor_is_after_start_tag {
 4614                                        indent_on_newline.len = *len;
 4615                                    }
 4616                                    Some(delimiter.clone())
 4617                                } else {
 4618                                    None
 4619                                }
 4620                            });
 4621
 4622                            (
 4623                                comment_delimiter,
 4624                                doc_delimiter,
 4625                                insert_extra_newline,
 4626                                indent_on_newline,
 4627                                indent_on_extra_newline,
 4628                            )
 4629                        } else {
 4630                            (
 4631                                None,
 4632                                None,
 4633                                false,
 4634                                IndentSize::default(),
 4635                                IndentSize::default(),
 4636                            )
 4637                        };
 4638
 4639                        let prevent_auto_indent = doc_delimiter.is_some();
 4640                        let delimiter = comment_delimiter.or(doc_delimiter);
 4641
 4642                        let capacity_for_delimiter =
 4643                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4644                        let mut new_text = String::with_capacity(
 4645                            1 + capacity_for_delimiter
 4646                                + existing_indent.len as usize
 4647                                + indent_on_newline.len as usize
 4648                                + indent_on_extra_newline.len as usize,
 4649                        );
 4650                        new_text.push('\n');
 4651                        new_text.extend(existing_indent.chars());
 4652                        new_text.extend(indent_on_newline.chars());
 4653
 4654                        if let Some(delimiter) = &delimiter {
 4655                            new_text.push_str(delimiter);
 4656                        }
 4657
 4658                        if insert_extra_newline {
 4659                            new_text.push('\n');
 4660                            new_text.extend(existing_indent.chars());
 4661                            new_text.extend(indent_on_extra_newline.chars());
 4662                        }
 4663
 4664                        let anchor = buffer.anchor_after(end);
 4665                        let new_selection = selection.map(|_| anchor);
 4666                        (
 4667                            ((start..end, new_text), prevent_auto_indent),
 4668                            (insert_extra_newline, new_selection),
 4669                        )
 4670                    })
 4671                    .unzip()
 4672            };
 4673
 4674            let mut auto_indent_edits = Vec::new();
 4675            let mut edits = Vec::new();
 4676            for (edit, prevent_auto_indent) in edits_with_flags {
 4677                if prevent_auto_indent {
 4678                    edits.push(edit);
 4679                } else {
 4680                    auto_indent_edits.push(edit);
 4681                }
 4682            }
 4683            if !edits.is_empty() {
 4684                this.edit(edits, cx);
 4685            }
 4686            if !auto_indent_edits.is_empty() {
 4687                this.edit_with_autoindent(auto_indent_edits, cx);
 4688            }
 4689
 4690            let buffer = this.buffer.read(cx).snapshot(cx);
 4691            let new_selections = selection_info
 4692                .into_iter()
 4693                .map(|(extra_newline_inserted, new_selection)| {
 4694                    let mut cursor = new_selection.end.to_point(&buffer);
 4695                    if extra_newline_inserted {
 4696                        cursor.row -= 1;
 4697                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4698                    }
 4699                    new_selection.map(|_| cursor)
 4700                })
 4701                .collect();
 4702
 4703            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4704            this.refresh_edit_prediction(true, false, window, cx);
 4705        });
 4706    }
 4707
 4708    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4709        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4710
 4711        let buffer = self.buffer.read(cx);
 4712        let snapshot = buffer.snapshot(cx);
 4713
 4714        let mut edits = Vec::new();
 4715        let mut rows = Vec::new();
 4716
 4717        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4718            let cursor = selection.head();
 4719            let row = cursor.row;
 4720
 4721            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4722
 4723            let newline = "\n".to_string();
 4724            edits.push((start_of_line..start_of_line, newline));
 4725
 4726            rows.push(row + rows_inserted as u32);
 4727        }
 4728
 4729        self.transact(window, cx, |editor, window, cx| {
 4730            editor.edit(edits, cx);
 4731
 4732            editor.change_selections(Default::default(), window, cx, |s| {
 4733                let mut index = 0;
 4734                s.move_cursors_with(|map, _, _| {
 4735                    let row = rows[index];
 4736                    index += 1;
 4737
 4738                    let point = Point::new(row, 0);
 4739                    let boundary = map.next_line_boundary(point).1;
 4740                    let clipped = map.clip_point(boundary, Bias::Left);
 4741
 4742                    (clipped, SelectionGoal::None)
 4743                });
 4744            });
 4745
 4746            let mut indent_edits = Vec::new();
 4747            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4748            for row in rows {
 4749                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4750                for (row, indent) in indents {
 4751                    if indent.len == 0 {
 4752                        continue;
 4753                    }
 4754
 4755                    let text = match indent.kind {
 4756                        IndentKind::Space => " ".repeat(indent.len as usize),
 4757                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4758                    };
 4759                    let point = Point::new(row.0, 0);
 4760                    indent_edits.push((point..point, text));
 4761                }
 4762            }
 4763            editor.edit(indent_edits, cx);
 4764        });
 4765    }
 4766
 4767    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4768        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4769
 4770        let buffer = self.buffer.read(cx);
 4771        let snapshot = buffer.snapshot(cx);
 4772
 4773        let mut edits = Vec::new();
 4774        let mut rows = Vec::new();
 4775        let mut rows_inserted = 0;
 4776
 4777        for selection in self.selections.all_adjusted(cx) {
 4778            let cursor = selection.head();
 4779            let row = cursor.row;
 4780
 4781            let point = Point::new(row + 1, 0);
 4782            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4783
 4784            let newline = "\n".to_string();
 4785            edits.push((start_of_line..start_of_line, newline));
 4786
 4787            rows_inserted += 1;
 4788            rows.push(row + rows_inserted);
 4789        }
 4790
 4791        self.transact(window, cx, |editor, window, cx| {
 4792            editor.edit(edits, cx);
 4793
 4794            editor.change_selections(Default::default(), window, cx, |s| {
 4795                let mut index = 0;
 4796                s.move_cursors_with(|map, _, _| {
 4797                    let row = rows[index];
 4798                    index += 1;
 4799
 4800                    let point = Point::new(row, 0);
 4801                    let boundary = map.next_line_boundary(point).1;
 4802                    let clipped = map.clip_point(boundary, Bias::Left);
 4803
 4804                    (clipped, SelectionGoal::None)
 4805                });
 4806            });
 4807
 4808            let mut indent_edits = Vec::new();
 4809            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4810            for row in rows {
 4811                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4812                for (row, indent) in indents {
 4813                    if indent.len == 0 {
 4814                        continue;
 4815                    }
 4816
 4817                    let text = match indent.kind {
 4818                        IndentKind::Space => " ".repeat(indent.len as usize),
 4819                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4820                    };
 4821                    let point = Point::new(row.0, 0);
 4822                    indent_edits.push((point..point, text));
 4823                }
 4824            }
 4825            editor.edit(indent_edits, cx);
 4826        });
 4827    }
 4828
 4829    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4830        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4831            original_indent_columns: Vec::new(),
 4832        });
 4833        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4834    }
 4835
 4836    fn insert_with_autoindent_mode(
 4837        &mut self,
 4838        text: &str,
 4839        autoindent_mode: Option<AutoindentMode>,
 4840        window: &mut Window,
 4841        cx: &mut Context<Self>,
 4842    ) {
 4843        if self.read_only(cx) {
 4844            return;
 4845        }
 4846
 4847        let text: Arc<str> = text.into();
 4848        self.transact(window, cx, |this, window, cx| {
 4849            let old_selections = this.selections.all_adjusted(cx);
 4850            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4851                let anchors = {
 4852                    let snapshot = buffer.read(cx);
 4853                    old_selections
 4854                        .iter()
 4855                        .map(|s| {
 4856                            let anchor = snapshot.anchor_after(s.head());
 4857                            s.map(|_| anchor)
 4858                        })
 4859                        .collect::<Vec<_>>()
 4860                };
 4861                buffer.edit(
 4862                    old_selections
 4863                        .iter()
 4864                        .map(|s| (s.start..s.end, text.clone())),
 4865                    autoindent_mode,
 4866                    cx,
 4867                );
 4868                anchors
 4869            });
 4870
 4871            this.change_selections(Default::default(), window, cx, |s| {
 4872                s.select_anchors(selection_anchors);
 4873            });
 4874
 4875            cx.notify();
 4876        });
 4877    }
 4878
 4879    fn trigger_completion_on_input(
 4880        &mut self,
 4881        text: &str,
 4882        trigger_in_words: bool,
 4883        window: &mut Window,
 4884        cx: &mut Context<Self>,
 4885    ) {
 4886        let completions_source = self
 4887            .context_menu
 4888            .borrow()
 4889            .as_ref()
 4890            .and_then(|menu| match menu {
 4891                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4892                CodeContextMenu::CodeActions(_) => None,
 4893            });
 4894
 4895        match completions_source {
 4896            Some(CompletionsMenuSource::Words) => {
 4897                self.show_word_completions(&ShowWordCompletions, window, cx)
 4898            }
 4899            Some(CompletionsMenuSource::Normal)
 4900            | Some(CompletionsMenuSource::SnippetChoices)
 4901            | None
 4902                if self.is_completion_trigger(
 4903                    text,
 4904                    trigger_in_words,
 4905                    completions_source.is_some(),
 4906                    cx,
 4907                ) =>
 4908            {
 4909                self.show_completions(
 4910                    &ShowCompletions {
 4911                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4912                    },
 4913                    window,
 4914                    cx,
 4915                )
 4916            }
 4917            _ => {
 4918                self.hide_context_menu(window, cx);
 4919            }
 4920        }
 4921    }
 4922
 4923    fn is_completion_trigger(
 4924        &self,
 4925        text: &str,
 4926        trigger_in_words: bool,
 4927        menu_is_open: bool,
 4928        cx: &mut Context<Self>,
 4929    ) -> bool {
 4930        let position = self.selections.newest_anchor().head();
 4931        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4932            return false;
 4933        };
 4934
 4935        if let Some(completion_provider) = &self.completion_provider {
 4936            completion_provider.is_completion_trigger(
 4937                &buffer,
 4938                position.text_anchor,
 4939                text,
 4940                trigger_in_words,
 4941                menu_is_open,
 4942                cx,
 4943            )
 4944        } else {
 4945            false
 4946        }
 4947    }
 4948
 4949    /// If any empty selections is touching the start of its innermost containing autoclose
 4950    /// region, expand it to select the brackets.
 4951    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4952        let selections = self.selections.all::<usize>(cx);
 4953        let buffer = self.buffer.read(cx).read(cx);
 4954        let new_selections = self
 4955            .selections_with_autoclose_regions(selections, &buffer)
 4956            .map(|(mut selection, region)| {
 4957                if !selection.is_empty() {
 4958                    return selection;
 4959                }
 4960
 4961                if let Some(region) = region {
 4962                    let mut range = region.range.to_offset(&buffer);
 4963                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4964                        range.start -= region.pair.start.len();
 4965                        if buffer.contains_str_at(range.start, &region.pair.start)
 4966                            && buffer.contains_str_at(range.end, &region.pair.end)
 4967                        {
 4968                            range.end += region.pair.end.len();
 4969                            selection.start = range.start;
 4970                            selection.end = range.end;
 4971
 4972                            return selection;
 4973                        }
 4974                    }
 4975                }
 4976
 4977                let always_treat_brackets_as_autoclosed = buffer
 4978                    .language_settings_at(selection.start, cx)
 4979                    .always_treat_brackets_as_autoclosed;
 4980
 4981                if !always_treat_brackets_as_autoclosed {
 4982                    return selection;
 4983                }
 4984
 4985                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4986                    for (pair, enabled) in scope.brackets() {
 4987                        if !enabled || !pair.close {
 4988                            continue;
 4989                        }
 4990
 4991                        if buffer.contains_str_at(selection.start, &pair.end) {
 4992                            let pair_start_len = pair.start.len();
 4993                            if buffer.contains_str_at(
 4994                                selection.start.saturating_sub(pair_start_len),
 4995                                &pair.start,
 4996                            ) {
 4997                                selection.start -= pair_start_len;
 4998                                selection.end += pair.end.len();
 4999
 5000                                return selection;
 5001                            }
 5002                        }
 5003                    }
 5004                }
 5005
 5006                selection
 5007            })
 5008            .collect();
 5009
 5010        drop(buffer);
 5011        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5012            selections.select(new_selections)
 5013        });
 5014    }
 5015
 5016    /// Iterate the given selections, and for each one, find the smallest surrounding
 5017    /// autoclose region. This uses the ordering of the selections and the autoclose
 5018    /// regions to avoid repeated comparisons.
 5019    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5020        &'a self,
 5021        selections: impl IntoIterator<Item = Selection<D>>,
 5022        buffer: &'a MultiBufferSnapshot,
 5023    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5024        let mut i = 0;
 5025        let mut regions = self.autoclose_regions.as_slice();
 5026        selections.into_iter().map(move |selection| {
 5027            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5028
 5029            let mut enclosing = None;
 5030            while let Some(pair_state) = regions.get(i) {
 5031                if pair_state.range.end.to_offset(buffer) < range.start {
 5032                    regions = &regions[i + 1..];
 5033                    i = 0;
 5034                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5035                    break;
 5036                } else {
 5037                    if pair_state.selection_id == selection.id {
 5038                        enclosing = Some(pair_state);
 5039                    }
 5040                    i += 1;
 5041                }
 5042            }
 5043
 5044            (selection, enclosing)
 5045        })
 5046    }
 5047
 5048    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5049    fn invalidate_autoclose_regions(
 5050        &mut self,
 5051        mut selections: &[Selection<Anchor>],
 5052        buffer: &MultiBufferSnapshot,
 5053    ) {
 5054        self.autoclose_regions.retain(|state| {
 5055            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5056                return false;
 5057            }
 5058
 5059            let mut i = 0;
 5060            while let Some(selection) = selections.get(i) {
 5061                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5062                    selections = &selections[1..];
 5063                    continue;
 5064                }
 5065                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5066                    break;
 5067                }
 5068                if selection.id == state.selection_id {
 5069                    return true;
 5070                } else {
 5071                    i += 1;
 5072                }
 5073            }
 5074            false
 5075        });
 5076    }
 5077
 5078    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5079        let offset = position.to_offset(buffer);
 5080        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5081        if offset > word_range.start && kind == Some(CharKind::Word) {
 5082            Some(
 5083                buffer
 5084                    .text_for_range(word_range.start..offset)
 5085                    .collect::<String>(),
 5086            )
 5087        } else {
 5088            None
 5089        }
 5090    }
 5091
 5092    pub fn toggle_inline_values(
 5093        &mut self,
 5094        _: &ToggleInlineValues,
 5095        _: &mut Window,
 5096        cx: &mut Context<Self>,
 5097    ) {
 5098        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5099
 5100        self.refresh_inline_values(cx);
 5101    }
 5102
 5103    pub fn toggle_inlay_hints(
 5104        &mut self,
 5105        _: &ToggleInlayHints,
 5106        _: &mut Window,
 5107        cx: &mut Context<Self>,
 5108    ) {
 5109        self.refresh_inlay_hints(
 5110            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5111            cx,
 5112        );
 5113    }
 5114
 5115    pub fn inlay_hints_enabled(&self) -> bool {
 5116        self.inlay_hint_cache.enabled
 5117    }
 5118
 5119    pub fn inline_values_enabled(&self) -> bool {
 5120        self.inline_value_cache.enabled
 5121    }
 5122
 5123    #[cfg(any(test, feature = "test-support"))]
 5124    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5125        self.display_map
 5126            .read(cx)
 5127            .current_inlays()
 5128            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5129            .cloned()
 5130            .collect()
 5131    }
 5132
 5133    #[cfg(any(test, feature = "test-support"))]
 5134    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5135        self.display_map
 5136            .read(cx)
 5137            .current_inlays()
 5138            .cloned()
 5139            .collect()
 5140    }
 5141
 5142    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5143        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5144            return;
 5145        }
 5146
 5147        let reason_description = reason.description();
 5148        let ignore_debounce = matches!(
 5149            reason,
 5150            InlayHintRefreshReason::SettingsChange(_)
 5151                | InlayHintRefreshReason::Toggle(_)
 5152                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5153                | InlayHintRefreshReason::ModifiersChanged(_)
 5154        );
 5155        let (invalidate_cache, required_languages) = match reason {
 5156            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5157                match self.inlay_hint_cache.modifiers_override(enabled) {
 5158                    Some(enabled) => {
 5159                        if enabled {
 5160                            (InvalidationStrategy::RefreshRequested, None)
 5161                        } else {
 5162                            self.splice_inlays(
 5163                                &self
 5164                                    .visible_inlay_hints(cx)
 5165                                    .iter()
 5166                                    .map(|inlay| inlay.id)
 5167                                    .collect::<Vec<InlayId>>(),
 5168                                Vec::new(),
 5169                                cx,
 5170                            );
 5171                            return;
 5172                        }
 5173                    }
 5174                    None => return,
 5175                }
 5176            }
 5177            InlayHintRefreshReason::Toggle(enabled) => {
 5178                if self.inlay_hint_cache.toggle(enabled) {
 5179                    if enabled {
 5180                        (InvalidationStrategy::RefreshRequested, None)
 5181                    } else {
 5182                        self.splice_inlays(
 5183                            &self
 5184                                .visible_inlay_hints(cx)
 5185                                .iter()
 5186                                .map(|inlay| inlay.id)
 5187                                .collect::<Vec<InlayId>>(),
 5188                            Vec::new(),
 5189                            cx,
 5190                        );
 5191                        return;
 5192                    }
 5193                } else {
 5194                    return;
 5195                }
 5196            }
 5197            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5198                match self.inlay_hint_cache.update_settings(
 5199                    &self.buffer,
 5200                    new_settings,
 5201                    self.visible_inlay_hints(cx),
 5202                    cx,
 5203                ) {
 5204                    ControlFlow::Break(Some(InlaySplice {
 5205                        to_remove,
 5206                        to_insert,
 5207                    })) => {
 5208                        self.splice_inlays(&to_remove, to_insert, cx);
 5209                        return;
 5210                    }
 5211                    ControlFlow::Break(None) => return,
 5212                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5213                }
 5214            }
 5215            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5216                if let Some(InlaySplice {
 5217                    to_remove,
 5218                    to_insert,
 5219                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5220                {
 5221                    self.splice_inlays(&to_remove, to_insert, cx);
 5222                }
 5223                self.display_map.update(cx, |display_map, _| {
 5224                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5225                });
 5226                return;
 5227            }
 5228            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5229            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5230                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5231            }
 5232            InlayHintRefreshReason::RefreshRequested => {
 5233                (InvalidationStrategy::RefreshRequested, None)
 5234            }
 5235        };
 5236
 5237        if let Some(InlaySplice {
 5238            to_remove,
 5239            to_insert,
 5240        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5241            reason_description,
 5242            self.visible_excerpts(required_languages.as_ref(), cx),
 5243            invalidate_cache,
 5244            ignore_debounce,
 5245            cx,
 5246        ) {
 5247            self.splice_inlays(&to_remove, to_insert, cx);
 5248        }
 5249    }
 5250
 5251    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5252        self.display_map
 5253            .read(cx)
 5254            .current_inlays()
 5255            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5256            .cloned()
 5257            .collect()
 5258    }
 5259
 5260    pub fn visible_excerpts(
 5261        &self,
 5262        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5263        cx: &mut Context<Editor>,
 5264    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5265        let Some(project) = self.project() else {
 5266            return HashMap::default();
 5267        };
 5268        let project = project.read(cx);
 5269        let multi_buffer = self.buffer().read(cx);
 5270        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5271        let multi_buffer_visible_start = self
 5272            .scroll_manager
 5273            .anchor()
 5274            .anchor
 5275            .to_point(&multi_buffer_snapshot);
 5276        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5277            multi_buffer_visible_start
 5278                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5279            Bias::Left,
 5280        );
 5281        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5282        multi_buffer_snapshot
 5283            .range_to_buffer_ranges(multi_buffer_visible_range)
 5284            .into_iter()
 5285            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5286            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5287                let buffer_file = project::File::from_dyn(buffer.file())?;
 5288                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5289                let worktree_entry = buffer_worktree
 5290                    .read(cx)
 5291                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5292                if worktree_entry.is_ignored {
 5293                    return None;
 5294                }
 5295
 5296                let language = buffer.language()?;
 5297                if let Some(restrict_to_languages) = restrict_to_languages
 5298                    && !restrict_to_languages.contains(language)
 5299                {
 5300                    return None;
 5301                }
 5302                Some((
 5303                    excerpt_id,
 5304                    (
 5305                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5306                        buffer.version().clone(),
 5307                        excerpt_visible_range,
 5308                    ),
 5309                ))
 5310            })
 5311            .collect()
 5312    }
 5313
 5314    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5315        TextLayoutDetails {
 5316            text_system: window.text_system().clone(),
 5317            editor_style: self.style.clone().unwrap(),
 5318            rem_size: window.rem_size(),
 5319            scroll_anchor: self.scroll_manager.anchor(),
 5320            visible_rows: self.visible_line_count(),
 5321            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5322        }
 5323    }
 5324
 5325    pub fn splice_inlays(
 5326        &self,
 5327        to_remove: &[InlayId],
 5328        to_insert: Vec<Inlay>,
 5329        cx: &mut Context<Self>,
 5330    ) {
 5331        self.display_map.update(cx, |display_map, cx| {
 5332            display_map.splice_inlays(to_remove, to_insert, cx)
 5333        });
 5334        cx.notify();
 5335    }
 5336
 5337    fn trigger_on_type_formatting(
 5338        &self,
 5339        input: String,
 5340        window: &mut Window,
 5341        cx: &mut Context<Self>,
 5342    ) -> Option<Task<Result<()>>> {
 5343        if input.len() != 1 {
 5344            return None;
 5345        }
 5346
 5347        let project = self.project()?;
 5348        let position = self.selections.newest_anchor().head();
 5349        let (buffer, buffer_position) = self
 5350            .buffer
 5351            .read(cx)
 5352            .text_anchor_for_position(position, cx)?;
 5353
 5354        let settings = language_settings::language_settings(
 5355            buffer
 5356                .read(cx)
 5357                .language_at(buffer_position)
 5358                .map(|l| l.name()),
 5359            buffer.read(cx).file(),
 5360            cx,
 5361        );
 5362        if !settings.use_on_type_format {
 5363            return None;
 5364        }
 5365
 5366        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5367        // hence we do LSP request & edit on host side only — add formats to host's history.
 5368        let push_to_lsp_host_history = true;
 5369        // If this is not the host, append its history with new edits.
 5370        let push_to_client_history = project.read(cx).is_via_collab();
 5371
 5372        let on_type_formatting = project.update(cx, |project, cx| {
 5373            project.on_type_format(
 5374                buffer.clone(),
 5375                buffer_position,
 5376                input,
 5377                push_to_lsp_host_history,
 5378                cx,
 5379            )
 5380        });
 5381        Some(cx.spawn_in(window, async move |editor, cx| {
 5382            if let Some(transaction) = on_type_formatting.await? {
 5383                if push_to_client_history {
 5384                    buffer
 5385                        .update(cx, |buffer, _| {
 5386                            buffer.push_transaction(transaction, Instant::now());
 5387                            buffer.finalize_last_transaction();
 5388                        })
 5389                        .ok();
 5390                }
 5391                editor.update(cx, |editor, cx| {
 5392                    editor.refresh_document_highlights(cx);
 5393                })?;
 5394            }
 5395            Ok(())
 5396        }))
 5397    }
 5398
 5399    pub fn show_word_completions(
 5400        &mut self,
 5401        _: &ShowWordCompletions,
 5402        window: &mut Window,
 5403        cx: &mut Context<Self>,
 5404    ) {
 5405        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5406    }
 5407
 5408    pub fn show_completions(
 5409        &mut self,
 5410        options: &ShowCompletions,
 5411        window: &mut Window,
 5412        cx: &mut Context<Self>,
 5413    ) {
 5414        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5415    }
 5416
 5417    fn open_or_update_completions_menu(
 5418        &mut self,
 5419        requested_source: Option<CompletionsMenuSource>,
 5420        trigger: Option<&str>,
 5421        window: &mut Window,
 5422        cx: &mut Context<Self>,
 5423    ) {
 5424        if self.pending_rename.is_some() {
 5425            return;
 5426        }
 5427
 5428        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5429
 5430        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5431        // inserted and selected. To handle that case, the start of the selection is used so that
 5432        // the menu starts with all choices.
 5433        let position = self
 5434            .selections
 5435            .newest_anchor()
 5436            .start
 5437            .bias_right(&multibuffer_snapshot);
 5438        if position.diff_base_anchor.is_some() {
 5439            return;
 5440        }
 5441        let (buffer, buffer_position) =
 5442            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5443                output
 5444            } else {
 5445                return;
 5446            };
 5447        let buffer_snapshot = buffer.read(cx).snapshot();
 5448
 5449        let query: Option<Arc<String>> =
 5450            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5451
 5452        drop(multibuffer_snapshot);
 5453
 5454        let provider = match requested_source {
 5455            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5456            Some(CompletionsMenuSource::Words) => None,
 5457            Some(CompletionsMenuSource::SnippetChoices) => {
 5458                log::error!("bug: SnippetChoices requested_source is not handled");
 5459                None
 5460            }
 5461        };
 5462
 5463        let sort_completions = provider
 5464            .as_ref()
 5465            .is_some_and(|provider| provider.sort_completions());
 5466
 5467        let filter_completions = provider
 5468            .as_ref()
 5469            .is_none_or(|provider| provider.filter_completions());
 5470
 5471        let trigger_kind = match trigger {
 5472            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5473                CompletionTriggerKind::TRIGGER_CHARACTER
 5474            }
 5475            _ => CompletionTriggerKind::INVOKED,
 5476        };
 5477        let completion_context = CompletionContext {
 5478            trigger_character: trigger.and_then(|trigger| {
 5479                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5480                    Some(String::from(trigger))
 5481                } else {
 5482                    None
 5483                }
 5484            }),
 5485            trigger_kind,
 5486        };
 5487
 5488        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5489        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5490        // involve trigger chars, so this is skipped in that case.
 5491        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5492        {
 5493            let menu_is_open = matches!(
 5494                self.context_menu.borrow().as_ref(),
 5495                Some(CodeContextMenu::Completions(_))
 5496            );
 5497            if menu_is_open {
 5498                self.hide_context_menu(window, cx);
 5499            }
 5500        }
 5501
 5502        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5503            if filter_completions {
 5504                menu.filter(query.clone(), provider.clone(), window, cx);
 5505            }
 5506            // When `is_incomplete` is false, no need to re-query completions when the current query
 5507            // is a suffix of the initial query.
 5508            if !menu.is_incomplete {
 5509                // If the new query is a suffix of the old query (typing more characters) and
 5510                // the previous result was complete, the existing completions can be filtered.
 5511                //
 5512                // Note that this is always true for snippet completions.
 5513                let query_matches = match (&menu.initial_query, &query) {
 5514                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5515                    (None, _) => true,
 5516                    _ => false,
 5517                };
 5518                if query_matches {
 5519                    let position_matches = if menu.initial_position == position {
 5520                        true
 5521                    } else {
 5522                        let snapshot = self.buffer.read(cx).read(cx);
 5523                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5524                    };
 5525                    if position_matches {
 5526                        return;
 5527                    }
 5528                }
 5529            }
 5530        };
 5531
 5532        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5533            buffer_snapshot.surrounding_word(buffer_position, false)
 5534        {
 5535            let word_to_exclude = buffer_snapshot
 5536                .text_for_range(word_range.clone())
 5537                .collect::<String>();
 5538            (
 5539                buffer_snapshot.anchor_before(word_range.start)
 5540                    ..buffer_snapshot.anchor_after(buffer_position),
 5541                Some(word_to_exclude),
 5542            )
 5543        } else {
 5544            (buffer_position..buffer_position, None)
 5545        };
 5546
 5547        let language = buffer_snapshot
 5548            .language_at(buffer_position)
 5549            .map(|language| language.name());
 5550
 5551        let completion_settings =
 5552            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5553
 5554        let show_completion_documentation = buffer_snapshot
 5555            .settings_at(buffer_position, cx)
 5556            .show_completion_documentation;
 5557
 5558        // The document can be large, so stay in reasonable bounds when searching for words,
 5559        // otherwise completion pop-up might be slow to appear.
 5560        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5561        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5562        let min_word_search = buffer_snapshot.clip_point(
 5563            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5564            Bias::Left,
 5565        );
 5566        let max_word_search = buffer_snapshot.clip_point(
 5567            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5568            Bias::Right,
 5569        );
 5570        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5571            ..buffer_snapshot.point_to_offset(max_word_search);
 5572
 5573        let skip_digits = query
 5574            .as_ref()
 5575            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5576
 5577        let omit_word_completions = match &query {
 5578            Some(query) => query.chars().count() < completion_settings.words_min_length,
 5579            None => completion_settings.words_min_length != 0,
 5580        };
 5581
 5582        let (mut words, provider_responses) = match &provider {
 5583            Some(provider) => {
 5584                let provider_responses = provider.completions(
 5585                    position.excerpt_id,
 5586                    &buffer,
 5587                    buffer_position,
 5588                    completion_context,
 5589                    window,
 5590                    cx,
 5591                );
 5592
 5593                let words = match (omit_word_completions, completion_settings.words) {
 5594                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5595                        Task::ready(BTreeMap::default())
 5596                    }
 5597                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5598                        .background_spawn(async move {
 5599                            buffer_snapshot.words_in_range(WordsQuery {
 5600                                fuzzy_contents: None,
 5601                                range: word_search_range,
 5602                                skip_digits,
 5603                            })
 5604                        }),
 5605                };
 5606
 5607                (words, provider_responses)
 5608            }
 5609            None => {
 5610                let words = if omit_word_completions {
 5611                    Task::ready(BTreeMap::default())
 5612                } else {
 5613                    cx.background_spawn(async move {
 5614                        buffer_snapshot.words_in_range(WordsQuery {
 5615                            fuzzy_contents: None,
 5616                            range: word_search_range,
 5617                            skip_digits,
 5618                        })
 5619                    })
 5620                };
 5621                (words, Task::ready(Ok(Vec::new())))
 5622            }
 5623        };
 5624
 5625        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5626
 5627        let id = post_inc(&mut self.next_completion_id);
 5628        let task = cx.spawn_in(window, async move |editor, cx| {
 5629            let Ok(()) = editor.update(cx, |this, _| {
 5630                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5631            }) else {
 5632                return;
 5633            };
 5634
 5635            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5636            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5637            let mut completions = Vec::new();
 5638            let mut is_incomplete = false;
 5639            if let Some(provider_responses) = provider_responses.await.log_err()
 5640                && !provider_responses.is_empty()
 5641            {
 5642                for response in provider_responses {
 5643                    completions.extend(response.completions);
 5644                    is_incomplete = is_incomplete || response.is_incomplete;
 5645                }
 5646                if completion_settings.words == WordsCompletionMode::Fallback {
 5647                    words = Task::ready(BTreeMap::default());
 5648                }
 5649            }
 5650
 5651            let mut words = words.await;
 5652            if let Some(word_to_exclude) = &word_to_exclude {
 5653                words.remove(word_to_exclude);
 5654            }
 5655            for lsp_completion in &completions {
 5656                words.remove(&lsp_completion.new_text);
 5657            }
 5658            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5659                replace_range: word_replace_range.clone(),
 5660                new_text: word.clone(),
 5661                label: CodeLabel::plain(word, None),
 5662                icon_path: None,
 5663                documentation: None,
 5664                source: CompletionSource::BufferWord {
 5665                    word_range,
 5666                    resolved: false,
 5667                },
 5668                insert_text_mode: Some(InsertTextMode::AS_IS),
 5669                confirm: None,
 5670            }));
 5671
 5672            let menu = if completions.is_empty() {
 5673                None
 5674            } else {
 5675                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5676                    let languages = editor
 5677                        .workspace
 5678                        .as_ref()
 5679                        .and_then(|(workspace, _)| workspace.upgrade())
 5680                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5681                    let menu = CompletionsMenu::new(
 5682                        id,
 5683                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5684                        sort_completions,
 5685                        show_completion_documentation,
 5686                        position,
 5687                        query.clone(),
 5688                        is_incomplete,
 5689                        buffer.clone(),
 5690                        completions.into(),
 5691                        snippet_sort_order,
 5692                        languages,
 5693                        language,
 5694                        cx,
 5695                    );
 5696
 5697                    let query = if filter_completions { query } else { None };
 5698                    let matches_task = if let Some(query) = query {
 5699                        menu.do_async_filtering(query, cx)
 5700                    } else {
 5701                        Task::ready(menu.unfiltered_matches())
 5702                    };
 5703                    (menu, matches_task)
 5704                }) else {
 5705                    return;
 5706                };
 5707
 5708                let matches = matches_task.await;
 5709
 5710                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5711                    // Newer menu already set, so exit.
 5712                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5713                        editor.context_menu.borrow().as_ref()
 5714                        && prev_menu.id > id
 5715                    {
 5716                        return;
 5717                    };
 5718
 5719                    // Only valid to take prev_menu because it the new menu is immediately set
 5720                    // below, or the menu is hidden.
 5721                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5722                        editor.context_menu.borrow_mut().take()
 5723                    {
 5724                        let position_matches =
 5725                            if prev_menu.initial_position == menu.initial_position {
 5726                                true
 5727                            } else {
 5728                                let snapshot = editor.buffer.read(cx).read(cx);
 5729                                prev_menu.initial_position.to_offset(&snapshot)
 5730                                    == menu.initial_position.to_offset(&snapshot)
 5731                            };
 5732                        if position_matches {
 5733                            // Preserve markdown cache before `set_filter_results` because it will
 5734                            // try to populate the documentation cache.
 5735                            menu.preserve_markdown_cache(prev_menu);
 5736                        }
 5737                    };
 5738
 5739                    menu.set_filter_results(matches, provider, window, cx);
 5740                }) else {
 5741                    return;
 5742                };
 5743
 5744                menu.visible().then_some(menu)
 5745            };
 5746
 5747            editor
 5748                .update_in(cx, |editor, window, cx| {
 5749                    if editor.focus_handle.is_focused(window)
 5750                        && let Some(menu) = menu
 5751                    {
 5752                        *editor.context_menu.borrow_mut() =
 5753                            Some(CodeContextMenu::Completions(menu));
 5754
 5755                        crate::hover_popover::hide_hover(editor, cx);
 5756                        if editor.show_edit_predictions_in_menu() {
 5757                            editor.update_visible_edit_prediction(window, cx);
 5758                        } else {
 5759                            editor.discard_edit_prediction(false, cx);
 5760                        }
 5761
 5762                        cx.notify();
 5763                        return;
 5764                    }
 5765
 5766                    if editor.completion_tasks.len() <= 1 {
 5767                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5768                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5769                        // If it was already hidden and we don't show edit predictions in the menu,
 5770                        // we should also show the edit prediction when available.
 5771                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5772                            editor.update_visible_edit_prediction(window, cx);
 5773                        }
 5774                    }
 5775                })
 5776                .ok();
 5777        });
 5778
 5779        self.completion_tasks.push((id, task));
 5780    }
 5781
 5782    #[cfg(feature = "test-support")]
 5783    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5784        let menu = self.context_menu.borrow();
 5785        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5786            let completions = menu.completions.borrow();
 5787            Some(completions.to_vec())
 5788        } else {
 5789            None
 5790        }
 5791    }
 5792
 5793    pub fn with_completions_menu_matching_id<R>(
 5794        &self,
 5795        id: CompletionId,
 5796        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5797    ) -> R {
 5798        let mut context_menu = self.context_menu.borrow_mut();
 5799        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5800            return f(None);
 5801        };
 5802        if completions_menu.id != id {
 5803            return f(None);
 5804        }
 5805        f(Some(completions_menu))
 5806    }
 5807
 5808    pub fn confirm_completion(
 5809        &mut self,
 5810        action: &ConfirmCompletion,
 5811        window: &mut Window,
 5812        cx: &mut Context<Self>,
 5813    ) -> Option<Task<Result<()>>> {
 5814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5815        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5816    }
 5817
 5818    pub fn confirm_completion_insert(
 5819        &mut self,
 5820        _: &ConfirmCompletionInsert,
 5821        window: &mut Window,
 5822        cx: &mut Context<Self>,
 5823    ) -> Option<Task<Result<()>>> {
 5824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5825        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5826    }
 5827
 5828    pub fn confirm_completion_replace(
 5829        &mut self,
 5830        _: &ConfirmCompletionReplace,
 5831        window: &mut Window,
 5832        cx: &mut Context<Self>,
 5833    ) -> Option<Task<Result<()>>> {
 5834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5835        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5836    }
 5837
 5838    pub fn compose_completion(
 5839        &mut self,
 5840        action: &ComposeCompletion,
 5841        window: &mut Window,
 5842        cx: &mut Context<Self>,
 5843    ) -> Option<Task<Result<()>>> {
 5844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5845        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5846    }
 5847
 5848    fn do_completion(
 5849        &mut self,
 5850        item_ix: Option<usize>,
 5851        intent: CompletionIntent,
 5852        window: &mut Window,
 5853        cx: &mut Context<Editor>,
 5854    ) -> Option<Task<Result<()>>> {
 5855        use language::ToOffset as _;
 5856
 5857        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5858        else {
 5859            return None;
 5860        };
 5861
 5862        let candidate_id = {
 5863            let entries = completions_menu.entries.borrow();
 5864            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5865            if self.show_edit_predictions_in_menu() {
 5866                self.discard_edit_prediction(true, cx);
 5867            }
 5868            mat.candidate_id
 5869        };
 5870
 5871        let completion = completions_menu
 5872            .completions
 5873            .borrow()
 5874            .get(candidate_id)?
 5875            .clone();
 5876        cx.stop_propagation();
 5877
 5878        let buffer_handle = completions_menu.buffer.clone();
 5879
 5880        let CompletionEdit {
 5881            new_text,
 5882            snippet,
 5883            replace_range,
 5884        } = process_completion_for_edit(
 5885            &completion,
 5886            intent,
 5887            &buffer_handle,
 5888            &completions_menu.initial_position.text_anchor,
 5889            cx,
 5890        );
 5891
 5892        let buffer = buffer_handle.read(cx);
 5893        let snapshot = self.buffer.read(cx).snapshot(cx);
 5894        let newest_anchor = self.selections.newest_anchor();
 5895        let replace_range_multibuffer = {
 5896            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5897            let multibuffer_anchor = snapshot
 5898                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5899                .unwrap()
 5900                ..snapshot
 5901                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5902                    .unwrap();
 5903            multibuffer_anchor.start.to_offset(&snapshot)
 5904                ..multibuffer_anchor.end.to_offset(&snapshot)
 5905        };
 5906        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5907            return None;
 5908        }
 5909
 5910        let old_text = buffer
 5911            .text_for_range(replace_range.clone())
 5912            .collect::<String>();
 5913        let lookbehind = newest_anchor
 5914            .start
 5915            .text_anchor
 5916            .to_offset(buffer)
 5917            .saturating_sub(replace_range.start);
 5918        let lookahead = replace_range
 5919            .end
 5920            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5921        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5922        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5923
 5924        let selections = self.selections.all::<usize>(cx);
 5925        let mut ranges = Vec::new();
 5926        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5927
 5928        for selection in &selections {
 5929            let range = if selection.id == newest_anchor.id {
 5930                replace_range_multibuffer.clone()
 5931            } else {
 5932                let mut range = selection.range();
 5933
 5934                // if prefix is present, don't duplicate it
 5935                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5936                    range.start = range.start.saturating_sub(lookbehind);
 5937
 5938                    // if suffix is also present, mimic the newest cursor and replace it
 5939                    if selection.id != newest_anchor.id
 5940                        && snapshot.contains_str_at(range.end, suffix)
 5941                    {
 5942                        range.end += lookahead;
 5943                    }
 5944                }
 5945                range
 5946            };
 5947
 5948            ranges.push(range.clone());
 5949
 5950            if !self.linked_edit_ranges.is_empty() {
 5951                let start_anchor = snapshot.anchor_before(range.start);
 5952                let end_anchor = snapshot.anchor_after(range.end);
 5953                if let Some(ranges) = self
 5954                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5955                {
 5956                    for (buffer, edits) in ranges {
 5957                        linked_edits
 5958                            .entry(buffer.clone())
 5959                            .or_default()
 5960                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5961                    }
 5962                }
 5963            }
 5964        }
 5965
 5966        let common_prefix_len = old_text
 5967            .chars()
 5968            .zip(new_text.chars())
 5969            .take_while(|(a, b)| a == b)
 5970            .map(|(a, _)| a.len_utf8())
 5971            .sum::<usize>();
 5972
 5973        cx.emit(EditorEvent::InputHandled {
 5974            utf16_range_to_replace: None,
 5975            text: new_text[common_prefix_len..].into(),
 5976        });
 5977
 5978        self.transact(window, cx, |editor, window, cx| {
 5979            if let Some(mut snippet) = snippet {
 5980                snippet.text = new_text.to_string();
 5981                editor
 5982                    .insert_snippet(&ranges, snippet, window, cx)
 5983                    .log_err();
 5984            } else {
 5985                editor.buffer.update(cx, |multi_buffer, cx| {
 5986                    let auto_indent = match completion.insert_text_mode {
 5987                        Some(InsertTextMode::AS_IS) => None,
 5988                        _ => editor.autoindent_mode.clone(),
 5989                    };
 5990                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5991                    multi_buffer.edit(edits, auto_indent, cx);
 5992                });
 5993            }
 5994            for (buffer, edits) in linked_edits {
 5995                buffer.update(cx, |buffer, cx| {
 5996                    let snapshot = buffer.snapshot();
 5997                    let edits = edits
 5998                        .into_iter()
 5999                        .map(|(range, text)| {
 6000                            use text::ToPoint as TP;
 6001                            let end_point = TP::to_point(&range.end, &snapshot);
 6002                            let start_point = TP::to_point(&range.start, &snapshot);
 6003                            (start_point..end_point, text)
 6004                        })
 6005                        .sorted_by_key(|(range, _)| range.start);
 6006                    buffer.edit(edits, None, cx);
 6007                })
 6008            }
 6009
 6010            editor.refresh_edit_prediction(true, false, window, cx);
 6011        });
 6012        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6013
 6014        let show_new_completions_on_confirm = completion
 6015            .confirm
 6016            .as_ref()
 6017            .is_some_and(|confirm| confirm(intent, window, cx));
 6018        if show_new_completions_on_confirm {
 6019            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6020        }
 6021
 6022        let provider = self.completion_provider.as_ref()?;
 6023        drop(completion);
 6024        let apply_edits = provider.apply_additional_edits_for_completion(
 6025            buffer_handle,
 6026            completions_menu.completions.clone(),
 6027            candidate_id,
 6028            true,
 6029            cx,
 6030        );
 6031
 6032        let editor_settings = EditorSettings::get_global(cx);
 6033        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6034            // After the code completion is finished, users often want to know what signatures are needed.
 6035            // so we should automatically call signature_help
 6036            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6037        }
 6038
 6039        Some(cx.foreground_executor().spawn(async move {
 6040            apply_edits.await?;
 6041            Ok(())
 6042        }))
 6043    }
 6044
 6045    pub fn toggle_code_actions(
 6046        &mut self,
 6047        action: &ToggleCodeActions,
 6048        window: &mut Window,
 6049        cx: &mut Context<Self>,
 6050    ) {
 6051        let quick_launch = action.quick_launch;
 6052        let mut context_menu = self.context_menu.borrow_mut();
 6053        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6054            if code_actions.deployed_from == action.deployed_from {
 6055                // Toggle if we're selecting the same one
 6056                *context_menu = None;
 6057                cx.notify();
 6058                return;
 6059            } else {
 6060                // Otherwise, clear it and start a new one
 6061                *context_menu = None;
 6062                cx.notify();
 6063            }
 6064        }
 6065        drop(context_menu);
 6066        let snapshot = self.snapshot(window, cx);
 6067        let deployed_from = action.deployed_from.clone();
 6068        let action = action.clone();
 6069        self.completion_tasks.clear();
 6070        self.discard_edit_prediction(false, cx);
 6071
 6072        let multibuffer_point = match &action.deployed_from {
 6073            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6074                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6075            }
 6076            _ => self.selections.newest::<Point>(cx).head(),
 6077        };
 6078        let Some((buffer, buffer_row)) = snapshot
 6079            .buffer_snapshot
 6080            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6081            .and_then(|(buffer_snapshot, range)| {
 6082                self.buffer()
 6083                    .read(cx)
 6084                    .buffer(buffer_snapshot.remote_id())
 6085                    .map(|buffer| (buffer, range.start.row))
 6086            })
 6087        else {
 6088            return;
 6089        };
 6090        let buffer_id = buffer.read(cx).remote_id();
 6091        let tasks = self
 6092            .tasks
 6093            .get(&(buffer_id, buffer_row))
 6094            .map(|t| Arc::new(t.to_owned()));
 6095
 6096        if !self.focus_handle.is_focused(window) {
 6097            return;
 6098        }
 6099        let project = self.project.clone();
 6100
 6101        let code_actions_task = match deployed_from {
 6102            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6103            _ => self.code_actions(buffer_row, window, cx),
 6104        };
 6105
 6106        let runnable_task = match deployed_from {
 6107            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6108            _ => {
 6109                let mut task_context_task = Task::ready(None);
 6110                if let Some(tasks) = &tasks
 6111                    && let Some(project) = project
 6112                {
 6113                    task_context_task =
 6114                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6115                }
 6116
 6117                cx.spawn_in(window, {
 6118                    let buffer = buffer.clone();
 6119                    async move |editor, cx| {
 6120                        let task_context = task_context_task.await;
 6121
 6122                        let resolved_tasks =
 6123                            tasks
 6124                                .zip(task_context.clone())
 6125                                .map(|(tasks, task_context)| ResolvedTasks {
 6126                                    templates: tasks.resolve(&task_context).collect(),
 6127                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6128                                        multibuffer_point.row,
 6129                                        tasks.column,
 6130                                    )),
 6131                                });
 6132                        let debug_scenarios = editor
 6133                            .update(cx, |editor, cx| {
 6134                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6135                            })?
 6136                            .await;
 6137                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6138                    }
 6139                })
 6140            }
 6141        };
 6142
 6143        cx.spawn_in(window, async move |editor, cx| {
 6144            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6145            let code_actions = code_actions_task.await;
 6146            let spawn_straight_away = quick_launch
 6147                && resolved_tasks
 6148                    .as_ref()
 6149                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6150                && code_actions
 6151                    .as_ref()
 6152                    .is_none_or(|actions| actions.is_empty())
 6153                && debug_scenarios.is_empty();
 6154
 6155            editor.update_in(cx, |editor, window, cx| {
 6156                crate::hover_popover::hide_hover(editor, cx);
 6157                let actions = CodeActionContents::new(
 6158                    resolved_tasks,
 6159                    code_actions,
 6160                    debug_scenarios,
 6161                    task_context.unwrap_or_default(),
 6162                );
 6163
 6164                // Don't show the menu if there are no actions available
 6165                if actions.is_empty() {
 6166                    cx.notify();
 6167                    return Task::ready(Ok(()));
 6168                }
 6169
 6170                *editor.context_menu.borrow_mut() =
 6171                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6172                        buffer,
 6173                        actions,
 6174                        selected_item: Default::default(),
 6175                        scroll_handle: UniformListScrollHandle::default(),
 6176                        deployed_from,
 6177                    }));
 6178                cx.notify();
 6179                if spawn_straight_away
 6180                    && let Some(task) = editor.confirm_code_action(
 6181                        &ConfirmCodeAction { item_ix: Some(0) },
 6182                        window,
 6183                        cx,
 6184                    )
 6185                {
 6186                    return task;
 6187                }
 6188
 6189                Task::ready(Ok(()))
 6190            })
 6191        })
 6192        .detach_and_log_err(cx);
 6193    }
 6194
 6195    fn debug_scenarios(
 6196        &mut self,
 6197        resolved_tasks: &Option<ResolvedTasks>,
 6198        buffer: &Entity<Buffer>,
 6199        cx: &mut App,
 6200    ) -> Task<Vec<task::DebugScenario>> {
 6201        maybe!({
 6202            let project = self.project()?;
 6203            let dap_store = project.read(cx).dap_store();
 6204            let mut scenarios = vec![];
 6205            let resolved_tasks = resolved_tasks.as_ref()?;
 6206            let buffer = buffer.read(cx);
 6207            let language = buffer.language()?;
 6208            let file = buffer.file();
 6209            let debug_adapter = language_settings(language.name().into(), file, cx)
 6210                .debuggers
 6211                .first()
 6212                .map(SharedString::from)
 6213                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6214
 6215            dap_store.update(cx, |dap_store, cx| {
 6216                for (_, task) in &resolved_tasks.templates {
 6217                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6218                        task.original_task().clone(),
 6219                        debug_adapter.clone().into(),
 6220                        task.display_label().to_owned().into(),
 6221                        cx,
 6222                    );
 6223                    scenarios.push(maybe_scenario);
 6224                }
 6225            });
 6226            Some(cx.background_spawn(async move {
 6227                futures::future::join_all(scenarios)
 6228                    .await
 6229                    .into_iter()
 6230                    .flatten()
 6231                    .collect::<Vec<_>>()
 6232            }))
 6233        })
 6234        .unwrap_or_else(|| Task::ready(vec![]))
 6235    }
 6236
 6237    fn code_actions(
 6238        &mut self,
 6239        buffer_row: u32,
 6240        window: &mut Window,
 6241        cx: &mut Context<Self>,
 6242    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6243        let mut task = self.code_actions_task.take();
 6244        cx.spawn_in(window, async move |editor, cx| {
 6245            while let Some(prev_task) = task {
 6246                prev_task.await.log_err();
 6247                task = editor
 6248                    .update(cx, |this, _| this.code_actions_task.take())
 6249                    .ok()?;
 6250            }
 6251
 6252            editor
 6253                .update(cx, |editor, cx| {
 6254                    editor
 6255                        .available_code_actions
 6256                        .clone()
 6257                        .and_then(|(location, code_actions)| {
 6258                            let snapshot = location.buffer.read(cx).snapshot();
 6259                            let point_range = location.range.to_point(&snapshot);
 6260                            let point_range = point_range.start.row..=point_range.end.row;
 6261                            if point_range.contains(&buffer_row) {
 6262                                Some(code_actions)
 6263                            } else {
 6264                                None
 6265                            }
 6266                        })
 6267                })
 6268                .ok()
 6269                .flatten()
 6270        })
 6271    }
 6272
 6273    pub fn confirm_code_action(
 6274        &mut self,
 6275        action: &ConfirmCodeAction,
 6276        window: &mut Window,
 6277        cx: &mut Context<Self>,
 6278    ) -> Option<Task<Result<()>>> {
 6279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6280
 6281        let actions_menu =
 6282            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6283                menu
 6284            } else {
 6285                return None;
 6286            };
 6287
 6288        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6289        let action = actions_menu.actions.get(action_ix)?;
 6290        let title = action.label();
 6291        let buffer = actions_menu.buffer;
 6292        let workspace = self.workspace()?;
 6293
 6294        match action {
 6295            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6296                workspace.update(cx, |workspace, cx| {
 6297                    workspace.schedule_resolved_task(
 6298                        task_source_kind,
 6299                        resolved_task,
 6300                        false,
 6301                        window,
 6302                        cx,
 6303                    );
 6304
 6305                    Some(Task::ready(Ok(())))
 6306                })
 6307            }
 6308            CodeActionsItem::CodeAction {
 6309                excerpt_id,
 6310                action,
 6311                provider,
 6312            } => {
 6313                let apply_code_action =
 6314                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6315                let workspace = workspace.downgrade();
 6316                Some(cx.spawn_in(window, async move |editor, cx| {
 6317                    let project_transaction = apply_code_action.await?;
 6318                    Self::open_project_transaction(
 6319                        &editor,
 6320                        workspace,
 6321                        project_transaction,
 6322                        title,
 6323                        cx,
 6324                    )
 6325                    .await
 6326                }))
 6327            }
 6328            CodeActionsItem::DebugScenario(scenario) => {
 6329                let context = actions_menu.actions.context;
 6330
 6331                workspace.update(cx, |workspace, cx| {
 6332                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6333                    workspace.start_debug_session(
 6334                        scenario,
 6335                        context,
 6336                        Some(buffer),
 6337                        None,
 6338                        window,
 6339                        cx,
 6340                    );
 6341                });
 6342                Some(Task::ready(Ok(())))
 6343            }
 6344        }
 6345    }
 6346
 6347    pub async fn open_project_transaction(
 6348        editor: &WeakEntity<Editor>,
 6349        workspace: WeakEntity<Workspace>,
 6350        transaction: ProjectTransaction,
 6351        title: String,
 6352        cx: &mut AsyncWindowContext,
 6353    ) -> Result<()> {
 6354        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6355        cx.update(|_, cx| {
 6356            entries.sort_unstable_by_key(|(buffer, _)| {
 6357                buffer.read(cx).file().map(|f| f.path().clone())
 6358            });
 6359        })?;
 6360
 6361        // If the project transaction's edits are all contained within this editor, then
 6362        // avoid opening a new editor to display them.
 6363
 6364        if let Some((buffer, transaction)) = entries.first() {
 6365            if entries.len() == 1 {
 6366                let excerpt = editor.update(cx, |editor, cx| {
 6367                    editor
 6368                        .buffer()
 6369                        .read(cx)
 6370                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6371                })?;
 6372                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6373                    && excerpted_buffer == *buffer
 6374                {
 6375                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6376                        let excerpt_range = excerpt_range.to_offset(buffer);
 6377                        buffer
 6378                            .edited_ranges_for_transaction::<usize>(transaction)
 6379                            .all(|range| {
 6380                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6381                            })
 6382                    })?;
 6383
 6384                    if all_edits_within_excerpt {
 6385                        return Ok(());
 6386                    }
 6387                }
 6388            }
 6389        } else {
 6390            return Ok(());
 6391        }
 6392
 6393        let mut ranges_to_highlight = Vec::new();
 6394        let excerpt_buffer = cx.new(|cx| {
 6395            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6396            for (buffer_handle, transaction) in &entries {
 6397                let edited_ranges = buffer_handle
 6398                    .read(cx)
 6399                    .edited_ranges_for_transaction::<Point>(transaction)
 6400                    .collect::<Vec<_>>();
 6401                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6402                    PathKey::for_buffer(buffer_handle, cx),
 6403                    buffer_handle.clone(),
 6404                    edited_ranges,
 6405                    DEFAULT_MULTIBUFFER_CONTEXT,
 6406                    cx,
 6407                );
 6408
 6409                ranges_to_highlight.extend(ranges);
 6410            }
 6411            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6412            multibuffer
 6413        })?;
 6414
 6415        workspace.update_in(cx, |workspace, window, cx| {
 6416            let project = workspace.project().clone();
 6417            let editor =
 6418                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6419            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6420            editor.update(cx, |editor, cx| {
 6421                editor.highlight_background::<Self>(
 6422                    &ranges_to_highlight,
 6423                    |theme| theme.colors().editor_highlighted_line_background,
 6424                    cx,
 6425                );
 6426            });
 6427        })?;
 6428
 6429        Ok(())
 6430    }
 6431
 6432    pub fn clear_code_action_providers(&mut self) {
 6433        self.code_action_providers.clear();
 6434        self.available_code_actions.take();
 6435    }
 6436
 6437    pub fn add_code_action_provider(
 6438        &mut self,
 6439        provider: Rc<dyn CodeActionProvider>,
 6440        window: &mut Window,
 6441        cx: &mut Context<Self>,
 6442    ) {
 6443        if self
 6444            .code_action_providers
 6445            .iter()
 6446            .any(|existing_provider| existing_provider.id() == provider.id())
 6447        {
 6448            return;
 6449        }
 6450
 6451        self.code_action_providers.push(provider);
 6452        self.refresh_code_actions(window, cx);
 6453    }
 6454
 6455    pub fn remove_code_action_provider(
 6456        &mut self,
 6457        id: Arc<str>,
 6458        window: &mut Window,
 6459        cx: &mut Context<Self>,
 6460    ) {
 6461        self.code_action_providers
 6462            .retain(|provider| provider.id() != id);
 6463        self.refresh_code_actions(window, cx);
 6464    }
 6465
 6466    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6467        !self.code_action_providers.is_empty()
 6468            && EditorSettings::get_global(cx).toolbar.code_actions
 6469    }
 6470
 6471    pub fn has_available_code_actions(&self) -> bool {
 6472        self.available_code_actions
 6473            .as_ref()
 6474            .is_some_and(|(_, actions)| !actions.is_empty())
 6475    }
 6476
 6477    fn render_inline_code_actions(
 6478        &self,
 6479        icon_size: ui::IconSize,
 6480        display_row: DisplayRow,
 6481        is_active: bool,
 6482        cx: &mut Context<Self>,
 6483    ) -> AnyElement {
 6484        let show_tooltip = !self.context_menu_visible();
 6485        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6486            .icon_size(icon_size)
 6487            .shape(ui::IconButtonShape::Square)
 6488            .icon_color(ui::Color::Hidden)
 6489            .toggle_state(is_active)
 6490            .when(show_tooltip, |this| {
 6491                this.tooltip({
 6492                    let focus_handle = self.focus_handle.clone();
 6493                    move |window, cx| {
 6494                        Tooltip::for_action_in(
 6495                            "Toggle Code Actions",
 6496                            &ToggleCodeActions {
 6497                                deployed_from: None,
 6498                                quick_launch: false,
 6499                            },
 6500                            &focus_handle,
 6501                            window,
 6502                            cx,
 6503                        )
 6504                    }
 6505                })
 6506            })
 6507            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6508                window.focus(&editor.focus_handle(cx));
 6509                editor.toggle_code_actions(
 6510                    &crate::actions::ToggleCodeActions {
 6511                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6512                            display_row,
 6513                        )),
 6514                        quick_launch: false,
 6515                    },
 6516                    window,
 6517                    cx,
 6518                );
 6519            }))
 6520            .into_any_element()
 6521    }
 6522
 6523    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6524        &self.context_menu
 6525    }
 6526
 6527    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6528        let newest_selection = self.selections.newest_anchor().clone();
 6529        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6530        let buffer = self.buffer.read(cx);
 6531        if newest_selection.head().diff_base_anchor.is_some() {
 6532            return None;
 6533        }
 6534        let (start_buffer, start) =
 6535            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6536        let (end_buffer, end) =
 6537            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6538        if start_buffer != end_buffer {
 6539            return None;
 6540        }
 6541
 6542        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6543            cx.background_executor()
 6544                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6545                .await;
 6546
 6547            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6548                let providers = this.code_action_providers.clone();
 6549                let tasks = this
 6550                    .code_action_providers
 6551                    .iter()
 6552                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6553                    .collect::<Vec<_>>();
 6554                (providers, tasks)
 6555            })?;
 6556
 6557            let mut actions = Vec::new();
 6558            for (provider, provider_actions) in
 6559                providers.into_iter().zip(future::join_all(tasks).await)
 6560            {
 6561                if let Some(provider_actions) = provider_actions.log_err() {
 6562                    actions.extend(provider_actions.into_iter().map(|action| {
 6563                        AvailableCodeAction {
 6564                            excerpt_id: newest_selection.start.excerpt_id,
 6565                            action,
 6566                            provider: provider.clone(),
 6567                        }
 6568                    }));
 6569                }
 6570            }
 6571
 6572            this.update(cx, |this, cx| {
 6573                this.available_code_actions = if actions.is_empty() {
 6574                    None
 6575                } else {
 6576                    Some((
 6577                        Location {
 6578                            buffer: start_buffer,
 6579                            range: start..end,
 6580                        },
 6581                        actions.into(),
 6582                    ))
 6583                };
 6584                cx.notify();
 6585            })
 6586        }));
 6587        None
 6588    }
 6589
 6590    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6591        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6592            self.show_git_blame_inline = false;
 6593
 6594            self.show_git_blame_inline_delay_task =
 6595                Some(cx.spawn_in(window, async move |this, cx| {
 6596                    cx.background_executor().timer(delay).await;
 6597
 6598                    this.update(cx, |this, cx| {
 6599                        this.show_git_blame_inline = true;
 6600                        cx.notify();
 6601                    })
 6602                    .log_err();
 6603                }));
 6604        }
 6605    }
 6606
 6607    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6608        let snapshot = self.snapshot(window, cx);
 6609        let cursor = self.selections.newest::<Point>(cx).head();
 6610        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6611        else {
 6612            return;
 6613        };
 6614
 6615        let Some(blame) = self.blame.as_ref() else {
 6616            return;
 6617        };
 6618
 6619        let row_info = RowInfo {
 6620            buffer_id: Some(buffer.remote_id()),
 6621            buffer_row: Some(point.row),
 6622            ..Default::default()
 6623        };
 6624        let Some(blame_entry) = blame
 6625            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6626            .flatten()
 6627        else {
 6628            return;
 6629        };
 6630
 6631        let anchor = self.selections.newest_anchor().head();
 6632        let position = self.to_pixel_point(anchor, &snapshot, window);
 6633        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6634            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6635        };
 6636    }
 6637
 6638    fn show_blame_popover(
 6639        &mut self,
 6640        blame_entry: &BlameEntry,
 6641        position: gpui::Point<Pixels>,
 6642        ignore_timeout: bool,
 6643        cx: &mut Context<Self>,
 6644    ) {
 6645        if let Some(state) = &mut self.inline_blame_popover {
 6646            state.hide_task.take();
 6647        } else {
 6648            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6649            let blame_entry = blame_entry.clone();
 6650            let show_task = cx.spawn(async move |editor, cx| {
 6651                if !ignore_timeout {
 6652                    cx.background_executor()
 6653                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6654                        .await;
 6655                }
 6656                editor
 6657                    .update(cx, |editor, cx| {
 6658                        editor.inline_blame_popover_show_task.take();
 6659                        let Some(blame) = editor.blame.as_ref() else {
 6660                            return;
 6661                        };
 6662                        let blame = blame.read(cx);
 6663                        let details = blame.details_for_entry(&blame_entry);
 6664                        let markdown = cx.new(|cx| {
 6665                            Markdown::new(
 6666                                details
 6667                                    .as_ref()
 6668                                    .map(|message| message.message.clone())
 6669                                    .unwrap_or_default(),
 6670                                None,
 6671                                None,
 6672                                cx,
 6673                            )
 6674                        });
 6675                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6676                            position,
 6677                            hide_task: None,
 6678                            popover_bounds: None,
 6679                            popover_state: InlineBlamePopoverState {
 6680                                scroll_handle: ScrollHandle::new(),
 6681                                commit_message: details,
 6682                                markdown,
 6683                            },
 6684                            keyboard_grace: ignore_timeout,
 6685                        });
 6686                        cx.notify();
 6687                    })
 6688                    .ok();
 6689            });
 6690            self.inline_blame_popover_show_task = Some(show_task);
 6691        }
 6692    }
 6693
 6694    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6695        self.inline_blame_popover_show_task.take();
 6696        if let Some(state) = &mut self.inline_blame_popover {
 6697            let hide_task = cx.spawn(async move |editor, cx| {
 6698                cx.background_executor()
 6699                    .timer(std::time::Duration::from_millis(100))
 6700                    .await;
 6701                editor
 6702                    .update(cx, |editor, cx| {
 6703                        editor.inline_blame_popover.take();
 6704                        cx.notify();
 6705                    })
 6706                    .ok();
 6707            });
 6708            state.hide_task = Some(hide_task);
 6709        }
 6710    }
 6711
 6712    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6713        if self.pending_rename.is_some() {
 6714            return None;
 6715        }
 6716
 6717        let provider = self.semantics_provider.clone()?;
 6718        let buffer = self.buffer.read(cx);
 6719        let newest_selection = self.selections.newest_anchor().clone();
 6720        let cursor_position = newest_selection.head();
 6721        let (cursor_buffer, cursor_buffer_position) =
 6722            buffer.text_anchor_for_position(cursor_position, cx)?;
 6723        let (tail_buffer, tail_buffer_position) =
 6724            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6725        if cursor_buffer != tail_buffer {
 6726            return None;
 6727        }
 6728
 6729        let snapshot = cursor_buffer.read(cx).snapshot();
 6730        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6731        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6732        if start_word_range != end_word_range {
 6733            self.document_highlights_task.take();
 6734            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6735            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6736            return None;
 6737        }
 6738
 6739        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6740        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6741            cx.background_executor()
 6742                .timer(Duration::from_millis(debounce))
 6743                .await;
 6744
 6745            let highlights = if let Some(highlights) = cx
 6746                .update(|cx| {
 6747                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6748                })
 6749                .ok()
 6750                .flatten()
 6751            {
 6752                highlights.await.log_err()
 6753            } else {
 6754                None
 6755            };
 6756
 6757            if let Some(highlights) = highlights {
 6758                this.update(cx, |this, cx| {
 6759                    if this.pending_rename.is_some() {
 6760                        return;
 6761                    }
 6762
 6763                    let buffer = this.buffer.read(cx);
 6764                    if buffer
 6765                        .text_anchor_for_position(cursor_position, cx)
 6766                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6767                    {
 6768                        return;
 6769                    }
 6770
 6771                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6772                    let mut write_ranges = Vec::new();
 6773                    let mut read_ranges = Vec::new();
 6774                    for highlight in highlights {
 6775                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6776                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6777                        {
 6778                            let start = highlight
 6779                                .range
 6780                                .start
 6781                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6782                            let end = highlight
 6783                                .range
 6784                                .end
 6785                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6786                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6787                                continue;
 6788                            }
 6789
 6790                            let range = Anchor {
 6791                                buffer_id: Some(buffer_id),
 6792                                excerpt_id,
 6793                                text_anchor: start,
 6794                                diff_base_anchor: None,
 6795                            }..Anchor {
 6796                                buffer_id: Some(buffer_id),
 6797                                excerpt_id,
 6798                                text_anchor: end,
 6799                                diff_base_anchor: None,
 6800                            };
 6801                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6802                                write_ranges.push(range);
 6803                            } else {
 6804                                read_ranges.push(range);
 6805                            }
 6806                        }
 6807                    }
 6808
 6809                    this.highlight_background::<DocumentHighlightRead>(
 6810                        &read_ranges,
 6811                        |theme| theme.colors().editor_document_highlight_read_background,
 6812                        cx,
 6813                    );
 6814                    this.highlight_background::<DocumentHighlightWrite>(
 6815                        &write_ranges,
 6816                        |theme| theme.colors().editor_document_highlight_write_background,
 6817                        cx,
 6818                    );
 6819                    cx.notify();
 6820                })
 6821                .log_err();
 6822            }
 6823        }));
 6824        None
 6825    }
 6826
 6827    fn prepare_highlight_query_from_selection(
 6828        &mut self,
 6829        cx: &mut Context<Editor>,
 6830    ) -> Option<(String, Range<Anchor>)> {
 6831        if matches!(self.mode, EditorMode::SingleLine) {
 6832            return None;
 6833        }
 6834        if !EditorSettings::get_global(cx).selection_highlight {
 6835            return None;
 6836        }
 6837        if self.selections.count() != 1 || self.selections.line_mode {
 6838            return None;
 6839        }
 6840        let selection = self.selections.newest::<Point>(cx);
 6841        if selection.is_empty() || selection.start.row != selection.end.row {
 6842            return None;
 6843        }
 6844        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6845        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6846        let query = multi_buffer_snapshot
 6847            .text_for_range(selection_anchor_range.clone())
 6848            .collect::<String>();
 6849        if query.trim().is_empty() {
 6850            return None;
 6851        }
 6852        Some((query, selection_anchor_range))
 6853    }
 6854
 6855    fn update_selection_occurrence_highlights(
 6856        &mut self,
 6857        query_text: String,
 6858        query_range: Range<Anchor>,
 6859        multi_buffer_range_to_query: Range<Point>,
 6860        use_debounce: bool,
 6861        window: &mut Window,
 6862        cx: &mut Context<Editor>,
 6863    ) -> Task<()> {
 6864        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6865        cx.spawn_in(window, async move |editor, cx| {
 6866            if use_debounce {
 6867                cx.background_executor()
 6868                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6869                    .await;
 6870            }
 6871            let match_task = cx.background_spawn(async move {
 6872                let buffer_ranges = multi_buffer_snapshot
 6873                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6874                    .into_iter()
 6875                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6876                let mut match_ranges = Vec::new();
 6877                let Ok(regex) = project::search::SearchQuery::text(
 6878                    query_text.clone(),
 6879                    false,
 6880                    false,
 6881                    false,
 6882                    Default::default(),
 6883                    Default::default(),
 6884                    false,
 6885                    None,
 6886                ) else {
 6887                    return Vec::default();
 6888                };
 6889                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6890                    match_ranges.extend(
 6891                        regex
 6892                            .search(buffer_snapshot, Some(search_range.clone()))
 6893                            .await
 6894                            .into_iter()
 6895                            .filter_map(|match_range| {
 6896                                let match_start = buffer_snapshot
 6897                                    .anchor_after(search_range.start + match_range.start);
 6898                                let match_end = buffer_snapshot
 6899                                    .anchor_before(search_range.start + match_range.end);
 6900                                let match_anchor_range = Anchor::range_in_buffer(
 6901                                    excerpt_id,
 6902                                    buffer_snapshot.remote_id(),
 6903                                    match_start..match_end,
 6904                                );
 6905                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6906                            }),
 6907                    );
 6908                }
 6909                match_ranges
 6910            });
 6911            let match_ranges = match_task.await;
 6912            editor
 6913                .update_in(cx, |editor, _, cx| {
 6914                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6915                    if !match_ranges.is_empty() {
 6916                        editor.highlight_background::<SelectedTextHighlight>(
 6917                            &match_ranges,
 6918                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6919                            cx,
 6920                        )
 6921                    }
 6922                })
 6923                .log_err();
 6924        })
 6925    }
 6926
 6927    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6928        struct NewlineFold;
 6929        let type_id = std::any::TypeId::of::<NewlineFold>();
 6930        if !self.mode.is_single_line() {
 6931            return;
 6932        }
 6933        let snapshot = self.snapshot(window, cx);
 6934        if snapshot.buffer_snapshot.max_point().row == 0 {
 6935            return;
 6936        }
 6937        let task = cx.background_spawn(async move {
 6938            let new_newlines = snapshot
 6939                .buffer_chars_at(0)
 6940                .filter_map(|(c, i)| {
 6941                    if c == '\n' {
 6942                        Some(
 6943                            snapshot.buffer_snapshot.anchor_after(i)
 6944                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6945                        )
 6946                    } else {
 6947                        None
 6948                    }
 6949                })
 6950                .collect::<Vec<_>>();
 6951            let existing_newlines = snapshot
 6952                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6953                .filter_map(|fold| {
 6954                    if fold.placeholder.type_tag == Some(type_id) {
 6955                        Some(fold.range.start..fold.range.end)
 6956                    } else {
 6957                        None
 6958                    }
 6959                })
 6960                .collect::<Vec<_>>();
 6961
 6962            (new_newlines, existing_newlines)
 6963        });
 6964        self.folding_newlines = cx.spawn(async move |this, cx| {
 6965            let (new_newlines, existing_newlines) = task.await;
 6966            if new_newlines == existing_newlines {
 6967                return;
 6968            }
 6969            let placeholder = FoldPlaceholder {
 6970                render: Arc::new(move |_, _, cx| {
 6971                    div()
 6972                        .bg(cx.theme().status().hint_background)
 6973                        .border_b_1()
 6974                        .size_full()
 6975                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6976                        .border_color(cx.theme().status().hint)
 6977                        .child("\\n")
 6978                        .into_any()
 6979                }),
 6980                constrain_width: false,
 6981                merge_adjacent: false,
 6982                type_tag: Some(type_id),
 6983            };
 6984            let creases = new_newlines
 6985                .into_iter()
 6986                .map(|range| Crease::simple(range, placeholder.clone()))
 6987                .collect();
 6988            this.update(cx, |this, cx| {
 6989                this.display_map.update(cx, |display_map, cx| {
 6990                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6991                    display_map.fold(creases, cx);
 6992                });
 6993            })
 6994            .ok();
 6995        });
 6996    }
 6997
 6998    fn refresh_selected_text_highlights(
 6999        &mut self,
 7000        on_buffer_edit: bool,
 7001        window: &mut Window,
 7002        cx: &mut Context<Editor>,
 7003    ) {
 7004        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7005        else {
 7006            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7007            self.quick_selection_highlight_task.take();
 7008            self.debounced_selection_highlight_task.take();
 7009            return;
 7010        };
 7011        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7012        if on_buffer_edit
 7013            || self
 7014                .quick_selection_highlight_task
 7015                .as_ref()
 7016                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7017        {
 7018            let multi_buffer_visible_start = self
 7019                .scroll_manager
 7020                .anchor()
 7021                .anchor
 7022                .to_point(&multi_buffer_snapshot);
 7023            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7024                multi_buffer_visible_start
 7025                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7026                Bias::Left,
 7027            );
 7028            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7029            self.quick_selection_highlight_task = Some((
 7030                query_range.clone(),
 7031                self.update_selection_occurrence_highlights(
 7032                    query_text.clone(),
 7033                    query_range.clone(),
 7034                    multi_buffer_visible_range,
 7035                    false,
 7036                    window,
 7037                    cx,
 7038                ),
 7039            ));
 7040        }
 7041        if on_buffer_edit
 7042            || self
 7043                .debounced_selection_highlight_task
 7044                .as_ref()
 7045                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7046        {
 7047            let multi_buffer_start = multi_buffer_snapshot
 7048                .anchor_before(0)
 7049                .to_point(&multi_buffer_snapshot);
 7050            let multi_buffer_end = multi_buffer_snapshot
 7051                .anchor_after(multi_buffer_snapshot.len())
 7052                .to_point(&multi_buffer_snapshot);
 7053            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7054            self.debounced_selection_highlight_task = Some((
 7055                query_range.clone(),
 7056                self.update_selection_occurrence_highlights(
 7057                    query_text,
 7058                    query_range,
 7059                    multi_buffer_full_range,
 7060                    true,
 7061                    window,
 7062                    cx,
 7063                ),
 7064            ));
 7065        }
 7066    }
 7067
 7068    pub fn refresh_edit_prediction(
 7069        &mut self,
 7070        debounce: bool,
 7071        user_requested: bool,
 7072        window: &mut Window,
 7073        cx: &mut Context<Self>,
 7074    ) -> Option<()> {
 7075        if DisableAiSettings::get_global(cx).disable_ai {
 7076            return None;
 7077        }
 7078
 7079        let provider = self.edit_prediction_provider()?;
 7080        let cursor = self.selections.newest_anchor().head();
 7081        let (buffer, cursor_buffer_position) =
 7082            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7083
 7084        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7085            self.discard_edit_prediction(false, cx);
 7086            return None;
 7087        }
 7088
 7089        if !user_requested
 7090            && (!self.should_show_edit_predictions()
 7091                || !self.is_focused(window)
 7092                || buffer.read(cx).is_empty())
 7093        {
 7094            self.discard_edit_prediction(false, cx);
 7095            return None;
 7096        }
 7097
 7098        self.update_visible_edit_prediction(window, cx);
 7099        provider.refresh(
 7100            self.project.clone(),
 7101            buffer,
 7102            cursor_buffer_position,
 7103            debounce,
 7104            cx,
 7105        );
 7106        Some(())
 7107    }
 7108
 7109    fn show_edit_predictions_in_menu(&self) -> bool {
 7110        match self.edit_prediction_settings {
 7111            EditPredictionSettings::Disabled => false,
 7112            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7113        }
 7114    }
 7115
 7116    pub fn edit_predictions_enabled(&self) -> bool {
 7117        match self.edit_prediction_settings {
 7118            EditPredictionSettings::Disabled => false,
 7119            EditPredictionSettings::Enabled { .. } => true,
 7120        }
 7121    }
 7122
 7123    fn edit_prediction_requires_modifier(&self) -> bool {
 7124        match self.edit_prediction_settings {
 7125            EditPredictionSettings::Disabled => false,
 7126            EditPredictionSettings::Enabled {
 7127                preview_requires_modifier,
 7128                ..
 7129            } => preview_requires_modifier,
 7130        }
 7131    }
 7132
 7133    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7134        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7135            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7136            self.discard_edit_prediction(false, cx);
 7137        } else {
 7138            let selection = self.selections.newest_anchor();
 7139            let cursor = selection.head();
 7140
 7141            if let Some((buffer, cursor_buffer_position)) =
 7142                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7143            {
 7144                self.edit_prediction_settings =
 7145                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7146            }
 7147        }
 7148    }
 7149
 7150    fn edit_prediction_settings_at_position(
 7151        &self,
 7152        buffer: &Entity<Buffer>,
 7153        buffer_position: language::Anchor,
 7154        cx: &App,
 7155    ) -> EditPredictionSettings {
 7156        if !self.mode.is_full()
 7157            || !self.show_edit_predictions_override.unwrap_or(true)
 7158            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7159        {
 7160            return EditPredictionSettings::Disabled;
 7161        }
 7162
 7163        let buffer = buffer.read(cx);
 7164
 7165        let file = buffer.file();
 7166
 7167        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7168            return EditPredictionSettings::Disabled;
 7169        };
 7170
 7171        let by_provider = matches!(
 7172            self.menu_edit_predictions_policy,
 7173            MenuEditPredictionsPolicy::ByProvider
 7174        );
 7175
 7176        let show_in_menu = by_provider
 7177            && self
 7178                .edit_prediction_provider
 7179                .as_ref()
 7180                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7181
 7182        let preview_requires_modifier =
 7183            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7184
 7185        EditPredictionSettings::Enabled {
 7186            show_in_menu,
 7187            preview_requires_modifier,
 7188        }
 7189    }
 7190
 7191    fn should_show_edit_predictions(&self) -> bool {
 7192        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7193    }
 7194
 7195    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7196        matches!(
 7197            self.edit_prediction_preview,
 7198            EditPredictionPreview::Active { .. }
 7199        )
 7200    }
 7201
 7202    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7203        let cursor = self.selections.newest_anchor().head();
 7204        if let Some((buffer, cursor_position)) =
 7205            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7206        {
 7207            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7208        } else {
 7209            false
 7210        }
 7211    }
 7212
 7213    pub fn supports_minimap(&self, cx: &App) -> bool {
 7214        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7215    }
 7216
 7217    fn edit_predictions_enabled_in_buffer(
 7218        &self,
 7219        buffer: &Entity<Buffer>,
 7220        buffer_position: language::Anchor,
 7221        cx: &App,
 7222    ) -> bool {
 7223        maybe!({
 7224            if self.read_only(cx) {
 7225                return Some(false);
 7226            }
 7227            let provider = self.edit_prediction_provider()?;
 7228            if !provider.is_enabled(buffer, buffer_position, cx) {
 7229                return Some(false);
 7230            }
 7231            let buffer = buffer.read(cx);
 7232            let Some(file) = buffer.file() else {
 7233                return Some(true);
 7234            };
 7235            let settings = all_language_settings(Some(file), cx);
 7236            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7237        })
 7238        .unwrap_or(false)
 7239    }
 7240
 7241    fn cycle_edit_prediction(
 7242        &mut self,
 7243        direction: Direction,
 7244        window: &mut Window,
 7245        cx: &mut Context<Self>,
 7246    ) -> Option<()> {
 7247        let provider = self.edit_prediction_provider()?;
 7248        let cursor = self.selections.newest_anchor().head();
 7249        let (buffer, cursor_buffer_position) =
 7250            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7251        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7252            return None;
 7253        }
 7254
 7255        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7256        self.update_visible_edit_prediction(window, cx);
 7257
 7258        Some(())
 7259    }
 7260
 7261    pub fn show_edit_prediction(
 7262        &mut self,
 7263        _: &ShowEditPrediction,
 7264        window: &mut Window,
 7265        cx: &mut Context<Self>,
 7266    ) {
 7267        if !self.has_active_edit_prediction() {
 7268            self.refresh_edit_prediction(false, true, window, cx);
 7269            return;
 7270        }
 7271
 7272        self.update_visible_edit_prediction(window, cx);
 7273    }
 7274
 7275    pub fn display_cursor_names(
 7276        &mut self,
 7277        _: &DisplayCursorNames,
 7278        window: &mut Window,
 7279        cx: &mut Context<Self>,
 7280    ) {
 7281        self.show_cursor_names(window, cx);
 7282    }
 7283
 7284    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7285        self.show_cursor_names = true;
 7286        cx.notify();
 7287        cx.spawn_in(window, async move |this, cx| {
 7288            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7289            this.update(cx, |this, cx| {
 7290                this.show_cursor_names = false;
 7291                cx.notify()
 7292            })
 7293            .ok()
 7294        })
 7295        .detach();
 7296    }
 7297
 7298    pub fn next_edit_prediction(
 7299        &mut self,
 7300        _: &NextEditPrediction,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        if self.has_active_edit_prediction() {
 7305            self.cycle_edit_prediction(Direction::Next, window, cx);
 7306        } else {
 7307            let is_copilot_disabled = self
 7308                .refresh_edit_prediction(false, true, window, cx)
 7309                .is_none();
 7310            if is_copilot_disabled {
 7311                cx.propagate();
 7312            }
 7313        }
 7314    }
 7315
 7316    pub fn previous_edit_prediction(
 7317        &mut self,
 7318        _: &PreviousEditPrediction,
 7319        window: &mut Window,
 7320        cx: &mut Context<Self>,
 7321    ) {
 7322        if self.has_active_edit_prediction() {
 7323            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7324        } else {
 7325            let is_copilot_disabled = self
 7326                .refresh_edit_prediction(false, true, window, cx)
 7327                .is_none();
 7328            if is_copilot_disabled {
 7329                cx.propagate();
 7330            }
 7331        }
 7332    }
 7333
 7334    pub fn accept_edit_prediction(
 7335        &mut self,
 7336        _: &AcceptEditPrediction,
 7337        window: &mut Window,
 7338        cx: &mut Context<Self>,
 7339    ) {
 7340        if self.show_edit_predictions_in_menu() {
 7341            self.hide_context_menu(window, cx);
 7342        }
 7343
 7344        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7345            return;
 7346        };
 7347
 7348        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7349
 7350        match &active_edit_prediction.completion {
 7351            EditPrediction::Move { target, .. } => {
 7352                let target = *target;
 7353
 7354                if let Some(position_map) = &self.last_position_map {
 7355                    if position_map
 7356                        .visible_row_range
 7357                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7358                        || !self.edit_prediction_requires_modifier()
 7359                    {
 7360                        self.unfold_ranges(&[target..target], true, false, cx);
 7361                        // Note that this is also done in vim's handler of the Tab action.
 7362                        self.change_selections(
 7363                            SelectionEffects::scroll(Autoscroll::newest()),
 7364                            window,
 7365                            cx,
 7366                            |selections| {
 7367                                selections.select_anchor_ranges([target..target]);
 7368                            },
 7369                        );
 7370                        self.clear_row_highlights::<EditPredictionPreview>();
 7371
 7372                        self.edit_prediction_preview
 7373                            .set_previous_scroll_position(None);
 7374                    } else {
 7375                        self.edit_prediction_preview
 7376                            .set_previous_scroll_position(Some(
 7377                                position_map.snapshot.scroll_anchor,
 7378                            ));
 7379
 7380                        self.highlight_rows::<EditPredictionPreview>(
 7381                            target..target,
 7382                            cx.theme().colors().editor_highlighted_line_background,
 7383                            RowHighlightOptions {
 7384                                autoscroll: true,
 7385                                ..Default::default()
 7386                            },
 7387                            cx,
 7388                        );
 7389                        self.request_autoscroll(Autoscroll::fit(), cx);
 7390                    }
 7391                }
 7392            }
 7393            EditPrediction::Edit { edits, .. } => {
 7394                if let Some(provider) = self.edit_prediction_provider() {
 7395                    provider.accept(cx);
 7396                }
 7397
 7398                // Store the transaction ID and selections before applying the edit
 7399                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7400
 7401                let snapshot = self.buffer.read(cx).snapshot(cx);
 7402                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7403
 7404                self.buffer.update(cx, |buffer, cx| {
 7405                    buffer.edit(edits.iter().cloned(), None, cx)
 7406                });
 7407
 7408                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7409                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7410                });
 7411
 7412                let selections = self.selections.disjoint_anchors();
 7413                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7414                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7415                    if has_new_transaction {
 7416                        self.selection_history
 7417                            .insert_transaction(transaction_id_now, selections);
 7418                    }
 7419                }
 7420
 7421                self.update_visible_edit_prediction(window, cx);
 7422                if self.active_edit_prediction.is_none() {
 7423                    self.refresh_edit_prediction(true, true, window, cx);
 7424                }
 7425
 7426                cx.notify();
 7427            }
 7428        }
 7429
 7430        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7431    }
 7432
 7433    pub fn accept_partial_edit_prediction(
 7434        &mut self,
 7435        _: &AcceptPartialEditPrediction,
 7436        window: &mut Window,
 7437        cx: &mut Context<Self>,
 7438    ) {
 7439        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7440            return;
 7441        };
 7442        if self.selections.count() != 1 {
 7443            return;
 7444        }
 7445
 7446        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7447
 7448        match &active_edit_prediction.completion {
 7449            EditPrediction::Move { target, .. } => {
 7450                let target = *target;
 7451                self.change_selections(
 7452                    SelectionEffects::scroll(Autoscroll::newest()),
 7453                    window,
 7454                    cx,
 7455                    |selections| {
 7456                        selections.select_anchor_ranges([target..target]);
 7457                    },
 7458                );
 7459            }
 7460            EditPrediction::Edit { edits, .. } => {
 7461                // Find an insertion that starts at the cursor position.
 7462                let snapshot = self.buffer.read(cx).snapshot(cx);
 7463                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7464                let insertion = edits.iter().find_map(|(range, text)| {
 7465                    let range = range.to_offset(&snapshot);
 7466                    if range.is_empty() && range.start == cursor_offset {
 7467                        Some(text)
 7468                    } else {
 7469                        None
 7470                    }
 7471                });
 7472
 7473                if let Some(text) = insertion {
 7474                    let mut partial_completion = text
 7475                        .chars()
 7476                        .by_ref()
 7477                        .take_while(|c| c.is_alphabetic())
 7478                        .collect::<String>();
 7479                    if partial_completion.is_empty() {
 7480                        partial_completion = text
 7481                            .chars()
 7482                            .by_ref()
 7483                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7484                            .collect::<String>();
 7485                    }
 7486
 7487                    cx.emit(EditorEvent::InputHandled {
 7488                        utf16_range_to_replace: None,
 7489                        text: partial_completion.clone().into(),
 7490                    });
 7491
 7492                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7493
 7494                    self.refresh_edit_prediction(true, true, window, cx);
 7495                    cx.notify();
 7496                } else {
 7497                    self.accept_edit_prediction(&Default::default(), window, cx);
 7498                }
 7499            }
 7500        }
 7501    }
 7502
 7503    fn discard_edit_prediction(
 7504        &mut self,
 7505        should_report_edit_prediction_event: bool,
 7506        cx: &mut Context<Self>,
 7507    ) -> bool {
 7508        if should_report_edit_prediction_event {
 7509            let completion_id = self
 7510                .active_edit_prediction
 7511                .as_ref()
 7512                .and_then(|active_completion| active_completion.completion_id.clone());
 7513
 7514            self.report_edit_prediction_event(completion_id, false, cx);
 7515        }
 7516
 7517        if let Some(provider) = self.edit_prediction_provider() {
 7518            provider.discard(cx);
 7519        }
 7520
 7521        self.take_active_edit_prediction(cx)
 7522    }
 7523
 7524    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7525        let Some(provider) = self.edit_prediction_provider() else {
 7526            return;
 7527        };
 7528
 7529        let Some((_, buffer, _)) = self
 7530            .buffer
 7531            .read(cx)
 7532            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7533        else {
 7534            return;
 7535        };
 7536
 7537        let extension = buffer
 7538            .read(cx)
 7539            .file()
 7540            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7541
 7542        let event_type = match accepted {
 7543            true => "Edit Prediction Accepted",
 7544            false => "Edit Prediction Discarded",
 7545        };
 7546        telemetry::event!(
 7547            event_type,
 7548            provider = provider.name(),
 7549            prediction_id = id,
 7550            suggestion_accepted = accepted,
 7551            file_extension = extension,
 7552        );
 7553    }
 7554
 7555    pub fn has_active_edit_prediction(&self) -> bool {
 7556        self.active_edit_prediction.is_some()
 7557    }
 7558
 7559    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7560        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7561            return false;
 7562        };
 7563
 7564        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7565        self.clear_highlights::<EditPredictionHighlight>(cx);
 7566        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7567        true
 7568    }
 7569
 7570    /// Returns true when we're displaying the edit prediction popover below the cursor
 7571    /// like we are not previewing and the LSP autocomplete menu is visible
 7572    /// or we are in `when_holding_modifier` mode.
 7573    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7574        if self.edit_prediction_preview_is_active()
 7575            || !self.show_edit_predictions_in_menu()
 7576            || !self.edit_predictions_enabled()
 7577        {
 7578            return false;
 7579        }
 7580
 7581        if self.has_visible_completions_menu() {
 7582            return true;
 7583        }
 7584
 7585        has_completion && self.edit_prediction_requires_modifier()
 7586    }
 7587
 7588    fn handle_modifiers_changed(
 7589        &mut self,
 7590        modifiers: Modifiers,
 7591        position_map: &PositionMap,
 7592        window: &mut Window,
 7593        cx: &mut Context<Self>,
 7594    ) {
 7595        if self.show_edit_predictions_in_menu() {
 7596            self.update_edit_prediction_preview(&modifiers, window, cx);
 7597        }
 7598
 7599        self.update_selection_mode(&modifiers, position_map, window, cx);
 7600
 7601        let mouse_position = window.mouse_position();
 7602        if !position_map.text_hitbox.is_hovered(window) {
 7603            return;
 7604        }
 7605
 7606        self.update_hovered_link(
 7607            position_map.point_for_position(mouse_position),
 7608            &position_map.snapshot,
 7609            modifiers,
 7610            window,
 7611            cx,
 7612        )
 7613    }
 7614
 7615    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7616        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7617        if invert {
 7618            match multi_cursor_setting {
 7619                MultiCursorModifier::Alt => modifiers.alt,
 7620                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7621            }
 7622        } else {
 7623            match multi_cursor_setting {
 7624                MultiCursorModifier::Alt => modifiers.secondary(),
 7625                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7626            }
 7627        }
 7628    }
 7629
 7630    fn columnar_selection_mode(
 7631        modifiers: &Modifiers,
 7632        cx: &mut Context<Self>,
 7633    ) -> Option<ColumnarMode> {
 7634        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7635            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7636                Some(ColumnarMode::FromMouse)
 7637            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7638                Some(ColumnarMode::FromSelection)
 7639            } else {
 7640                None
 7641            }
 7642        } else {
 7643            None
 7644        }
 7645    }
 7646
 7647    fn update_selection_mode(
 7648        &mut self,
 7649        modifiers: &Modifiers,
 7650        position_map: &PositionMap,
 7651        window: &mut Window,
 7652        cx: &mut Context<Self>,
 7653    ) {
 7654        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7655            return;
 7656        };
 7657        if self.selections.pending.is_none() {
 7658            return;
 7659        }
 7660
 7661        let mouse_position = window.mouse_position();
 7662        let point_for_position = position_map.point_for_position(mouse_position);
 7663        let position = point_for_position.previous_valid;
 7664
 7665        self.select(
 7666            SelectPhase::BeginColumnar {
 7667                position,
 7668                reset: false,
 7669                mode,
 7670                goal_column: point_for_position.exact_unclipped.column(),
 7671            },
 7672            window,
 7673            cx,
 7674        );
 7675    }
 7676
 7677    fn update_edit_prediction_preview(
 7678        &mut self,
 7679        modifiers: &Modifiers,
 7680        window: &mut Window,
 7681        cx: &mut Context<Self>,
 7682    ) {
 7683        let mut modifiers_held = false;
 7684        if let Some(accept_keystroke) = self
 7685            .accept_edit_prediction_keybind(false, window, cx)
 7686            .keystroke()
 7687        {
 7688            modifiers_held = modifiers_held
 7689                || (accept_keystroke.modifiers() == modifiers
 7690                    && accept_keystroke.modifiers().modified());
 7691        };
 7692        if let Some(accept_partial_keystroke) = self
 7693            .accept_edit_prediction_keybind(true, window, cx)
 7694            .keystroke()
 7695        {
 7696            modifiers_held = modifiers_held
 7697                || (accept_partial_keystroke.modifiers() == modifiers
 7698                    && accept_partial_keystroke.modifiers().modified());
 7699        }
 7700
 7701        if modifiers_held {
 7702            if matches!(
 7703                self.edit_prediction_preview,
 7704                EditPredictionPreview::Inactive { .. }
 7705            ) {
 7706                self.edit_prediction_preview = EditPredictionPreview::Active {
 7707                    previous_scroll_position: None,
 7708                    since: Instant::now(),
 7709                };
 7710
 7711                self.update_visible_edit_prediction(window, cx);
 7712                cx.notify();
 7713            }
 7714        } else if let EditPredictionPreview::Active {
 7715            previous_scroll_position,
 7716            since,
 7717        } = self.edit_prediction_preview
 7718        {
 7719            if let (Some(previous_scroll_position), Some(position_map)) =
 7720                (previous_scroll_position, self.last_position_map.as_ref())
 7721            {
 7722                self.set_scroll_position(
 7723                    previous_scroll_position
 7724                        .scroll_position(&position_map.snapshot.display_snapshot),
 7725                    window,
 7726                    cx,
 7727                );
 7728            }
 7729
 7730            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7731                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7732            };
 7733            self.clear_row_highlights::<EditPredictionPreview>();
 7734            self.update_visible_edit_prediction(window, cx);
 7735            cx.notify();
 7736        }
 7737    }
 7738
 7739    fn update_visible_edit_prediction(
 7740        &mut self,
 7741        _window: &mut Window,
 7742        cx: &mut Context<Self>,
 7743    ) -> Option<()> {
 7744        if DisableAiSettings::get_global(cx).disable_ai {
 7745            return None;
 7746        }
 7747
 7748        let selection = self.selections.newest_anchor();
 7749        let cursor = selection.head();
 7750        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7751        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7752        let excerpt_id = cursor.excerpt_id;
 7753
 7754        let show_in_menu = self.show_edit_predictions_in_menu();
 7755        let completions_menu_has_precedence = !show_in_menu
 7756            && (self.context_menu.borrow().is_some()
 7757                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7758
 7759        if completions_menu_has_precedence
 7760            || !offset_selection.is_empty()
 7761            || self
 7762                .active_edit_prediction
 7763                .as_ref()
 7764                .is_some_and(|completion| {
 7765                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7766                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7767                    !invalidation_range.contains(&offset_selection.head())
 7768                })
 7769        {
 7770            self.discard_edit_prediction(false, cx);
 7771            return None;
 7772        }
 7773
 7774        self.take_active_edit_prediction(cx);
 7775        let Some(provider) = self.edit_prediction_provider() else {
 7776            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7777            return None;
 7778        };
 7779
 7780        let (buffer, cursor_buffer_position) =
 7781            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7782
 7783        self.edit_prediction_settings =
 7784            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7785
 7786        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7787            self.discard_edit_prediction(false, cx);
 7788            return None;
 7789        };
 7790
 7791        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7792
 7793        if self.edit_prediction_indent_conflict {
 7794            let cursor_point = cursor.to_point(&multibuffer);
 7795
 7796            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7797
 7798            if let Some((_, indent)) = indents.iter().next()
 7799                && indent.len == cursor_point.column
 7800            {
 7801                self.edit_prediction_indent_conflict = false;
 7802            }
 7803        }
 7804
 7805        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7806        let edits = edit_prediction
 7807            .edits
 7808            .into_iter()
 7809            .flat_map(|(range, new_text)| {
 7810                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7811                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7812                Some((start..end, new_text))
 7813            })
 7814            .collect::<Vec<_>>();
 7815        if edits.is_empty() {
 7816            return None;
 7817        }
 7818
 7819        let first_edit_start = edits.first().unwrap().0.start;
 7820        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7821        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7822
 7823        let last_edit_end = edits.last().unwrap().0.end;
 7824        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7825        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7826
 7827        let cursor_row = cursor.to_point(&multibuffer).row;
 7828
 7829        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7830
 7831        let mut inlay_ids = Vec::new();
 7832        let invalidation_row_range;
 7833        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7834            Some(cursor_row..edit_end_row)
 7835        } else if cursor_row > edit_end_row {
 7836            Some(edit_start_row..cursor_row)
 7837        } else {
 7838            None
 7839        };
 7840        let supports_jump = self
 7841            .edit_prediction_provider
 7842            .as_ref()
 7843            .map(|provider| provider.provider.supports_jump_to_edit())
 7844            .unwrap_or(true);
 7845
 7846        let is_move = supports_jump
 7847            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7848        let completion = if is_move {
 7849            invalidation_row_range =
 7850                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7851            let target = first_edit_start;
 7852            EditPrediction::Move { target, snapshot }
 7853        } else {
 7854            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7855                && !self.edit_predictions_hidden_for_vim_mode;
 7856
 7857            if show_completions_in_buffer {
 7858                if edits
 7859                    .iter()
 7860                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7861                {
 7862                    let mut inlays = Vec::new();
 7863                    for (range, new_text) in &edits {
 7864                        let inlay = Inlay::edit_prediction(
 7865                            post_inc(&mut self.next_inlay_id),
 7866                            range.start,
 7867                            new_text.as_str(),
 7868                        );
 7869                        inlay_ids.push(inlay.id);
 7870                        inlays.push(inlay);
 7871                    }
 7872
 7873                    self.splice_inlays(&[], inlays, cx);
 7874                } else {
 7875                    let background_color = cx.theme().status().deleted_background;
 7876                    self.highlight_text::<EditPredictionHighlight>(
 7877                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7878                        HighlightStyle {
 7879                            background_color: Some(background_color),
 7880                            ..Default::default()
 7881                        },
 7882                        cx,
 7883                    );
 7884                }
 7885            }
 7886
 7887            invalidation_row_range = edit_start_row..edit_end_row;
 7888
 7889            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7890                if provider.show_tab_accept_marker() {
 7891                    EditDisplayMode::TabAccept
 7892                } else {
 7893                    EditDisplayMode::Inline
 7894                }
 7895            } else {
 7896                EditDisplayMode::DiffPopover
 7897            };
 7898
 7899            EditPrediction::Edit {
 7900                edits,
 7901                edit_preview: edit_prediction.edit_preview,
 7902                display_mode,
 7903                snapshot,
 7904            }
 7905        };
 7906
 7907        let invalidation_range = multibuffer
 7908            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7909            ..multibuffer.anchor_after(Point::new(
 7910                invalidation_row_range.end,
 7911                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7912            ));
 7913
 7914        self.stale_edit_prediction_in_menu = None;
 7915        self.active_edit_prediction = Some(EditPredictionState {
 7916            inlay_ids,
 7917            completion,
 7918            completion_id: edit_prediction.id,
 7919            invalidation_range,
 7920        });
 7921
 7922        cx.notify();
 7923
 7924        Some(())
 7925    }
 7926
 7927    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7928        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7929    }
 7930
 7931    fn clear_tasks(&mut self) {
 7932        self.tasks.clear()
 7933    }
 7934
 7935    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7936        if self.tasks.insert(key, value).is_some() {
 7937            // This case should hopefully be rare, but just in case...
 7938            log::error!(
 7939                "multiple different run targets found on a single line, only the last target will be rendered"
 7940            )
 7941        }
 7942    }
 7943
 7944    /// Get all display points of breakpoints that will be rendered within editor
 7945    ///
 7946    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7947    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7948    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7949    fn active_breakpoints(
 7950        &self,
 7951        range: Range<DisplayRow>,
 7952        window: &mut Window,
 7953        cx: &mut Context<Self>,
 7954    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7955        let mut breakpoint_display_points = HashMap::default();
 7956
 7957        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7958            return breakpoint_display_points;
 7959        };
 7960
 7961        let snapshot = self.snapshot(window, cx);
 7962
 7963        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7964        let Some(project) = self.project() else {
 7965            return breakpoint_display_points;
 7966        };
 7967
 7968        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7969            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7970
 7971        for (buffer_snapshot, range, excerpt_id) in
 7972            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7973        {
 7974            let Some(buffer) = project
 7975                .read(cx)
 7976                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7977            else {
 7978                continue;
 7979            };
 7980            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7981                &buffer,
 7982                Some(
 7983                    buffer_snapshot.anchor_before(range.start)
 7984                        ..buffer_snapshot.anchor_after(range.end),
 7985                ),
 7986                buffer_snapshot,
 7987                cx,
 7988            );
 7989            for (breakpoint, state) in breakpoints {
 7990                let multi_buffer_anchor =
 7991                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7992                let position = multi_buffer_anchor
 7993                    .to_point(multi_buffer_snapshot)
 7994                    .to_display_point(&snapshot);
 7995
 7996                breakpoint_display_points.insert(
 7997                    position.row(),
 7998                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7999                );
 8000            }
 8001        }
 8002
 8003        breakpoint_display_points
 8004    }
 8005
 8006    fn breakpoint_context_menu(
 8007        &self,
 8008        anchor: Anchor,
 8009        window: &mut Window,
 8010        cx: &mut Context<Self>,
 8011    ) -> Entity<ui::ContextMenu> {
 8012        let weak_editor = cx.weak_entity();
 8013        let focus_handle = self.focus_handle(cx);
 8014
 8015        let row = self
 8016            .buffer
 8017            .read(cx)
 8018            .snapshot(cx)
 8019            .summary_for_anchor::<Point>(&anchor)
 8020            .row;
 8021
 8022        let breakpoint = self
 8023            .breakpoint_at_row(row, window, cx)
 8024            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8025
 8026        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8027            "Edit Log Breakpoint"
 8028        } else {
 8029            "Set Log Breakpoint"
 8030        };
 8031
 8032        let condition_breakpoint_msg = if breakpoint
 8033            .as_ref()
 8034            .is_some_and(|bp| bp.1.condition.is_some())
 8035        {
 8036            "Edit Condition Breakpoint"
 8037        } else {
 8038            "Set Condition Breakpoint"
 8039        };
 8040
 8041        let hit_condition_breakpoint_msg = if breakpoint
 8042            .as_ref()
 8043            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8044        {
 8045            "Edit Hit Condition Breakpoint"
 8046        } else {
 8047            "Set Hit Condition Breakpoint"
 8048        };
 8049
 8050        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8051            "Unset Breakpoint"
 8052        } else {
 8053            "Set Breakpoint"
 8054        };
 8055
 8056        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8057
 8058        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8059            BreakpointState::Enabled => Some("Disable"),
 8060            BreakpointState::Disabled => Some("Enable"),
 8061        });
 8062
 8063        let (anchor, breakpoint) =
 8064            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8065
 8066        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8067            menu.on_blur_subscription(Subscription::new(|| {}))
 8068                .context(focus_handle)
 8069                .when(run_to_cursor, |this| {
 8070                    let weak_editor = weak_editor.clone();
 8071                    this.entry("Run to cursor", None, move |window, cx| {
 8072                        weak_editor
 8073                            .update(cx, |editor, cx| {
 8074                                editor.change_selections(
 8075                                    SelectionEffects::no_scroll(),
 8076                                    window,
 8077                                    cx,
 8078                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8079                                );
 8080                            })
 8081                            .ok();
 8082
 8083                        window.dispatch_action(Box::new(RunToCursor), cx);
 8084                    })
 8085                    .separator()
 8086                })
 8087                .when_some(toggle_state_msg, |this, msg| {
 8088                    this.entry(msg, None, {
 8089                        let weak_editor = weak_editor.clone();
 8090                        let breakpoint = breakpoint.clone();
 8091                        move |_window, cx| {
 8092                            weak_editor
 8093                                .update(cx, |this, cx| {
 8094                                    this.edit_breakpoint_at_anchor(
 8095                                        anchor,
 8096                                        breakpoint.as_ref().clone(),
 8097                                        BreakpointEditAction::InvertState,
 8098                                        cx,
 8099                                    );
 8100                                })
 8101                                .log_err();
 8102                        }
 8103                    })
 8104                })
 8105                .entry(set_breakpoint_msg, None, {
 8106                    let weak_editor = weak_editor.clone();
 8107                    let breakpoint = breakpoint.clone();
 8108                    move |_window, cx| {
 8109                        weak_editor
 8110                            .update(cx, |this, cx| {
 8111                                this.edit_breakpoint_at_anchor(
 8112                                    anchor,
 8113                                    breakpoint.as_ref().clone(),
 8114                                    BreakpointEditAction::Toggle,
 8115                                    cx,
 8116                                );
 8117                            })
 8118                            .log_err();
 8119                    }
 8120                })
 8121                .entry(log_breakpoint_msg, None, {
 8122                    let breakpoint = breakpoint.clone();
 8123                    let weak_editor = weak_editor.clone();
 8124                    move |window, cx| {
 8125                        weak_editor
 8126                            .update(cx, |this, cx| {
 8127                                this.add_edit_breakpoint_block(
 8128                                    anchor,
 8129                                    breakpoint.as_ref(),
 8130                                    BreakpointPromptEditAction::Log,
 8131                                    window,
 8132                                    cx,
 8133                                );
 8134                            })
 8135                            .log_err();
 8136                    }
 8137                })
 8138                .entry(condition_breakpoint_msg, None, {
 8139                    let breakpoint = breakpoint.clone();
 8140                    let weak_editor = weak_editor.clone();
 8141                    move |window, cx| {
 8142                        weak_editor
 8143                            .update(cx, |this, cx| {
 8144                                this.add_edit_breakpoint_block(
 8145                                    anchor,
 8146                                    breakpoint.as_ref(),
 8147                                    BreakpointPromptEditAction::Condition,
 8148                                    window,
 8149                                    cx,
 8150                                );
 8151                            })
 8152                            .log_err();
 8153                    }
 8154                })
 8155                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8156                    weak_editor
 8157                        .update(cx, |this, cx| {
 8158                            this.add_edit_breakpoint_block(
 8159                                anchor,
 8160                                breakpoint.as_ref(),
 8161                                BreakpointPromptEditAction::HitCondition,
 8162                                window,
 8163                                cx,
 8164                            );
 8165                        })
 8166                        .log_err();
 8167                })
 8168        })
 8169    }
 8170
 8171    fn render_breakpoint(
 8172        &self,
 8173        position: Anchor,
 8174        row: DisplayRow,
 8175        breakpoint: &Breakpoint,
 8176        state: Option<BreakpointSessionState>,
 8177        cx: &mut Context<Self>,
 8178    ) -> IconButton {
 8179        let is_rejected = state.is_some_and(|s| !s.verified);
 8180        // Is it a breakpoint that shows up when hovering over gutter?
 8181        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8182            (false, false),
 8183            |PhantomBreakpointIndicator {
 8184                 is_active,
 8185                 display_row,
 8186                 collides_with_existing_breakpoint,
 8187             }| {
 8188                (
 8189                    is_active && display_row == row,
 8190                    collides_with_existing_breakpoint,
 8191                )
 8192            },
 8193        );
 8194
 8195        let (color, icon) = {
 8196            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8197                (false, false) => ui::IconName::DebugBreakpoint,
 8198                (true, false) => ui::IconName::DebugLogBreakpoint,
 8199                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8200                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8201            };
 8202
 8203            let color = if is_phantom {
 8204                Color::Hint
 8205            } else if is_rejected {
 8206                Color::Disabled
 8207            } else {
 8208                Color::Debugger
 8209            };
 8210
 8211            (color, icon)
 8212        };
 8213
 8214        let breakpoint = Arc::from(breakpoint.clone());
 8215
 8216        let alt_as_text = gpui::Keystroke {
 8217            modifiers: Modifiers::secondary_key(),
 8218            ..Default::default()
 8219        };
 8220        let primary_action_text = if breakpoint.is_disabled() {
 8221            "Enable breakpoint"
 8222        } else if is_phantom && !collides_with_existing {
 8223            "Set breakpoint"
 8224        } else {
 8225            "Unset breakpoint"
 8226        };
 8227        let focus_handle = self.focus_handle.clone();
 8228
 8229        let meta = if is_rejected {
 8230            SharedString::from("No executable code is associated with this line.")
 8231        } else if collides_with_existing && !breakpoint.is_disabled() {
 8232            SharedString::from(format!(
 8233                "{alt_as_text}-click to disable,\nright-click for more options."
 8234            ))
 8235        } else {
 8236            SharedString::from("Right-click for more options.")
 8237        };
 8238        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8239            .icon_size(IconSize::XSmall)
 8240            .size(ui::ButtonSize::None)
 8241            .when(is_rejected, |this| {
 8242                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8243            })
 8244            .icon_color(color)
 8245            .style(ButtonStyle::Transparent)
 8246            .on_click(cx.listener({
 8247                move |editor, event: &ClickEvent, window, cx| {
 8248                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8249                        BreakpointEditAction::InvertState
 8250                    } else {
 8251                        BreakpointEditAction::Toggle
 8252                    };
 8253
 8254                    window.focus(&editor.focus_handle(cx));
 8255                    editor.edit_breakpoint_at_anchor(
 8256                        position,
 8257                        breakpoint.as_ref().clone(),
 8258                        edit_action,
 8259                        cx,
 8260                    );
 8261                }
 8262            }))
 8263            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8264                editor.set_breakpoint_context_menu(
 8265                    row,
 8266                    Some(position),
 8267                    event.position(),
 8268                    window,
 8269                    cx,
 8270                );
 8271            }))
 8272            .tooltip(move |window, cx| {
 8273                Tooltip::with_meta_in(
 8274                    primary_action_text,
 8275                    Some(&ToggleBreakpoint),
 8276                    meta.clone(),
 8277                    &focus_handle,
 8278                    window,
 8279                    cx,
 8280                )
 8281            })
 8282    }
 8283
 8284    fn build_tasks_context(
 8285        project: &Entity<Project>,
 8286        buffer: &Entity<Buffer>,
 8287        buffer_row: u32,
 8288        tasks: &Arc<RunnableTasks>,
 8289        cx: &mut Context<Self>,
 8290    ) -> Task<Option<task::TaskContext>> {
 8291        let position = Point::new(buffer_row, tasks.column);
 8292        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8293        let location = Location {
 8294            buffer: buffer.clone(),
 8295            range: range_start..range_start,
 8296        };
 8297        // Fill in the environmental variables from the tree-sitter captures
 8298        let mut captured_task_variables = TaskVariables::default();
 8299        for (capture_name, value) in tasks.extra_variables.clone() {
 8300            captured_task_variables.insert(
 8301                task::VariableName::Custom(capture_name.into()),
 8302                value.clone(),
 8303            );
 8304        }
 8305        project.update(cx, |project, cx| {
 8306            project.task_store().update(cx, |task_store, cx| {
 8307                task_store.task_context_for_location(captured_task_variables, location, cx)
 8308            })
 8309        })
 8310    }
 8311
 8312    pub fn spawn_nearest_task(
 8313        &mut self,
 8314        action: &SpawnNearestTask,
 8315        window: &mut Window,
 8316        cx: &mut Context<Self>,
 8317    ) {
 8318        let Some((workspace, _)) = self.workspace.clone() else {
 8319            return;
 8320        };
 8321        let Some(project) = self.project.clone() else {
 8322            return;
 8323        };
 8324
 8325        // Try to find a closest, enclosing node using tree-sitter that has a task
 8326        let Some((buffer, buffer_row, tasks)) = self
 8327            .find_enclosing_node_task(cx)
 8328            // Or find the task that's closest in row-distance.
 8329            .or_else(|| self.find_closest_task(cx))
 8330        else {
 8331            return;
 8332        };
 8333
 8334        let reveal_strategy = action.reveal;
 8335        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8336        cx.spawn_in(window, async move |_, cx| {
 8337            let context = task_context.await?;
 8338            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8339
 8340            let resolved = &mut resolved_task.resolved;
 8341            resolved.reveal = reveal_strategy;
 8342
 8343            workspace
 8344                .update_in(cx, |workspace, window, cx| {
 8345                    workspace.schedule_resolved_task(
 8346                        task_source_kind,
 8347                        resolved_task,
 8348                        false,
 8349                        window,
 8350                        cx,
 8351                    );
 8352                })
 8353                .ok()
 8354        })
 8355        .detach();
 8356    }
 8357
 8358    fn find_closest_task(
 8359        &mut self,
 8360        cx: &mut Context<Self>,
 8361    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8362        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8363
 8364        let ((buffer_id, row), tasks) = self
 8365            .tasks
 8366            .iter()
 8367            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8368
 8369        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8370        let tasks = Arc::new(tasks.to_owned());
 8371        Some((buffer, *row, tasks))
 8372    }
 8373
 8374    fn find_enclosing_node_task(
 8375        &mut self,
 8376        cx: &mut Context<Self>,
 8377    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8378        let snapshot = self.buffer.read(cx).snapshot(cx);
 8379        let offset = self.selections.newest::<usize>(cx).head();
 8380        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8381        let buffer_id = excerpt.buffer().remote_id();
 8382
 8383        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8384        let mut cursor = layer.node().walk();
 8385
 8386        while cursor.goto_first_child_for_byte(offset).is_some() {
 8387            if cursor.node().end_byte() == offset {
 8388                cursor.goto_next_sibling();
 8389            }
 8390        }
 8391
 8392        // Ascend to the smallest ancestor that contains the range and has a task.
 8393        loop {
 8394            let node = cursor.node();
 8395            let node_range = node.byte_range();
 8396            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8397
 8398            // Check if this node contains our offset
 8399            if node_range.start <= offset && node_range.end >= offset {
 8400                // If it contains offset, check for task
 8401                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8402                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8403                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8404                }
 8405            }
 8406
 8407            if !cursor.goto_parent() {
 8408                break;
 8409            }
 8410        }
 8411        None
 8412    }
 8413
 8414    fn render_run_indicator(
 8415        &self,
 8416        _style: &EditorStyle,
 8417        is_active: bool,
 8418        row: DisplayRow,
 8419        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8420        cx: &mut Context<Self>,
 8421    ) -> IconButton {
 8422        let color = Color::Muted;
 8423        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8424
 8425        IconButton::new(
 8426            ("run_indicator", row.0 as usize),
 8427            ui::IconName::PlayOutlined,
 8428        )
 8429        .shape(ui::IconButtonShape::Square)
 8430        .icon_size(IconSize::XSmall)
 8431        .icon_color(color)
 8432        .toggle_state(is_active)
 8433        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8434            let quick_launch = match e {
 8435                ClickEvent::Keyboard(_) => true,
 8436                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8437            };
 8438
 8439            window.focus(&editor.focus_handle(cx));
 8440            editor.toggle_code_actions(
 8441                &ToggleCodeActions {
 8442                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8443                    quick_launch,
 8444                },
 8445                window,
 8446                cx,
 8447            );
 8448        }))
 8449        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8450            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8451        }))
 8452    }
 8453
 8454    pub fn context_menu_visible(&self) -> bool {
 8455        !self.edit_prediction_preview_is_active()
 8456            && self
 8457                .context_menu
 8458                .borrow()
 8459                .as_ref()
 8460                .is_some_and(|menu| menu.visible())
 8461    }
 8462
 8463    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8464        self.context_menu
 8465            .borrow()
 8466            .as_ref()
 8467            .map(|menu| menu.origin())
 8468    }
 8469
 8470    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8471        self.context_menu_options = Some(options);
 8472    }
 8473
 8474    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8475    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8476
 8477    fn render_edit_prediction_popover(
 8478        &mut self,
 8479        text_bounds: &Bounds<Pixels>,
 8480        content_origin: gpui::Point<Pixels>,
 8481        right_margin: Pixels,
 8482        editor_snapshot: &EditorSnapshot,
 8483        visible_row_range: Range<DisplayRow>,
 8484        scroll_top: f32,
 8485        scroll_bottom: f32,
 8486        line_layouts: &[LineWithInvisibles],
 8487        line_height: Pixels,
 8488        scroll_pixel_position: gpui::Point<Pixels>,
 8489        newest_selection_head: Option<DisplayPoint>,
 8490        editor_width: Pixels,
 8491        style: &EditorStyle,
 8492        window: &mut Window,
 8493        cx: &mut App,
 8494    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8495        if self.mode().is_minimap() {
 8496            return None;
 8497        }
 8498        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8499
 8500        if self.edit_prediction_visible_in_cursor_popover(true) {
 8501            return None;
 8502        }
 8503
 8504        match &active_edit_prediction.completion {
 8505            EditPrediction::Move { target, .. } => {
 8506                let target_display_point = target.to_display_point(editor_snapshot);
 8507
 8508                if self.edit_prediction_requires_modifier() {
 8509                    if !self.edit_prediction_preview_is_active() {
 8510                        return None;
 8511                    }
 8512
 8513                    self.render_edit_prediction_modifier_jump_popover(
 8514                        text_bounds,
 8515                        content_origin,
 8516                        visible_row_range,
 8517                        line_layouts,
 8518                        line_height,
 8519                        scroll_pixel_position,
 8520                        newest_selection_head,
 8521                        target_display_point,
 8522                        window,
 8523                        cx,
 8524                    )
 8525                } else {
 8526                    self.render_edit_prediction_eager_jump_popover(
 8527                        text_bounds,
 8528                        content_origin,
 8529                        editor_snapshot,
 8530                        visible_row_range,
 8531                        scroll_top,
 8532                        scroll_bottom,
 8533                        line_height,
 8534                        scroll_pixel_position,
 8535                        target_display_point,
 8536                        editor_width,
 8537                        window,
 8538                        cx,
 8539                    )
 8540                }
 8541            }
 8542            EditPrediction::Edit {
 8543                display_mode: EditDisplayMode::Inline,
 8544                ..
 8545            } => None,
 8546            EditPrediction::Edit {
 8547                display_mode: EditDisplayMode::TabAccept,
 8548                edits,
 8549                ..
 8550            } => {
 8551                let range = &edits.first()?.0;
 8552                let target_display_point = range.end.to_display_point(editor_snapshot);
 8553
 8554                self.render_edit_prediction_end_of_line_popover(
 8555                    "Accept",
 8556                    editor_snapshot,
 8557                    visible_row_range,
 8558                    target_display_point,
 8559                    line_height,
 8560                    scroll_pixel_position,
 8561                    content_origin,
 8562                    editor_width,
 8563                    window,
 8564                    cx,
 8565                )
 8566            }
 8567            EditPrediction::Edit {
 8568                edits,
 8569                edit_preview,
 8570                display_mode: EditDisplayMode::DiffPopover,
 8571                snapshot,
 8572            } => self.render_edit_prediction_diff_popover(
 8573                text_bounds,
 8574                content_origin,
 8575                right_margin,
 8576                editor_snapshot,
 8577                visible_row_range,
 8578                line_layouts,
 8579                line_height,
 8580                scroll_pixel_position,
 8581                newest_selection_head,
 8582                editor_width,
 8583                style,
 8584                edits,
 8585                edit_preview,
 8586                snapshot,
 8587                window,
 8588                cx,
 8589            ),
 8590        }
 8591    }
 8592
 8593    fn render_edit_prediction_modifier_jump_popover(
 8594        &mut self,
 8595        text_bounds: &Bounds<Pixels>,
 8596        content_origin: gpui::Point<Pixels>,
 8597        visible_row_range: Range<DisplayRow>,
 8598        line_layouts: &[LineWithInvisibles],
 8599        line_height: Pixels,
 8600        scroll_pixel_position: gpui::Point<Pixels>,
 8601        newest_selection_head: Option<DisplayPoint>,
 8602        target_display_point: DisplayPoint,
 8603        window: &mut Window,
 8604        cx: &mut App,
 8605    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8606        let scrolled_content_origin =
 8607            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8608
 8609        const SCROLL_PADDING_Y: Pixels = px(12.);
 8610
 8611        if target_display_point.row() < visible_row_range.start {
 8612            return self.render_edit_prediction_scroll_popover(
 8613                |_| SCROLL_PADDING_Y,
 8614                IconName::ArrowUp,
 8615                visible_row_range,
 8616                line_layouts,
 8617                newest_selection_head,
 8618                scrolled_content_origin,
 8619                window,
 8620                cx,
 8621            );
 8622        } else if target_display_point.row() >= visible_row_range.end {
 8623            return self.render_edit_prediction_scroll_popover(
 8624                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8625                IconName::ArrowDown,
 8626                visible_row_range,
 8627                line_layouts,
 8628                newest_selection_head,
 8629                scrolled_content_origin,
 8630                window,
 8631                cx,
 8632            );
 8633        }
 8634
 8635        const POLE_WIDTH: Pixels = px(2.);
 8636
 8637        let line_layout =
 8638            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8639        let target_column = target_display_point.column() as usize;
 8640
 8641        let target_x = line_layout.x_for_index(target_column);
 8642        let target_y =
 8643            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8644
 8645        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8646
 8647        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8648        border_color.l += 0.001;
 8649
 8650        let mut element = v_flex()
 8651            .items_end()
 8652            .when(flag_on_right, |el| el.items_start())
 8653            .child(if flag_on_right {
 8654                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8655                    .rounded_bl(px(0.))
 8656                    .rounded_tl(px(0.))
 8657                    .border_l_2()
 8658                    .border_color(border_color)
 8659            } else {
 8660                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8661                    .rounded_br(px(0.))
 8662                    .rounded_tr(px(0.))
 8663                    .border_r_2()
 8664                    .border_color(border_color)
 8665            })
 8666            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8667            .into_any();
 8668
 8669        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8670
 8671        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8672            - point(
 8673                if flag_on_right {
 8674                    POLE_WIDTH
 8675                } else {
 8676                    size.width - POLE_WIDTH
 8677                },
 8678                size.height - line_height,
 8679            );
 8680
 8681        origin.x = origin.x.max(content_origin.x);
 8682
 8683        element.prepaint_at(origin, window, cx);
 8684
 8685        Some((element, origin))
 8686    }
 8687
 8688    fn render_edit_prediction_scroll_popover(
 8689        &mut self,
 8690        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8691        scroll_icon: IconName,
 8692        visible_row_range: Range<DisplayRow>,
 8693        line_layouts: &[LineWithInvisibles],
 8694        newest_selection_head: Option<DisplayPoint>,
 8695        scrolled_content_origin: gpui::Point<Pixels>,
 8696        window: &mut Window,
 8697        cx: &mut App,
 8698    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8699        let mut element = self
 8700            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8701            .into_any();
 8702
 8703        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8704
 8705        let cursor = newest_selection_head?;
 8706        let cursor_row_layout =
 8707            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8708        let cursor_column = cursor.column() as usize;
 8709
 8710        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8711
 8712        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8713
 8714        element.prepaint_at(origin, window, cx);
 8715        Some((element, origin))
 8716    }
 8717
 8718    fn render_edit_prediction_eager_jump_popover(
 8719        &mut self,
 8720        text_bounds: &Bounds<Pixels>,
 8721        content_origin: gpui::Point<Pixels>,
 8722        editor_snapshot: &EditorSnapshot,
 8723        visible_row_range: Range<DisplayRow>,
 8724        scroll_top: f32,
 8725        scroll_bottom: f32,
 8726        line_height: Pixels,
 8727        scroll_pixel_position: gpui::Point<Pixels>,
 8728        target_display_point: DisplayPoint,
 8729        editor_width: Pixels,
 8730        window: &mut Window,
 8731        cx: &mut App,
 8732    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8733        if target_display_point.row().as_f32() < scroll_top {
 8734            let mut element = self
 8735                .render_edit_prediction_line_popover(
 8736                    "Jump to Edit",
 8737                    Some(IconName::ArrowUp),
 8738                    window,
 8739                    cx,
 8740                )?
 8741                .into_any();
 8742
 8743            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8744            let offset = point(
 8745                (text_bounds.size.width - size.width) / 2.,
 8746                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8747            );
 8748
 8749            let origin = text_bounds.origin + offset;
 8750            element.prepaint_at(origin, window, cx);
 8751            Some((element, origin))
 8752        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8753            let mut element = self
 8754                .render_edit_prediction_line_popover(
 8755                    "Jump to Edit",
 8756                    Some(IconName::ArrowDown),
 8757                    window,
 8758                    cx,
 8759                )?
 8760                .into_any();
 8761
 8762            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8763            let offset = point(
 8764                (text_bounds.size.width - size.width) / 2.,
 8765                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8766            );
 8767
 8768            let origin = text_bounds.origin + offset;
 8769            element.prepaint_at(origin, window, cx);
 8770            Some((element, origin))
 8771        } else {
 8772            self.render_edit_prediction_end_of_line_popover(
 8773                "Jump to Edit",
 8774                editor_snapshot,
 8775                visible_row_range,
 8776                target_display_point,
 8777                line_height,
 8778                scroll_pixel_position,
 8779                content_origin,
 8780                editor_width,
 8781                window,
 8782                cx,
 8783            )
 8784        }
 8785    }
 8786
 8787    fn render_edit_prediction_end_of_line_popover(
 8788        self: &mut Editor,
 8789        label: &'static str,
 8790        editor_snapshot: &EditorSnapshot,
 8791        visible_row_range: Range<DisplayRow>,
 8792        target_display_point: DisplayPoint,
 8793        line_height: Pixels,
 8794        scroll_pixel_position: gpui::Point<Pixels>,
 8795        content_origin: gpui::Point<Pixels>,
 8796        editor_width: Pixels,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        let target_line_end = DisplayPoint::new(
 8801            target_display_point.row(),
 8802            editor_snapshot.line_len(target_display_point.row()),
 8803        );
 8804
 8805        let mut element = self
 8806            .render_edit_prediction_line_popover(label, None, window, cx)?
 8807            .into_any();
 8808
 8809        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8810
 8811        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8812
 8813        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8814        let mut origin = start_point
 8815            + line_origin
 8816            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8817        origin.x = origin.x.max(content_origin.x);
 8818
 8819        let max_x = content_origin.x + editor_width - size.width;
 8820
 8821        if origin.x > max_x {
 8822            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8823
 8824            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8825                origin.y += offset;
 8826                IconName::ArrowUp
 8827            } else {
 8828                origin.y -= offset;
 8829                IconName::ArrowDown
 8830            };
 8831
 8832            element = self
 8833                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8834                .into_any();
 8835
 8836            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8837
 8838            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8839        }
 8840
 8841        element.prepaint_at(origin, window, cx);
 8842        Some((element, origin))
 8843    }
 8844
 8845    fn render_edit_prediction_diff_popover(
 8846        self: &Editor,
 8847        text_bounds: &Bounds<Pixels>,
 8848        content_origin: gpui::Point<Pixels>,
 8849        right_margin: Pixels,
 8850        editor_snapshot: &EditorSnapshot,
 8851        visible_row_range: Range<DisplayRow>,
 8852        line_layouts: &[LineWithInvisibles],
 8853        line_height: Pixels,
 8854        scroll_pixel_position: gpui::Point<Pixels>,
 8855        newest_selection_head: Option<DisplayPoint>,
 8856        editor_width: Pixels,
 8857        style: &EditorStyle,
 8858        edits: &Vec<(Range<Anchor>, String)>,
 8859        edit_preview: &Option<language::EditPreview>,
 8860        snapshot: &language::BufferSnapshot,
 8861        window: &mut Window,
 8862        cx: &mut App,
 8863    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8864        let edit_start = edits
 8865            .first()
 8866            .unwrap()
 8867            .0
 8868            .start
 8869            .to_display_point(editor_snapshot);
 8870        let edit_end = edits
 8871            .last()
 8872            .unwrap()
 8873            .0
 8874            .end
 8875            .to_display_point(editor_snapshot);
 8876
 8877        let is_visible = visible_row_range.contains(&edit_start.row())
 8878            || visible_row_range.contains(&edit_end.row());
 8879        if !is_visible {
 8880            return None;
 8881        }
 8882
 8883        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8884            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8885        } else {
 8886            // Fallback for providers without edit_preview
 8887            crate::edit_prediction_fallback_text(edits, cx)
 8888        };
 8889
 8890        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8891        let line_count = highlighted_edits.text.lines().count();
 8892
 8893        const BORDER_WIDTH: Pixels = px(1.);
 8894
 8895        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8896        let has_keybind = keybind.is_some();
 8897
 8898        let mut element = h_flex()
 8899            .items_start()
 8900            .child(
 8901                h_flex()
 8902                    .bg(cx.theme().colors().editor_background)
 8903                    .border(BORDER_WIDTH)
 8904                    .shadow_xs()
 8905                    .border_color(cx.theme().colors().border)
 8906                    .rounded_l_lg()
 8907                    .when(line_count > 1, |el| el.rounded_br_lg())
 8908                    .pr_1()
 8909                    .child(styled_text),
 8910            )
 8911            .child(
 8912                h_flex()
 8913                    .h(line_height + BORDER_WIDTH * 2.)
 8914                    .px_1p5()
 8915                    .gap_1()
 8916                    // Workaround: For some reason, there's a gap if we don't do this
 8917                    .ml(-BORDER_WIDTH)
 8918                    .shadow(vec![gpui::BoxShadow {
 8919                        color: gpui::black().opacity(0.05),
 8920                        offset: point(px(1.), px(1.)),
 8921                        blur_radius: px(2.),
 8922                        spread_radius: px(0.),
 8923                    }])
 8924                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8925                    .border(BORDER_WIDTH)
 8926                    .border_color(cx.theme().colors().border)
 8927                    .rounded_r_lg()
 8928                    .id("edit_prediction_diff_popover_keybind")
 8929                    .when(!has_keybind, |el| {
 8930                        let status_colors = cx.theme().status();
 8931
 8932                        el.bg(status_colors.error_background)
 8933                            .border_color(status_colors.error.opacity(0.6))
 8934                            .child(Icon::new(IconName::Info).color(Color::Error))
 8935                            .cursor_default()
 8936                            .hoverable_tooltip(move |_window, cx| {
 8937                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8938                            })
 8939                    })
 8940                    .children(keybind),
 8941            )
 8942            .into_any();
 8943
 8944        let longest_row =
 8945            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8946        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8947            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8948        } else {
 8949            layout_line(
 8950                longest_row,
 8951                editor_snapshot,
 8952                style,
 8953                editor_width,
 8954                |_| false,
 8955                window,
 8956                cx,
 8957            )
 8958            .width
 8959        };
 8960
 8961        let viewport_bounds =
 8962            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8963                right: -right_margin,
 8964                ..Default::default()
 8965            });
 8966
 8967        let x_after_longest =
 8968            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8969                - scroll_pixel_position.x;
 8970
 8971        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8972
 8973        // Fully visible if it can be displayed within the window (allow overlapping other
 8974        // panes). However, this is only allowed if the popover starts within text_bounds.
 8975        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8976            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8977
 8978        let mut origin = if can_position_to_the_right {
 8979            point(
 8980                x_after_longest,
 8981                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8982                    - scroll_pixel_position.y,
 8983            )
 8984        } else {
 8985            let cursor_row = newest_selection_head.map(|head| head.row());
 8986            let above_edit = edit_start
 8987                .row()
 8988                .0
 8989                .checked_sub(line_count as u32)
 8990                .map(DisplayRow);
 8991            let below_edit = Some(edit_end.row() + 1);
 8992            let above_cursor =
 8993                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8994            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8995
 8996            // Place the edit popover adjacent to the edit if there is a location
 8997            // available that is onscreen and does not obscure the cursor. Otherwise,
 8998            // place it adjacent to the cursor.
 8999            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9000                .into_iter()
 9001                .flatten()
 9002                .find(|&start_row| {
 9003                    let end_row = start_row + line_count as u32;
 9004                    visible_row_range.contains(&start_row)
 9005                        && visible_row_range.contains(&end_row)
 9006                        && cursor_row
 9007                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9008                })?;
 9009
 9010            content_origin
 9011                + point(
 9012                    -scroll_pixel_position.x,
 9013                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9014                )
 9015        };
 9016
 9017        origin.x -= BORDER_WIDTH;
 9018
 9019        window.defer_draw(element, origin, 1);
 9020
 9021        // Do not return an element, since it will already be drawn due to defer_draw.
 9022        None
 9023    }
 9024
 9025    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9026        px(30.)
 9027    }
 9028
 9029    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9030        if self.read_only(cx) {
 9031            cx.theme().players().read_only()
 9032        } else {
 9033            self.style.as_ref().unwrap().local_player
 9034        }
 9035    }
 9036
 9037    fn render_edit_prediction_accept_keybind(
 9038        &self,
 9039        window: &mut Window,
 9040        cx: &App,
 9041    ) -> Option<AnyElement> {
 9042        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9043        let accept_keystroke = accept_binding.keystroke()?;
 9044
 9045        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9046
 9047        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9048            Color::Accent
 9049        } else {
 9050            Color::Muted
 9051        };
 9052
 9053        h_flex()
 9054            .px_0p5()
 9055            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9056            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9057            .text_size(TextSize::XSmall.rems(cx))
 9058            .child(h_flex().children(ui::render_modifiers(
 9059                accept_keystroke.modifiers(),
 9060                PlatformStyle::platform(),
 9061                Some(modifiers_color),
 9062                Some(IconSize::XSmall.rems().into()),
 9063                true,
 9064            )))
 9065            .when(is_platform_style_mac, |parent| {
 9066                parent.child(accept_keystroke.key().to_string())
 9067            })
 9068            .when(!is_platform_style_mac, |parent| {
 9069                parent.child(
 9070                    Key::new(
 9071                        util::capitalize(accept_keystroke.key()),
 9072                        Some(Color::Default),
 9073                    )
 9074                    .size(Some(IconSize::XSmall.rems().into())),
 9075                )
 9076            })
 9077            .into_any()
 9078            .into()
 9079    }
 9080
 9081    fn render_edit_prediction_line_popover(
 9082        &self,
 9083        label: impl Into<SharedString>,
 9084        icon: Option<IconName>,
 9085        window: &mut Window,
 9086        cx: &App,
 9087    ) -> Option<Stateful<Div>> {
 9088        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9089
 9090        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9091        let has_keybind = keybind.is_some();
 9092
 9093        let result = h_flex()
 9094            .id("ep-line-popover")
 9095            .py_0p5()
 9096            .pl_1()
 9097            .pr(padding_right)
 9098            .gap_1()
 9099            .rounded_md()
 9100            .border_1()
 9101            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9102            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9103            .shadow_xs()
 9104            .when(!has_keybind, |el| {
 9105                let status_colors = cx.theme().status();
 9106
 9107                el.bg(status_colors.error_background)
 9108                    .border_color(status_colors.error.opacity(0.6))
 9109                    .pl_2()
 9110                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9111                    .cursor_default()
 9112                    .hoverable_tooltip(move |_window, cx| {
 9113                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9114                    })
 9115            })
 9116            .children(keybind)
 9117            .child(
 9118                Label::new(label)
 9119                    .size(LabelSize::Small)
 9120                    .when(!has_keybind, |el| {
 9121                        el.color(cx.theme().status().error.into()).strikethrough()
 9122                    }),
 9123            )
 9124            .when(!has_keybind, |el| {
 9125                el.child(
 9126                    h_flex().ml_1().child(
 9127                        Icon::new(IconName::Info)
 9128                            .size(IconSize::Small)
 9129                            .color(cx.theme().status().error.into()),
 9130                    ),
 9131                )
 9132            })
 9133            .when_some(icon, |element, icon| {
 9134                element.child(
 9135                    div()
 9136                        .mt(px(1.5))
 9137                        .child(Icon::new(icon).size(IconSize::Small)),
 9138                )
 9139            });
 9140
 9141        Some(result)
 9142    }
 9143
 9144    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9145        let accent_color = cx.theme().colors().text_accent;
 9146        let editor_bg_color = cx.theme().colors().editor_background;
 9147        editor_bg_color.blend(accent_color.opacity(0.1))
 9148    }
 9149
 9150    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9151        let accent_color = cx.theme().colors().text_accent;
 9152        let editor_bg_color = cx.theme().colors().editor_background;
 9153        editor_bg_color.blend(accent_color.opacity(0.6))
 9154    }
 9155    fn get_prediction_provider_icon_name(
 9156        provider: &Option<RegisteredEditPredictionProvider>,
 9157    ) -> IconName {
 9158        match provider {
 9159            Some(provider) => match provider.provider.name() {
 9160                "copilot" => IconName::Copilot,
 9161                "supermaven" => IconName::Supermaven,
 9162                _ => IconName::ZedPredict,
 9163            },
 9164            None => IconName::ZedPredict,
 9165        }
 9166    }
 9167
 9168    fn render_edit_prediction_cursor_popover(
 9169        &self,
 9170        min_width: Pixels,
 9171        max_width: Pixels,
 9172        cursor_point: Point,
 9173        style: &EditorStyle,
 9174        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9175        _window: &Window,
 9176        cx: &mut Context<Editor>,
 9177    ) -> Option<AnyElement> {
 9178        let provider = self.edit_prediction_provider.as_ref()?;
 9179        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9180
 9181        let is_refreshing = provider.provider.is_refreshing(cx);
 9182
 9183        fn pending_completion_container(icon: IconName) -> Div {
 9184            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9185        }
 9186
 9187        let completion = match &self.active_edit_prediction {
 9188            Some(prediction) => {
 9189                if !self.has_visible_completions_menu() {
 9190                    const RADIUS: Pixels = px(6.);
 9191                    const BORDER_WIDTH: Pixels = px(1.);
 9192
 9193                    return Some(
 9194                        h_flex()
 9195                            .elevation_2(cx)
 9196                            .border(BORDER_WIDTH)
 9197                            .border_color(cx.theme().colors().border)
 9198                            .when(accept_keystroke.is_none(), |el| {
 9199                                el.border_color(cx.theme().status().error)
 9200                            })
 9201                            .rounded(RADIUS)
 9202                            .rounded_tl(px(0.))
 9203                            .overflow_hidden()
 9204                            .child(div().px_1p5().child(match &prediction.completion {
 9205                                EditPrediction::Move { target, snapshot } => {
 9206                                    use text::ToPoint as _;
 9207                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9208                                    {
 9209                                        Icon::new(IconName::ZedPredictDown)
 9210                                    } else {
 9211                                        Icon::new(IconName::ZedPredictUp)
 9212                                    }
 9213                                }
 9214                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9215                            }))
 9216                            .child(
 9217                                h_flex()
 9218                                    .gap_1()
 9219                                    .py_1()
 9220                                    .px_2()
 9221                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9222                                    .border_l_1()
 9223                                    .border_color(cx.theme().colors().border)
 9224                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9225                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9226                                        el.child(
 9227                                            Label::new("Hold")
 9228                                                .size(LabelSize::Small)
 9229                                                .when(accept_keystroke.is_none(), |el| {
 9230                                                    el.strikethrough()
 9231                                                })
 9232                                                .line_height_style(LineHeightStyle::UiLabel),
 9233                                        )
 9234                                    })
 9235                                    .id("edit_prediction_cursor_popover_keybind")
 9236                                    .when(accept_keystroke.is_none(), |el| {
 9237                                        let status_colors = cx.theme().status();
 9238
 9239                                        el.bg(status_colors.error_background)
 9240                                            .border_color(status_colors.error.opacity(0.6))
 9241                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9242                                            .cursor_default()
 9243                                            .hoverable_tooltip(move |_window, cx| {
 9244                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9245                                                    .into()
 9246                                            })
 9247                                    })
 9248                                    .when_some(
 9249                                        accept_keystroke.as_ref(),
 9250                                        |el, accept_keystroke| {
 9251                                            el.child(h_flex().children(ui::render_modifiers(
 9252                                                accept_keystroke.modifiers(),
 9253                                                PlatformStyle::platform(),
 9254                                                Some(Color::Default),
 9255                                                Some(IconSize::XSmall.rems().into()),
 9256                                                false,
 9257                                            )))
 9258                                        },
 9259                                    ),
 9260                            )
 9261                            .into_any(),
 9262                    );
 9263                }
 9264
 9265                self.render_edit_prediction_cursor_popover_preview(
 9266                    prediction,
 9267                    cursor_point,
 9268                    style,
 9269                    cx,
 9270                )?
 9271            }
 9272
 9273            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9274                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9275                    stale_completion,
 9276                    cursor_point,
 9277                    style,
 9278                    cx,
 9279                )?,
 9280
 9281                None => pending_completion_container(provider_icon)
 9282                    .child(Label::new("...").size(LabelSize::Small)),
 9283            },
 9284
 9285            None => pending_completion_container(provider_icon)
 9286                .child(Label::new("...").size(LabelSize::Small)),
 9287        };
 9288
 9289        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9290            completion
 9291                .with_animation(
 9292                    "loading-completion",
 9293                    Animation::new(Duration::from_secs(2))
 9294                        .repeat()
 9295                        .with_easing(pulsating_between(0.4, 0.8)),
 9296                    |label, delta| label.opacity(delta),
 9297                )
 9298                .into_any_element()
 9299        } else {
 9300            completion.into_any_element()
 9301        };
 9302
 9303        let has_completion = self.active_edit_prediction.is_some();
 9304
 9305        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9306        Some(
 9307            h_flex()
 9308                .min_w(min_width)
 9309                .max_w(max_width)
 9310                .flex_1()
 9311                .elevation_2(cx)
 9312                .border_color(cx.theme().colors().border)
 9313                .child(
 9314                    div()
 9315                        .flex_1()
 9316                        .py_1()
 9317                        .px_2()
 9318                        .overflow_hidden()
 9319                        .child(completion),
 9320                )
 9321                .when_some(accept_keystroke, |el, accept_keystroke| {
 9322                    if !accept_keystroke.modifiers().modified() {
 9323                        return el;
 9324                    }
 9325
 9326                    el.child(
 9327                        h_flex()
 9328                            .h_full()
 9329                            .border_l_1()
 9330                            .rounded_r_lg()
 9331                            .border_color(cx.theme().colors().border)
 9332                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9333                            .gap_1()
 9334                            .py_1()
 9335                            .px_2()
 9336                            .child(
 9337                                h_flex()
 9338                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9339                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9340                                    .child(h_flex().children(ui::render_modifiers(
 9341                                        accept_keystroke.modifiers(),
 9342                                        PlatformStyle::platform(),
 9343                                        Some(if !has_completion {
 9344                                            Color::Muted
 9345                                        } else {
 9346                                            Color::Default
 9347                                        }),
 9348                                        None,
 9349                                        false,
 9350                                    ))),
 9351                            )
 9352                            .child(Label::new("Preview").into_any_element())
 9353                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9354                    )
 9355                })
 9356                .into_any(),
 9357        )
 9358    }
 9359
 9360    fn render_edit_prediction_cursor_popover_preview(
 9361        &self,
 9362        completion: &EditPredictionState,
 9363        cursor_point: Point,
 9364        style: &EditorStyle,
 9365        cx: &mut Context<Editor>,
 9366    ) -> Option<Div> {
 9367        use text::ToPoint as _;
 9368
 9369        fn render_relative_row_jump(
 9370            prefix: impl Into<String>,
 9371            current_row: u32,
 9372            target_row: u32,
 9373        ) -> Div {
 9374            let (row_diff, arrow) = if target_row < current_row {
 9375                (current_row - target_row, IconName::ArrowUp)
 9376            } else {
 9377                (target_row - current_row, IconName::ArrowDown)
 9378            };
 9379
 9380            h_flex()
 9381                .child(
 9382                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9383                        .color(Color::Muted)
 9384                        .size(LabelSize::Small),
 9385                )
 9386                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9387        }
 9388
 9389        let supports_jump = self
 9390            .edit_prediction_provider
 9391            .as_ref()
 9392            .map(|provider| provider.provider.supports_jump_to_edit())
 9393            .unwrap_or(true);
 9394
 9395        match &completion.completion {
 9396            EditPrediction::Move {
 9397                target, snapshot, ..
 9398            } => {
 9399                if !supports_jump {
 9400                    return None;
 9401                }
 9402
 9403                Some(
 9404                    h_flex()
 9405                        .px_2()
 9406                        .gap_2()
 9407                        .flex_1()
 9408                        .child(
 9409                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9410                                Icon::new(IconName::ZedPredictDown)
 9411                            } else {
 9412                                Icon::new(IconName::ZedPredictUp)
 9413                            },
 9414                        )
 9415                        .child(Label::new("Jump to Edit")),
 9416                )
 9417            }
 9418
 9419            EditPrediction::Edit {
 9420                edits,
 9421                edit_preview,
 9422                snapshot,
 9423                display_mode: _,
 9424            } => {
 9425                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9426
 9427                let (highlighted_edits, has_more_lines) =
 9428                    if let Some(edit_preview) = edit_preview.as_ref() {
 9429                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9430                            .first_line_preview()
 9431                    } else {
 9432                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9433                    };
 9434
 9435                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9436                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9437
 9438                let preview = h_flex()
 9439                    .gap_1()
 9440                    .min_w_16()
 9441                    .child(styled_text)
 9442                    .when(has_more_lines, |parent| parent.child(""));
 9443
 9444                let left = if supports_jump && first_edit_row != cursor_point.row {
 9445                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9446                        .into_any_element()
 9447                } else {
 9448                    let icon_name =
 9449                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9450                    Icon::new(icon_name).into_any_element()
 9451                };
 9452
 9453                Some(
 9454                    h_flex()
 9455                        .h_full()
 9456                        .flex_1()
 9457                        .gap_2()
 9458                        .pr_1()
 9459                        .overflow_x_hidden()
 9460                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9461                        .child(left)
 9462                        .child(preview),
 9463                )
 9464            }
 9465        }
 9466    }
 9467
 9468    pub fn render_context_menu(
 9469        &self,
 9470        style: &EditorStyle,
 9471        max_height_in_lines: u32,
 9472        window: &mut Window,
 9473        cx: &mut Context<Editor>,
 9474    ) -> Option<AnyElement> {
 9475        let menu = self.context_menu.borrow();
 9476        let menu = menu.as_ref()?;
 9477        if !menu.visible() {
 9478            return None;
 9479        };
 9480        Some(menu.render(style, max_height_in_lines, window, cx))
 9481    }
 9482
 9483    fn render_context_menu_aside(
 9484        &mut self,
 9485        max_size: Size<Pixels>,
 9486        window: &mut Window,
 9487        cx: &mut Context<Editor>,
 9488    ) -> Option<AnyElement> {
 9489        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9490            if menu.visible() {
 9491                menu.render_aside(max_size, window, cx)
 9492            } else {
 9493                None
 9494            }
 9495        })
 9496    }
 9497
 9498    fn hide_context_menu(
 9499        &mut self,
 9500        window: &mut Window,
 9501        cx: &mut Context<Self>,
 9502    ) -> Option<CodeContextMenu> {
 9503        cx.notify();
 9504        self.completion_tasks.clear();
 9505        let context_menu = self.context_menu.borrow_mut().take();
 9506        self.stale_edit_prediction_in_menu.take();
 9507        self.update_visible_edit_prediction(window, cx);
 9508        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9509            && let Some(completion_provider) = &self.completion_provider
 9510        {
 9511            completion_provider.selection_changed(None, window, cx);
 9512        }
 9513        context_menu
 9514    }
 9515
 9516    fn show_snippet_choices(
 9517        &mut self,
 9518        choices: &Vec<String>,
 9519        selection: Range<Anchor>,
 9520        cx: &mut Context<Self>,
 9521    ) {
 9522        let Some((_, buffer, _)) = self
 9523            .buffer()
 9524            .read(cx)
 9525            .excerpt_containing(selection.start, cx)
 9526        else {
 9527            return;
 9528        };
 9529        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9530        else {
 9531            return;
 9532        };
 9533        if buffer != end_buffer {
 9534            log::error!("expected anchor range to have matching buffer IDs");
 9535            return;
 9536        }
 9537
 9538        let id = post_inc(&mut self.next_completion_id);
 9539        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9540        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9541            CompletionsMenu::new_snippet_choices(
 9542                id,
 9543                true,
 9544                choices,
 9545                selection,
 9546                buffer,
 9547                snippet_sort_order,
 9548            ),
 9549        ));
 9550    }
 9551
 9552    pub fn insert_snippet(
 9553        &mut self,
 9554        insertion_ranges: &[Range<usize>],
 9555        snippet: Snippet,
 9556        window: &mut Window,
 9557        cx: &mut Context<Self>,
 9558    ) -> Result<()> {
 9559        struct Tabstop<T> {
 9560            is_end_tabstop: bool,
 9561            ranges: Vec<Range<T>>,
 9562            choices: Option<Vec<String>>,
 9563        }
 9564
 9565        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9566            let snippet_text: Arc<str> = snippet.text.clone().into();
 9567            let edits = insertion_ranges
 9568                .iter()
 9569                .cloned()
 9570                .map(|range| (range, snippet_text.clone()));
 9571            let autoindent_mode = AutoindentMode::Block {
 9572                original_indent_columns: Vec::new(),
 9573            };
 9574            buffer.edit(edits, Some(autoindent_mode), cx);
 9575
 9576            let snapshot = &*buffer.read(cx);
 9577            let snippet = &snippet;
 9578            snippet
 9579                .tabstops
 9580                .iter()
 9581                .map(|tabstop| {
 9582                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9583                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9584                    });
 9585                    let mut tabstop_ranges = tabstop
 9586                        .ranges
 9587                        .iter()
 9588                        .flat_map(|tabstop_range| {
 9589                            let mut delta = 0_isize;
 9590                            insertion_ranges.iter().map(move |insertion_range| {
 9591                                let insertion_start = insertion_range.start as isize + delta;
 9592                                delta +=
 9593                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9594
 9595                                let start = ((insertion_start + tabstop_range.start) as usize)
 9596                                    .min(snapshot.len());
 9597                                let end = ((insertion_start + tabstop_range.end) as usize)
 9598                                    .min(snapshot.len());
 9599                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9600                            })
 9601                        })
 9602                        .collect::<Vec<_>>();
 9603                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9604
 9605                    Tabstop {
 9606                        is_end_tabstop,
 9607                        ranges: tabstop_ranges,
 9608                        choices: tabstop.choices.clone(),
 9609                    }
 9610                })
 9611                .collect::<Vec<_>>()
 9612        });
 9613        if let Some(tabstop) = tabstops.first() {
 9614            self.change_selections(Default::default(), window, cx, |s| {
 9615                // Reverse order so that the first range is the newest created selection.
 9616                // Completions will use it and autoscroll will prioritize it.
 9617                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9618            });
 9619
 9620            if let Some(choices) = &tabstop.choices
 9621                && let Some(selection) = tabstop.ranges.first()
 9622            {
 9623                self.show_snippet_choices(choices, selection.clone(), cx)
 9624            }
 9625
 9626            // If we're already at the last tabstop and it's at the end of the snippet,
 9627            // we're done, we don't need to keep the state around.
 9628            if !tabstop.is_end_tabstop {
 9629                let choices = tabstops
 9630                    .iter()
 9631                    .map(|tabstop| tabstop.choices.clone())
 9632                    .collect();
 9633
 9634                let ranges = tabstops
 9635                    .into_iter()
 9636                    .map(|tabstop| tabstop.ranges)
 9637                    .collect::<Vec<_>>();
 9638
 9639                self.snippet_stack.push(SnippetState {
 9640                    active_index: 0,
 9641                    ranges,
 9642                    choices,
 9643                });
 9644            }
 9645
 9646            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9647            if self.autoclose_regions.is_empty() {
 9648                let snapshot = self.buffer.read(cx).snapshot(cx);
 9649                let mut all_selections = self.selections.all::<Point>(cx);
 9650                for selection in &mut all_selections {
 9651                    let selection_head = selection.head();
 9652                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9653                        continue;
 9654                    };
 9655
 9656                    let mut bracket_pair = None;
 9657                    let max_lookup_length = scope
 9658                        .brackets()
 9659                        .map(|(pair, _)| {
 9660                            pair.start
 9661                                .as_str()
 9662                                .chars()
 9663                                .count()
 9664                                .max(pair.end.as_str().chars().count())
 9665                        })
 9666                        .max();
 9667                    if let Some(max_lookup_length) = max_lookup_length {
 9668                        let next_text = snapshot
 9669                            .chars_at(selection_head)
 9670                            .take(max_lookup_length)
 9671                            .collect::<String>();
 9672                        let prev_text = snapshot
 9673                            .reversed_chars_at(selection_head)
 9674                            .take(max_lookup_length)
 9675                            .collect::<String>();
 9676
 9677                        for (pair, enabled) in scope.brackets() {
 9678                            if enabled
 9679                                && pair.close
 9680                                && prev_text.starts_with(pair.start.as_str())
 9681                                && next_text.starts_with(pair.end.as_str())
 9682                            {
 9683                                bracket_pair = Some(pair.clone());
 9684                                break;
 9685                            }
 9686                        }
 9687                    }
 9688
 9689                    if let Some(pair) = bracket_pair {
 9690                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9691                        let autoclose_enabled =
 9692                            self.use_autoclose && snapshot_settings.use_autoclose;
 9693                        if autoclose_enabled {
 9694                            let start = snapshot.anchor_after(selection_head);
 9695                            let end = snapshot.anchor_after(selection_head);
 9696                            self.autoclose_regions.push(AutocloseRegion {
 9697                                selection_id: selection.id,
 9698                                range: start..end,
 9699                                pair,
 9700                            });
 9701                        }
 9702                    }
 9703                }
 9704            }
 9705        }
 9706        Ok(())
 9707    }
 9708
 9709    pub fn move_to_next_snippet_tabstop(
 9710        &mut self,
 9711        window: &mut Window,
 9712        cx: &mut Context<Self>,
 9713    ) -> bool {
 9714        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9715    }
 9716
 9717    pub fn move_to_prev_snippet_tabstop(
 9718        &mut self,
 9719        window: &mut Window,
 9720        cx: &mut Context<Self>,
 9721    ) -> bool {
 9722        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9723    }
 9724
 9725    pub fn move_to_snippet_tabstop(
 9726        &mut self,
 9727        bias: Bias,
 9728        window: &mut Window,
 9729        cx: &mut Context<Self>,
 9730    ) -> bool {
 9731        if let Some(mut snippet) = self.snippet_stack.pop() {
 9732            match bias {
 9733                Bias::Left => {
 9734                    if snippet.active_index > 0 {
 9735                        snippet.active_index -= 1;
 9736                    } else {
 9737                        self.snippet_stack.push(snippet);
 9738                        return false;
 9739                    }
 9740                }
 9741                Bias::Right => {
 9742                    if snippet.active_index + 1 < snippet.ranges.len() {
 9743                        snippet.active_index += 1;
 9744                    } else {
 9745                        self.snippet_stack.push(snippet);
 9746                        return false;
 9747                    }
 9748                }
 9749            }
 9750            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9751                self.change_selections(Default::default(), window, cx, |s| {
 9752                    // Reverse order so that the first range is the newest created selection.
 9753                    // Completions will use it and autoscroll will prioritize it.
 9754                    s.select_ranges(current_ranges.iter().rev().cloned())
 9755                });
 9756
 9757                if let Some(choices) = &snippet.choices[snippet.active_index]
 9758                    && let Some(selection) = current_ranges.first()
 9759                {
 9760                    self.show_snippet_choices(choices, selection.clone(), cx);
 9761                }
 9762
 9763                // If snippet state is not at the last tabstop, push it back on the stack
 9764                if snippet.active_index + 1 < snippet.ranges.len() {
 9765                    self.snippet_stack.push(snippet);
 9766                }
 9767                return true;
 9768            }
 9769        }
 9770
 9771        false
 9772    }
 9773
 9774    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9775        self.transact(window, cx, |this, window, cx| {
 9776            this.select_all(&SelectAll, window, cx);
 9777            this.insert("", window, cx);
 9778        });
 9779    }
 9780
 9781    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9782        if self.read_only(cx) {
 9783            return;
 9784        }
 9785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9786        self.transact(window, cx, |this, window, cx| {
 9787            this.select_autoclose_pair(window, cx);
 9788            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9789            if !this.linked_edit_ranges.is_empty() {
 9790                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9791                let snapshot = this.buffer.read(cx).snapshot(cx);
 9792
 9793                for selection in selections.iter() {
 9794                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9795                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9796                    if selection_start.buffer_id != selection_end.buffer_id {
 9797                        continue;
 9798                    }
 9799                    if let Some(ranges) =
 9800                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9801                    {
 9802                        for (buffer, entries) in ranges {
 9803                            linked_ranges.entry(buffer).or_default().extend(entries);
 9804                        }
 9805                    }
 9806                }
 9807            }
 9808
 9809            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9810            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9811            for selection in &mut selections {
 9812                if selection.is_empty() {
 9813                    let old_head = selection.head();
 9814                    let mut new_head =
 9815                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9816                            .to_point(&display_map);
 9817                    if let Some((buffer, line_buffer_range)) = display_map
 9818                        .buffer_snapshot
 9819                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9820                    {
 9821                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9822                        let indent_len = match indent_size.kind {
 9823                            IndentKind::Space => {
 9824                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9825                            }
 9826                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9827                        };
 9828                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9829                            let indent_len = indent_len.get();
 9830                            new_head = cmp::min(
 9831                                new_head,
 9832                                MultiBufferPoint::new(
 9833                                    old_head.row,
 9834                                    ((old_head.column - 1) / indent_len) * indent_len,
 9835                                ),
 9836                            );
 9837                        }
 9838                    }
 9839
 9840                    selection.set_head(new_head, SelectionGoal::None);
 9841                }
 9842            }
 9843
 9844            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9845            this.insert("", window, cx);
 9846            let empty_str: Arc<str> = Arc::from("");
 9847            for (buffer, edits) in linked_ranges {
 9848                let snapshot = buffer.read(cx).snapshot();
 9849                use text::ToPoint as TP;
 9850
 9851                let edits = edits
 9852                    .into_iter()
 9853                    .map(|range| {
 9854                        let end_point = TP::to_point(&range.end, &snapshot);
 9855                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9856
 9857                        if end_point == start_point {
 9858                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9859                                .saturating_sub(1);
 9860                            start_point =
 9861                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9862                        };
 9863
 9864                        (start_point..end_point, empty_str.clone())
 9865                    })
 9866                    .sorted_by_key(|(range, _)| range.start)
 9867                    .collect::<Vec<_>>();
 9868                buffer.update(cx, |this, cx| {
 9869                    this.edit(edits, None, cx);
 9870                })
 9871            }
 9872            this.refresh_edit_prediction(true, false, window, cx);
 9873            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9874        });
 9875    }
 9876
 9877    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9878        if self.read_only(cx) {
 9879            return;
 9880        }
 9881        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9882        self.transact(window, cx, |this, window, cx| {
 9883            this.change_selections(Default::default(), window, cx, |s| {
 9884                s.move_with(|map, selection| {
 9885                    if selection.is_empty() {
 9886                        let cursor = movement::right(map, selection.head());
 9887                        selection.end = cursor;
 9888                        selection.reversed = true;
 9889                        selection.goal = SelectionGoal::None;
 9890                    }
 9891                })
 9892            });
 9893            this.insert("", window, cx);
 9894            this.refresh_edit_prediction(true, false, window, cx);
 9895        });
 9896    }
 9897
 9898    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9899        if self.mode.is_single_line() {
 9900            cx.propagate();
 9901            return;
 9902        }
 9903
 9904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9905        if self.move_to_prev_snippet_tabstop(window, cx) {
 9906            return;
 9907        }
 9908        self.outdent(&Outdent, window, cx);
 9909    }
 9910
 9911    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9912        if self.mode.is_single_line() {
 9913            cx.propagate();
 9914            return;
 9915        }
 9916
 9917        if self.move_to_next_snippet_tabstop(window, cx) {
 9918            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9919            return;
 9920        }
 9921        if self.read_only(cx) {
 9922            return;
 9923        }
 9924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9925        let mut selections = self.selections.all_adjusted(cx);
 9926        let buffer = self.buffer.read(cx);
 9927        let snapshot = buffer.snapshot(cx);
 9928        let rows_iter = selections.iter().map(|s| s.head().row);
 9929        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9930
 9931        let has_some_cursor_in_whitespace = selections
 9932            .iter()
 9933            .filter(|selection| selection.is_empty())
 9934            .any(|selection| {
 9935                let cursor = selection.head();
 9936                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9937                cursor.column < current_indent.len
 9938            });
 9939
 9940        let mut edits = Vec::new();
 9941        let mut prev_edited_row = 0;
 9942        let mut row_delta = 0;
 9943        for selection in &mut selections {
 9944            if selection.start.row != prev_edited_row {
 9945                row_delta = 0;
 9946            }
 9947            prev_edited_row = selection.end.row;
 9948
 9949            // If the selection is non-empty, then increase the indentation of the selected lines.
 9950            if !selection.is_empty() {
 9951                row_delta =
 9952                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9953                continue;
 9954            }
 9955
 9956            let cursor = selection.head();
 9957            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9958            if let Some(suggested_indent) =
 9959                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9960            {
 9961                // Don't do anything if already at suggested indent
 9962                // and there is any other cursor which is not
 9963                if has_some_cursor_in_whitespace
 9964                    && cursor.column == current_indent.len
 9965                    && current_indent.len == suggested_indent.len
 9966                {
 9967                    continue;
 9968                }
 9969
 9970                // Adjust line and move cursor to suggested indent
 9971                // if cursor is not at suggested indent
 9972                if cursor.column < suggested_indent.len
 9973                    && cursor.column <= current_indent.len
 9974                    && current_indent.len <= suggested_indent.len
 9975                {
 9976                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9977                    selection.end = selection.start;
 9978                    if row_delta == 0 {
 9979                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9980                            cursor.row,
 9981                            current_indent,
 9982                            suggested_indent,
 9983                        ));
 9984                        row_delta = suggested_indent.len - current_indent.len;
 9985                    }
 9986                    continue;
 9987                }
 9988
 9989                // If current indent is more than suggested indent
 9990                // only move cursor to current indent and skip indent
 9991                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9992                    selection.start = Point::new(cursor.row, current_indent.len);
 9993                    selection.end = selection.start;
 9994                    continue;
 9995                }
 9996            }
 9997
 9998            // Otherwise, insert a hard or soft tab.
 9999            let settings = buffer.language_settings_at(cursor, cx);
10000            let tab_size = if settings.hard_tabs {
10001                IndentSize::tab()
10002            } else {
10003                let tab_size = settings.tab_size.get();
10004                let indent_remainder = snapshot
10005                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10006                    .flat_map(str::chars)
10007                    .fold(row_delta % tab_size, |counter: u32, c| {
10008                        if c == '\t' {
10009                            0
10010                        } else {
10011                            (counter + 1) % tab_size
10012                        }
10013                    });
10014
10015                let chars_to_next_tab_stop = tab_size - indent_remainder;
10016                IndentSize::spaces(chars_to_next_tab_stop)
10017            };
10018            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10019            selection.end = selection.start;
10020            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10021            row_delta += tab_size.len;
10022        }
10023
10024        self.transact(window, cx, |this, window, cx| {
10025            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10026            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10027            this.refresh_edit_prediction(true, false, window, cx);
10028        });
10029    }
10030
10031    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10032        if self.read_only(cx) {
10033            return;
10034        }
10035        if self.mode.is_single_line() {
10036            cx.propagate();
10037            return;
10038        }
10039
10040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10041        let mut selections = self.selections.all::<Point>(cx);
10042        let mut prev_edited_row = 0;
10043        let mut row_delta = 0;
10044        let mut edits = Vec::new();
10045        let buffer = self.buffer.read(cx);
10046        let snapshot = buffer.snapshot(cx);
10047        for selection in &mut selections {
10048            if selection.start.row != prev_edited_row {
10049                row_delta = 0;
10050            }
10051            prev_edited_row = selection.end.row;
10052
10053            row_delta =
10054                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10055        }
10056
10057        self.transact(window, cx, |this, window, cx| {
10058            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10059            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10060        });
10061    }
10062
10063    fn indent_selection(
10064        buffer: &MultiBuffer,
10065        snapshot: &MultiBufferSnapshot,
10066        selection: &mut Selection<Point>,
10067        edits: &mut Vec<(Range<Point>, String)>,
10068        delta_for_start_row: u32,
10069        cx: &App,
10070    ) -> u32 {
10071        let settings = buffer.language_settings_at(selection.start, cx);
10072        let tab_size = settings.tab_size.get();
10073        let indent_kind = if settings.hard_tabs {
10074            IndentKind::Tab
10075        } else {
10076            IndentKind::Space
10077        };
10078        let mut start_row = selection.start.row;
10079        let mut end_row = selection.end.row + 1;
10080
10081        // If a selection ends at the beginning of a line, don't indent
10082        // that last line.
10083        if selection.end.column == 0 && selection.end.row > selection.start.row {
10084            end_row -= 1;
10085        }
10086
10087        // Avoid re-indenting a row that has already been indented by a
10088        // previous selection, but still update this selection's column
10089        // to reflect that indentation.
10090        if delta_for_start_row > 0 {
10091            start_row += 1;
10092            selection.start.column += delta_for_start_row;
10093            if selection.end.row == selection.start.row {
10094                selection.end.column += delta_for_start_row;
10095            }
10096        }
10097
10098        let mut delta_for_end_row = 0;
10099        let has_multiple_rows = start_row + 1 != end_row;
10100        for row in start_row..end_row {
10101            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10102            let indent_delta = match (current_indent.kind, indent_kind) {
10103                (IndentKind::Space, IndentKind::Space) => {
10104                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10105                    IndentSize::spaces(columns_to_next_tab_stop)
10106                }
10107                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10108                (_, IndentKind::Tab) => IndentSize::tab(),
10109            };
10110
10111            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10112                0
10113            } else {
10114                selection.start.column
10115            };
10116            let row_start = Point::new(row, start);
10117            edits.push((
10118                row_start..row_start,
10119                indent_delta.chars().collect::<String>(),
10120            ));
10121
10122            // Update this selection's endpoints to reflect the indentation.
10123            if row == selection.start.row {
10124                selection.start.column += indent_delta.len;
10125            }
10126            if row == selection.end.row {
10127                selection.end.column += indent_delta.len;
10128                delta_for_end_row = indent_delta.len;
10129            }
10130        }
10131
10132        if selection.start.row == selection.end.row {
10133            delta_for_start_row + delta_for_end_row
10134        } else {
10135            delta_for_end_row
10136        }
10137    }
10138
10139    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10140        if self.read_only(cx) {
10141            return;
10142        }
10143        if self.mode.is_single_line() {
10144            cx.propagate();
10145            return;
10146        }
10147
10148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10150        let selections = self.selections.all::<Point>(cx);
10151        let mut deletion_ranges = Vec::new();
10152        let mut last_outdent = None;
10153        {
10154            let buffer = self.buffer.read(cx);
10155            let snapshot = buffer.snapshot(cx);
10156            for selection in &selections {
10157                let settings = buffer.language_settings_at(selection.start, cx);
10158                let tab_size = settings.tab_size.get();
10159                let mut rows = selection.spanned_rows(false, &display_map);
10160
10161                // Avoid re-outdenting a row that has already been outdented by a
10162                // previous selection.
10163                if let Some(last_row) = last_outdent
10164                    && last_row == rows.start
10165                {
10166                    rows.start = rows.start.next_row();
10167                }
10168                let has_multiple_rows = rows.len() > 1;
10169                for row in rows.iter_rows() {
10170                    let indent_size = snapshot.indent_size_for_line(row);
10171                    if indent_size.len > 0 {
10172                        let deletion_len = match indent_size.kind {
10173                            IndentKind::Space => {
10174                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10175                                if columns_to_prev_tab_stop == 0 {
10176                                    tab_size
10177                                } else {
10178                                    columns_to_prev_tab_stop
10179                                }
10180                            }
10181                            IndentKind::Tab => 1,
10182                        };
10183                        let start = if has_multiple_rows
10184                            || deletion_len > selection.start.column
10185                            || indent_size.len < selection.start.column
10186                        {
10187                            0
10188                        } else {
10189                            selection.start.column - deletion_len
10190                        };
10191                        deletion_ranges.push(
10192                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10193                        );
10194                        last_outdent = Some(row);
10195                    }
10196                }
10197            }
10198        }
10199
10200        self.transact(window, cx, |this, window, cx| {
10201            this.buffer.update(cx, |buffer, cx| {
10202                let empty_str: Arc<str> = Arc::default();
10203                buffer.edit(
10204                    deletion_ranges
10205                        .into_iter()
10206                        .map(|range| (range, empty_str.clone())),
10207                    None,
10208                    cx,
10209                );
10210            });
10211            let selections = this.selections.all::<usize>(cx);
10212            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10213        });
10214    }
10215
10216    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10217        if self.read_only(cx) {
10218            return;
10219        }
10220        if self.mode.is_single_line() {
10221            cx.propagate();
10222            return;
10223        }
10224
10225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10226        let selections = self
10227            .selections
10228            .all::<usize>(cx)
10229            .into_iter()
10230            .map(|s| s.range());
10231
10232        self.transact(window, cx, |this, window, cx| {
10233            this.buffer.update(cx, |buffer, cx| {
10234                buffer.autoindent_ranges(selections, cx);
10235            });
10236            let selections = this.selections.all::<usize>(cx);
10237            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10238        });
10239    }
10240
10241    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10243        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10244        let selections = self.selections.all::<Point>(cx);
10245
10246        let mut new_cursors = Vec::new();
10247        let mut edit_ranges = Vec::new();
10248        let mut selections = selections.iter().peekable();
10249        while let Some(selection) = selections.next() {
10250            let mut rows = selection.spanned_rows(false, &display_map);
10251            let goal_display_column = selection.head().to_display_point(&display_map).column();
10252
10253            // Accumulate contiguous regions of rows that we want to delete.
10254            while let Some(next_selection) = selections.peek() {
10255                let next_rows = next_selection.spanned_rows(false, &display_map);
10256                if next_rows.start <= rows.end {
10257                    rows.end = next_rows.end;
10258                    selections.next().unwrap();
10259                } else {
10260                    break;
10261                }
10262            }
10263
10264            let buffer = &display_map.buffer_snapshot;
10265            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10266            let edit_end;
10267            let cursor_buffer_row;
10268            if buffer.max_point().row >= rows.end.0 {
10269                // If there's a line after the range, delete the \n from the end of the row range
10270                // and position the cursor on the next line.
10271                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10272                cursor_buffer_row = rows.end;
10273            } else {
10274                // If there isn't a line after the range, delete the \n from the line before the
10275                // start of the row range and position the cursor there.
10276                edit_start = edit_start.saturating_sub(1);
10277                edit_end = buffer.len();
10278                cursor_buffer_row = rows.start.previous_row();
10279            }
10280
10281            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10282            *cursor.column_mut() =
10283                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10284
10285            new_cursors.push((
10286                selection.id,
10287                buffer.anchor_after(cursor.to_point(&display_map)),
10288            ));
10289            edit_ranges.push(edit_start..edit_end);
10290        }
10291
10292        self.transact(window, cx, |this, window, cx| {
10293            let buffer = this.buffer.update(cx, |buffer, cx| {
10294                let empty_str: Arc<str> = Arc::default();
10295                buffer.edit(
10296                    edit_ranges
10297                        .into_iter()
10298                        .map(|range| (range, empty_str.clone())),
10299                    None,
10300                    cx,
10301                );
10302                buffer.snapshot(cx)
10303            });
10304            let new_selections = new_cursors
10305                .into_iter()
10306                .map(|(id, cursor)| {
10307                    let cursor = cursor.to_point(&buffer);
10308                    Selection {
10309                        id,
10310                        start: cursor,
10311                        end: cursor,
10312                        reversed: false,
10313                        goal: SelectionGoal::None,
10314                    }
10315                })
10316                .collect();
10317
10318            this.change_selections(Default::default(), window, cx, |s| {
10319                s.select(new_selections);
10320            });
10321        });
10322    }
10323
10324    pub fn join_lines_impl(
10325        &mut self,
10326        insert_whitespace: bool,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        if self.read_only(cx) {
10331            return;
10332        }
10333        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10334        for selection in self.selections.all::<Point>(cx) {
10335            let start = MultiBufferRow(selection.start.row);
10336            // Treat single line selections as if they include the next line. Otherwise this action
10337            // would do nothing for single line selections individual cursors.
10338            let end = if selection.start.row == selection.end.row {
10339                MultiBufferRow(selection.start.row + 1)
10340            } else {
10341                MultiBufferRow(selection.end.row)
10342            };
10343
10344            if let Some(last_row_range) = row_ranges.last_mut()
10345                && start <= last_row_range.end
10346            {
10347                last_row_range.end = end;
10348                continue;
10349            }
10350            row_ranges.push(start..end);
10351        }
10352
10353        let snapshot = self.buffer.read(cx).snapshot(cx);
10354        let mut cursor_positions = Vec::new();
10355        for row_range in &row_ranges {
10356            let anchor = snapshot.anchor_before(Point::new(
10357                row_range.end.previous_row().0,
10358                snapshot.line_len(row_range.end.previous_row()),
10359            ));
10360            cursor_positions.push(anchor..anchor);
10361        }
10362
10363        self.transact(window, cx, |this, window, cx| {
10364            for row_range in row_ranges.into_iter().rev() {
10365                for row in row_range.iter_rows().rev() {
10366                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10367                    let next_line_row = row.next_row();
10368                    let indent = snapshot.indent_size_for_line(next_line_row);
10369                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10370
10371                    let replace =
10372                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10373                            " "
10374                        } else {
10375                            ""
10376                        };
10377
10378                    this.buffer.update(cx, |buffer, cx| {
10379                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10380                    });
10381                }
10382            }
10383
10384            this.change_selections(Default::default(), window, cx, |s| {
10385                s.select_anchor_ranges(cursor_positions)
10386            });
10387        });
10388    }
10389
10390    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10392        self.join_lines_impl(true, window, cx);
10393    }
10394
10395    pub fn sort_lines_case_sensitive(
10396        &mut self,
10397        _: &SortLinesCaseSensitive,
10398        window: &mut Window,
10399        cx: &mut Context<Self>,
10400    ) {
10401        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10402    }
10403
10404    pub fn sort_lines_by_length(
10405        &mut self,
10406        _: &SortLinesByLength,
10407        window: &mut Window,
10408        cx: &mut Context<Self>,
10409    ) {
10410        self.manipulate_immutable_lines(window, cx, |lines| {
10411            lines.sort_by_key(|&line| line.chars().count())
10412        })
10413    }
10414
10415    pub fn sort_lines_case_insensitive(
10416        &mut self,
10417        _: &SortLinesCaseInsensitive,
10418        window: &mut Window,
10419        cx: &mut Context<Self>,
10420    ) {
10421        self.manipulate_immutable_lines(window, cx, |lines| {
10422            lines.sort_by_key(|line| line.to_lowercase())
10423        })
10424    }
10425
10426    pub fn unique_lines_case_insensitive(
10427        &mut self,
10428        _: &UniqueLinesCaseInsensitive,
10429        window: &mut Window,
10430        cx: &mut Context<Self>,
10431    ) {
10432        self.manipulate_immutable_lines(window, cx, |lines| {
10433            let mut seen = HashSet::default();
10434            lines.retain(|line| seen.insert(line.to_lowercase()));
10435        })
10436    }
10437
10438    pub fn unique_lines_case_sensitive(
10439        &mut self,
10440        _: &UniqueLinesCaseSensitive,
10441        window: &mut Window,
10442        cx: &mut Context<Self>,
10443    ) {
10444        self.manipulate_immutable_lines(window, cx, |lines| {
10445            let mut seen = HashSet::default();
10446            lines.retain(|line| seen.insert(*line));
10447        })
10448    }
10449
10450    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10451        let snapshot = self.buffer.read(cx).snapshot(cx);
10452        for selection in self.selections.disjoint_anchors().iter() {
10453            if snapshot
10454                .language_at(selection.start)
10455                .and_then(|lang| lang.config().wrap_characters.as_ref())
10456                .is_some()
10457            {
10458                return true;
10459            }
10460        }
10461        false
10462    }
10463
10464    fn wrap_selections_in_tag(
10465        &mut self,
10466        _: &WrapSelectionsInTag,
10467        window: &mut Window,
10468        cx: &mut Context<Self>,
10469    ) {
10470        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10471
10472        let snapshot = self.buffer.read(cx).snapshot(cx);
10473
10474        let mut edits = Vec::new();
10475        let mut boundaries = Vec::new();
10476
10477        for selection in self.selections.all::<Point>(cx).iter() {
10478            let Some(wrap_config) = snapshot
10479                .language_at(selection.start)
10480                .and_then(|lang| lang.config().wrap_characters.clone())
10481            else {
10482                continue;
10483            };
10484
10485            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10486            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10487
10488            let start_before = snapshot.anchor_before(selection.start);
10489            let end_after = snapshot.anchor_after(selection.end);
10490
10491            edits.push((start_before..start_before, open_tag));
10492            edits.push((end_after..end_after, close_tag));
10493
10494            boundaries.push((
10495                start_before,
10496                end_after,
10497                wrap_config.start_prefix.len(),
10498                wrap_config.end_suffix.len(),
10499            ));
10500        }
10501
10502        if edits.is_empty() {
10503            return;
10504        }
10505
10506        self.transact(window, cx, |this, window, cx| {
10507            let buffer = this.buffer.update(cx, |buffer, cx| {
10508                buffer.edit(edits, None, cx);
10509                buffer.snapshot(cx)
10510            });
10511
10512            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10513            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10514                boundaries.into_iter()
10515            {
10516                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10517                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10518                new_selections.push(open_offset..open_offset);
10519                new_selections.push(close_offset..close_offset);
10520            }
10521
10522            this.change_selections(Default::default(), window, cx, |s| {
10523                s.select_ranges(new_selections);
10524            });
10525
10526            this.request_autoscroll(Autoscroll::fit(), cx);
10527        });
10528    }
10529
10530    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10531        let Some(project) = self.project.clone() else {
10532            return;
10533        };
10534        self.reload(project, window, cx)
10535            .detach_and_notify_err(window, cx);
10536    }
10537
10538    pub fn restore_file(
10539        &mut self,
10540        _: &::git::RestoreFile,
10541        window: &mut Window,
10542        cx: &mut Context<Self>,
10543    ) {
10544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10545        let mut buffer_ids = HashSet::default();
10546        let snapshot = self.buffer().read(cx).snapshot(cx);
10547        for selection in self.selections.all::<usize>(cx) {
10548            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10549        }
10550
10551        let buffer = self.buffer().read(cx);
10552        let ranges = buffer_ids
10553            .into_iter()
10554            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10555            .collect::<Vec<_>>();
10556
10557        self.restore_hunks_in_ranges(ranges, window, cx);
10558    }
10559
10560    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10561        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10562        let selections = self
10563            .selections
10564            .all(cx)
10565            .into_iter()
10566            .map(|s| s.range())
10567            .collect();
10568        self.restore_hunks_in_ranges(selections, window, cx);
10569    }
10570
10571    pub fn restore_hunks_in_ranges(
10572        &mut self,
10573        ranges: Vec<Range<Point>>,
10574        window: &mut Window,
10575        cx: &mut Context<Editor>,
10576    ) {
10577        let mut revert_changes = HashMap::default();
10578        let chunk_by = self
10579            .snapshot(window, cx)
10580            .hunks_for_ranges(ranges)
10581            .into_iter()
10582            .chunk_by(|hunk| hunk.buffer_id);
10583        for (buffer_id, hunks) in &chunk_by {
10584            let hunks = hunks.collect::<Vec<_>>();
10585            for hunk in &hunks {
10586                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10587            }
10588            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10589        }
10590        drop(chunk_by);
10591        if !revert_changes.is_empty() {
10592            self.transact(window, cx, |editor, window, cx| {
10593                editor.restore(revert_changes, window, cx);
10594            });
10595        }
10596    }
10597
10598    pub fn open_active_item_in_terminal(
10599        &mut self,
10600        _: &OpenInTerminal,
10601        window: &mut Window,
10602        cx: &mut Context<Self>,
10603    ) {
10604        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10605            let project_path = buffer.read(cx).project_path(cx)?;
10606            let project = self.project()?.read(cx);
10607            let entry = project.entry_for_path(&project_path, cx)?;
10608            let parent = match &entry.canonical_path {
10609                Some(canonical_path) => canonical_path.to_path_buf(),
10610                None => project.absolute_path(&project_path, cx)?,
10611            }
10612            .parent()?
10613            .to_path_buf();
10614            Some(parent)
10615        }) {
10616            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10617        }
10618    }
10619
10620    fn set_breakpoint_context_menu(
10621        &mut self,
10622        display_row: DisplayRow,
10623        position: Option<Anchor>,
10624        clicked_point: gpui::Point<Pixels>,
10625        window: &mut Window,
10626        cx: &mut Context<Self>,
10627    ) {
10628        let source = self
10629            .buffer
10630            .read(cx)
10631            .snapshot(cx)
10632            .anchor_before(Point::new(display_row.0, 0u32));
10633
10634        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10635
10636        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10637            self,
10638            source,
10639            clicked_point,
10640            context_menu,
10641            window,
10642            cx,
10643        );
10644    }
10645
10646    fn add_edit_breakpoint_block(
10647        &mut self,
10648        anchor: Anchor,
10649        breakpoint: &Breakpoint,
10650        edit_action: BreakpointPromptEditAction,
10651        window: &mut Window,
10652        cx: &mut Context<Self>,
10653    ) {
10654        let weak_editor = cx.weak_entity();
10655        let bp_prompt = cx.new(|cx| {
10656            BreakpointPromptEditor::new(
10657                weak_editor,
10658                anchor,
10659                breakpoint.clone(),
10660                edit_action,
10661                window,
10662                cx,
10663            )
10664        });
10665
10666        let height = bp_prompt.update(cx, |this, cx| {
10667            this.prompt
10668                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10669        });
10670        let cloned_prompt = bp_prompt.clone();
10671        let blocks = vec![BlockProperties {
10672            style: BlockStyle::Sticky,
10673            placement: BlockPlacement::Above(anchor),
10674            height: Some(height),
10675            render: Arc::new(move |cx| {
10676                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10677                cloned_prompt.clone().into_any_element()
10678            }),
10679            priority: 0,
10680        }];
10681
10682        let focus_handle = bp_prompt.focus_handle(cx);
10683        window.focus(&focus_handle);
10684
10685        let block_ids = self.insert_blocks(blocks, None, cx);
10686        bp_prompt.update(cx, |prompt, _| {
10687            prompt.add_block_ids(block_ids);
10688        });
10689    }
10690
10691    pub(crate) fn breakpoint_at_row(
10692        &self,
10693        row: u32,
10694        window: &mut Window,
10695        cx: &mut Context<Self>,
10696    ) -> Option<(Anchor, Breakpoint)> {
10697        let snapshot = self.snapshot(window, cx);
10698        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10699
10700        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10701    }
10702
10703    pub(crate) fn breakpoint_at_anchor(
10704        &self,
10705        breakpoint_position: Anchor,
10706        snapshot: &EditorSnapshot,
10707        cx: &mut Context<Self>,
10708    ) -> Option<(Anchor, Breakpoint)> {
10709        let buffer = self
10710            .buffer
10711            .read(cx)
10712            .buffer_for_anchor(breakpoint_position, cx)?;
10713
10714        let enclosing_excerpt = breakpoint_position.excerpt_id;
10715        let buffer_snapshot = buffer.read(cx).snapshot();
10716
10717        let row = buffer_snapshot
10718            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10719            .row;
10720
10721        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10722        let anchor_end = snapshot
10723            .buffer_snapshot
10724            .anchor_after(Point::new(row, line_len));
10725
10726        self.breakpoint_store
10727            .as_ref()?
10728            .read_with(cx, |breakpoint_store, cx| {
10729                breakpoint_store
10730                    .breakpoints(
10731                        &buffer,
10732                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10733                        &buffer_snapshot,
10734                        cx,
10735                    )
10736                    .next()
10737                    .and_then(|(bp, _)| {
10738                        let breakpoint_row = buffer_snapshot
10739                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10740                            .row;
10741
10742                        if breakpoint_row == row {
10743                            snapshot
10744                                .buffer_snapshot
10745                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10746                                .map(|position| (position, bp.bp.clone()))
10747                        } else {
10748                            None
10749                        }
10750                    })
10751            })
10752    }
10753
10754    pub fn edit_log_breakpoint(
10755        &mut self,
10756        _: &EditLogBreakpoint,
10757        window: &mut Window,
10758        cx: &mut Context<Self>,
10759    ) {
10760        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10761            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10762                message: None,
10763                state: BreakpointState::Enabled,
10764                condition: None,
10765                hit_condition: None,
10766            });
10767
10768            self.add_edit_breakpoint_block(
10769                anchor,
10770                &breakpoint,
10771                BreakpointPromptEditAction::Log,
10772                window,
10773                cx,
10774            );
10775        }
10776    }
10777
10778    fn breakpoints_at_cursors(
10779        &self,
10780        window: &mut Window,
10781        cx: &mut Context<Self>,
10782    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10783        let snapshot = self.snapshot(window, cx);
10784        let cursors = self
10785            .selections
10786            .disjoint_anchors()
10787            .iter()
10788            .map(|selection| {
10789                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10790
10791                let breakpoint_position = self
10792                    .breakpoint_at_row(cursor_position.row, window, cx)
10793                    .map(|bp| bp.0)
10794                    .unwrap_or_else(|| {
10795                        snapshot
10796                            .display_snapshot
10797                            .buffer_snapshot
10798                            .anchor_after(Point::new(cursor_position.row, 0))
10799                    });
10800
10801                let breakpoint = self
10802                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10803                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10804
10805                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10806            })
10807            // 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.
10808            .collect::<HashMap<Anchor, _>>();
10809
10810        cursors.into_iter().collect()
10811    }
10812
10813    pub fn enable_breakpoint(
10814        &mut self,
10815        _: &crate::actions::EnableBreakpoint,
10816        window: &mut Window,
10817        cx: &mut Context<Self>,
10818    ) {
10819        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10820            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10821                continue;
10822            };
10823            self.edit_breakpoint_at_anchor(
10824                anchor,
10825                breakpoint,
10826                BreakpointEditAction::InvertState,
10827                cx,
10828            );
10829        }
10830    }
10831
10832    pub fn disable_breakpoint(
10833        &mut self,
10834        _: &crate::actions::DisableBreakpoint,
10835        window: &mut Window,
10836        cx: &mut Context<Self>,
10837    ) {
10838        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10839            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10840                continue;
10841            };
10842            self.edit_breakpoint_at_anchor(
10843                anchor,
10844                breakpoint,
10845                BreakpointEditAction::InvertState,
10846                cx,
10847            );
10848        }
10849    }
10850
10851    pub fn toggle_breakpoint(
10852        &mut self,
10853        _: &crate::actions::ToggleBreakpoint,
10854        window: &mut Window,
10855        cx: &mut Context<Self>,
10856    ) {
10857        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10858            if let Some(breakpoint) = breakpoint {
10859                self.edit_breakpoint_at_anchor(
10860                    anchor,
10861                    breakpoint,
10862                    BreakpointEditAction::Toggle,
10863                    cx,
10864                );
10865            } else {
10866                self.edit_breakpoint_at_anchor(
10867                    anchor,
10868                    Breakpoint::new_standard(),
10869                    BreakpointEditAction::Toggle,
10870                    cx,
10871                );
10872            }
10873        }
10874    }
10875
10876    pub fn edit_breakpoint_at_anchor(
10877        &mut self,
10878        breakpoint_position: Anchor,
10879        breakpoint: Breakpoint,
10880        edit_action: BreakpointEditAction,
10881        cx: &mut Context<Self>,
10882    ) {
10883        let Some(breakpoint_store) = &self.breakpoint_store else {
10884            return;
10885        };
10886
10887        let Some(buffer) = self
10888            .buffer
10889            .read(cx)
10890            .buffer_for_anchor(breakpoint_position, cx)
10891        else {
10892            return;
10893        };
10894
10895        breakpoint_store.update(cx, |breakpoint_store, cx| {
10896            breakpoint_store.toggle_breakpoint(
10897                buffer,
10898                BreakpointWithPosition {
10899                    position: breakpoint_position.text_anchor,
10900                    bp: breakpoint,
10901                },
10902                edit_action,
10903                cx,
10904            );
10905        });
10906
10907        cx.notify();
10908    }
10909
10910    #[cfg(any(test, feature = "test-support"))]
10911    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10912        self.breakpoint_store.clone()
10913    }
10914
10915    pub fn prepare_restore_change(
10916        &self,
10917        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10918        hunk: &MultiBufferDiffHunk,
10919        cx: &mut App,
10920    ) -> Option<()> {
10921        if hunk.is_created_file() {
10922            return None;
10923        }
10924        let buffer = self.buffer.read(cx);
10925        let diff = buffer.diff_for(hunk.buffer_id)?;
10926        let buffer = buffer.buffer(hunk.buffer_id)?;
10927        let buffer = buffer.read(cx);
10928        let original_text = diff
10929            .read(cx)
10930            .base_text()
10931            .as_rope()
10932            .slice(hunk.diff_base_byte_range.clone());
10933        let buffer_snapshot = buffer.snapshot();
10934        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10935        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10936            probe
10937                .0
10938                .start
10939                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10940                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10941        }) {
10942            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10943            Some(())
10944        } else {
10945            None
10946        }
10947    }
10948
10949    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10950        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10951    }
10952
10953    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10954        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10955    }
10956
10957    fn manipulate_lines<M>(
10958        &mut self,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961        mut manipulate: M,
10962    ) where
10963        M: FnMut(&str) -> LineManipulationResult,
10964    {
10965        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10966
10967        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10968        let buffer = self.buffer.read(cx).snapshot(cx);
10969
10970        let mut edits = Vec::new();
10971
10972        let selections = self.selections.all::<Point>(cx);
10973        let mut selections = selections.iter().peekable();
10974        let mut contiguous_row_selections = Vec::new();
10975        let mut new_selections = Vec::new();
10976        let mut added_lines = 0;
10977        let mut removed_lines = 0;
10978
10979        while let Some(selection) = selections.next() {
10980            let (start_row, end_row) = consume_contiguous_rows(
10981                &mut contiguous_row_selections,
10982                selection,
10983                &display_map,
10984                &mut selections,
10985            );
10986
10987            let start_point = Point::new(start_row.0, 0);
10988            let end_point = Point::new(
10989                end_row.previous_row().0,
10990                buffer.line_len(end_row.previous_row()),
10991            );
10992            let text = buffer
10993                .text_for_range(start_point..end_point)
10994                .collect::<String>();
10995
10996            let LineManipulationResult {
10997                new_text,
10998                line_count_before,
10999                line_count_after,
11000            } = manipulate(&text);
11001
11002            edits.push((start_point..end_point, new_text));
11003
11004            // Selections must change based on added and removed line count
11005            let start_row =
11006                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11007            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11008            new_selections.push(Selection {
11009                id: selection.id,
11010                start: start_row,
11011                end: end_row,
11012                goal: SelectionGoal::None,
11013                reversed: selection.reversed,
11014            });
11015
11016            if line_count_after > line_count_before {
11017                added_lines += line_count_after - line_count_before;
11018            } else if line_count_before > line_count_after {
11019                removed_lines += line_count_before - line_count_after;
11020            }
11021        }
11022
11023        self.transact(window, cx, |this, window, cx| {
11024            let buffer = this.buffer.update(cx, |buffer, cx| {
11025                buffer.edit(edits, None, cx);
11026                buffer.snapshot(cx)
11027            });
11028
11029            // Recalculate offsets on newly edited buffer
11030            let new_selections = new_selections
11031                .iter()
11032                .map(|s| {
11033                    let start_point = Point::new(s.start.0, 0);
11034                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11035                    Selection {
11036                        id: s.id,
11037                        start: buffer.point_to_offset(start_point),
11038                        end: buffer.point_to_offset(end_point),
11039                        goal: s.goal,
11040                        reversed: s.reversed,
11041                    }
11042                })
11043                .collect();
11044
11045            this.change_selections(Default::default(), window, cx, |s| {
11046                s.select(new_selections);
11047            });
11048
11049            this.request_autoscroll(Autoscroll::fit(), cx);
11050        });
11051    }
11052
11053    fn manipulate_immutable_lines<Fn>(
11054        &mut self,
11055        window: &mut Window,
11056        cx: &mut Context<Self>,
11057        mut callback: Fn,
11058    ) where
11059        Fn: FnMut(&mut Vec<&str>),
11060    {
11061        self.manipulate_lines(window, cx, |text| {
11062            let mut lines: Vec<&str> = text.split('\n').collect();
11063            let line_count_before = lines.len();
11064
11065            callback(&mut lines);
11066
11067            LineManipulationResult {
11068                new_text: lines.join("\n"),
11069                line_count_before,
11070                line_count_after: lines.len(),
11071            }
11072        });
11073    }
11074
11075    fn manipulate_mutable_lines<Fn>(
11076        &mut self,
11077        window: &mut Window,
11078        cx: &mut Context<Self>,
11079        mut callback: Fn,
11080    ) where
11081        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11082    {
11083        self.manipulate_lines(window, cx, |text| {
11084            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11085            let line_count_before = lines.len();
11086
11087            callback(&mut lines);
11088
11089            LineManipulationResult {
11090                new_text: lines.join("\n"),
11091                line_count_before,
11092                line_count_after: lines.len(),
11093            }
11094        });
11095    }
11096
11097    pub fn convert_indentation_to_spaces(
11098        &mut self,
11099        _: &ConvertIndentationToSpaces,
11100        window: &mut Window,
11101        cx: &mut Context<Self>,
11102    ) {
11103        let settings = self.buffer.read(cx).language_settings(cx);
11104        let tab_size = settings.tab_size.get() as usize;
11105
11106        self.manipulate_mutable_lines(window, cx, |lines| {
11107            // Allocates a reasonably sized scratch buffer once for the whole loop
11108            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11109            // Avoids recomputing spaces that could be inserted many times
11110            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11111                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11112                .collect();
11113
11114            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11115                let mut chars = line.as_ref().chars();
11116                let mut col = 0;
11117                let mut changed = false;
11118
11119                for ch in chars.by_ref() {
11120                    match ch {
11121                        ' ' => {
11122                            reindented_line.push(' ');
11123                            col += 1;
11124                        }
11125                        '\t' => {
11126                            // \t are converted to spaces depending on the current column
11127                            let spaces_len = tab_size - (col % tab_size);
11128                            reindented_line.extend(&space_cache[spaces_len - 1]);
11129                            col += spaces_len;
11130                            changed = true;
11131                        }
11132                        _ => {
11133                            // If we dont append before break, the character is consumed
11134                            reindented_line.push(ch);
11135                            break;
11136                        }
11137                    }
11138                }
11139
11140                if !changed {
11141                    reindented_line.clear();
11142                    continue;
11143                }
11144                // Append the rest of the line and replace old reference with new one
11145                reindented_line.extend(chars);
11146                *line = Cow::Owned(reindented_line.clone());
11147                reindented_line.clear();
11148            }
11149        });
11150    }
11151
11152    pub fn convert_indentation_to_tabs(
11153        &mut self,
11154        _: &ConvertIndentationToTabs,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157    ) {
11158        let settings = self.buffer.read(cx).language_settings(cx);
11159        let tab_size = settings.tab_size.get() as usize;
11160
11161        self.manipulate_mutable_lines(window, cx, |lines| {
11162            // Allocates a reasonably sized buffer once for the whole loop
11163            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11164            // Avoids recomputing spaces that could be inserted many times
11165            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11166                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11167                .collect();
11168
11169            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11170                let mut chars = line.chars();
11171                let mut spaces_count = 0;
11172                let mut first_non_indent_char = None;
11173                let mut changed = false;
11174
11175                for ch in chars.by_ref() {
11176                    match ch {
11177                        ' ' => {
11178                            // Keep track of spaces. Append \t when we reach tab_size
11179                            spaces_count += 1;
11180                            changed = true;
11181                            if spaces_count == tab_size {
11182                                reindented_line.push('\t');
11183                                spaces_count = 0;
11184                            }
11185                        }
11186                        '\t' => {
11187                            reindented_line.push('\t');
11188                            spaces_count = 0;
11189                        }
11190                        _ => {
11191                            // Dont append it yet, we might have remaining spaces
11192                            first_non_indent_char = Some(ch);
11193                            break;
11194                        }
11195                    }
11196                }
11197
11198                if !changed {
11199                    reindented_line.clear();
11200                    continue;
11201                }
11202                // Remaining spaces that didn't make a full tab stop
11203                if spaces_count > 0 {
11204                    reindented_line.extend(&space_cache[spaces_count - 1]);
11205                }
11206                // If we consume an extra character that was not indentation, add it back
11207                if let Some(extra_char) = first_non_indent_char {
11208                    reindented_line.push(extra_char);
11209                }
11210                // Append the rest of the line and replace old reference with new one
11211                reindented_line.extend(chars);
11212                *line = Cow::Owned(reindented_line.clone());
11213                reindented_line.clear();
11214            }
11215        });
11216    }
11217
11218    pub fn convert_to_upper_case(
11219        &mut self,
11220        _: &ConvertToUpperCase,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223    ) {
11224        self.manipulate_text(window, cx, |text| text.to_uppercase())
11225    }
11226
11227    pub fn convert_to_lower_case(
11228        &mut self,
11229        _: &ConvertToLowerCase,
11230        window: &mut Window,
11231        cx: &mut Context<Self>,
11232    ) {
11233        self.manipulate_text(window, cx, |text| text.to_lowercase())
11234    }
11235
11236    pub fn convert_to_title_case(
11237        &mut self,
11238        _: &ConvertToTitleCase,
11239        window: &mut Window,
11240        cx: &mut Context<Self>,
11241    ) {
11242        self.manipulate_text(window, cx, |text| {
11243            text.split('\n')
11244                .map(|line| line.to_case(Case::Title))
11245                .join("\n")
11246        })
11247    }
11248
11249    pub fn convert_to_snake_case(
11250        &mut self,
11251        _: &ConvertToSnakeCase,
11252        window: &mut Window,
11253        cx: &mut Context<Self>,
11254    ) {
11255        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11256    }
11257
11258    pub fn convert_to_kebab_case(
11259        &mut self,
11260        _: &ConvertToKebabCase,
11261        window: &mut Window,
11262        cx: &mut Context<Self>,
11263    ) {
11264        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11265    }
11266
11267    pub fn convert_to_upper_camel_case(
11268        &mut self,
11269        _: &ConvertToUpperCamelCase,
11270        window: &mut Window,
11271        cx: &mut Context<Self>,
11272    ) {
11273        self.manipulate_text(window, cx, |text| {
11274            text.split('\n')
11275                .map(|line| line.to_case(Case::UpperCamel))
11276                .join("\n")
11277        })
11278    }
11279
11280    pub fn convert_to_lower_camel_case(
11281        &mut self,
11282        _: &ConvertToLowerCamelCase,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11287    }
11288
11289    pub fn convert_to_opposite_case(
11290        &mut self,
11291        _: &ConvertToOppositeCase,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294    ) {
11295        self.manipulate_text(window, cx, |text| {
11296            text.chars()
11297                .fold(String::with_capacity(text.len()), |mut t, c| {
11298                    if c.is_uppercase() {
11299                        t.extend(c.to_lowercase());
11300                    } else {
11301                        t.extend(c.to_uppercase());
11302                    }
11303                    t
11304                })
11305        })
11306    }
11307
11308    pub fn convert_to_sentence_case(
11309        &mut self,
11310        _: &ConvertToSentenceCase,
11311        window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11315    }
11316
11317    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11318        self.manipulate_text(window, cx, |text| {
11319            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11320            if has_upper_case_characters {
11321                text.to_lowercase()
11322            } else {
11323                text.to_uppercase()
11324            }
11325        })
11326    }
11327
11328    pub fn convert_to_rot13(
11329        &mut self,
11330        _: &ConvertToRot13,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333    ) {
11334        self.manipulate_text(window, cx, |text| {
11335            text.chars()
11336                .map(|c| match c {
11337                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11338                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11339                    _ => c,
11340                })
11341                .collect()
11342        })
11343    }
11344
11345    pub fn convert_to_rot47(
11346        &mut self,
11347        _: &ConvertToRot47,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) {
11351        self.manipulate_text(window, cx, |text| {
11352            text.chars()
11353                .map(|c| {
11354                    let code_point = c as u32;
11355                    if code_point >= 33 && code_point <= 126 {
11356                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11357                    }
11358                    c
11359                })
11360                .collect()
11361        })
11362    }
11363
11364    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11365    where
11366        Fn: FnMut(&str) -> String,
11367    {
11368        let buffer = self.buffer.read(cx).snapshot(cx);
11369
11370        let mut new_selections = Vec::new();
11371        let mut edits = Vec::new();
11372        let mut selection_adjustment = 0i32;
11373
11374        for selection in self.selections.all::<usize>(cx) {
11375            let selection_is_empty = selection.is_empty();
11376
11377            let (start, end) = if selection_is_empty {
11378                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11379                (word_range.start, word_range.end)
11380            } else {
11381                (selection.start, selection.end)
11382            };
11383
11384            let text = buffer.text_for_range(start..end).collect::<String>();
11385            let old_length = text.len() as i32;
11386            let text = callback(&text);
11387
11388            new_selections.push(Selection {
11389                start: (start as i32 - selection_adjustment) as usize,
11390                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11391                goal: SelectionGoal::None,
11392                ..selection
11393            });
11394
11395            selection_adjustment += old_length - text.len() as i32;
11396
11397            edits.push((start..end, text));
11398        }
11399
11400        self.transact(window, cx, |this, window, cx| {
11401            this.buffer.update(cx, |buffer, cx| {
11402                buffer.edit(edits, None, cx);
11403            });
11404
11405            this.change_selections(Default::default(), window, cx, |s| {
11406                s.select(new_selections);
11407            });
11408
11409            this.request_autoscroll(Autoscroll::fit(), cx);
11410        });
11411    }
11412
11413    pub fn move_selection_on_drop(
11414        &mut self,
11415        selection: &Selection<Anchor>,
11416        target: DisplayPoint,
11417        is_cut: bool,
11418        window: &mut Window,
11419        cx: &mut Context<Self>,
11420    ) {
11421        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11422        let buffer = &display_map.buffer_snapshot;
11423        let mut edits = Vec::new();
11424        let insert_point = display_map
11425            .clip_point(target, Bias::Left)
11426            .to_point(&display_map);
11427        let text = buffer
11428            .text_for_range(selection.start..selection.end)
11429            .collect::<String>();
11430        if is_cut {
11431            edits.push(((selection.start..selection.end), String::new()));
11432        }
11433        let insert_anchor = buffer.anchor_before(insert_point);
11434        edits.push(((insert_anchor..insert_anchor), text));
11435        let last_edit_start = insert_anchor.bias_left(buffer);
11436        let last_edit_end = insert_anchor.bias_right(buffer);
11437        self.transact(window, cx, |this, window, cx| {
11438            this.buffer.update(cx, |buffer, cx| {
11439                buffer.edit(edits, None, cx);
11440            });
11441            this.change_selections(Default::default(), window, cx, |s| {
11442                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11443            });
11444        });
11445    }
11446
11447    pub fn clear_selection_drag_state(&mut self) {
11448        self.selection_drag_state = SelectionDragState::None;
11449    }
11450
11451    pub fn duplicate(
11452        &mut self,
11453        upwards: bool,
11454        whole_lines: bool,
11455        window: &mut Window,
11456        cx: &mut Context<Self>,
11457    ) {
11458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11459
11460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11461        let buffer = &display_map.buffer_snapshot;
11462        let selections = self.selections.all::<Point>(cx);
11463
11464        let mut edits = Vec::new();
11465        let mut selections_iter = selections.iter().peekable();
11466        while let Some(selection) = selections_iter.next() {
11467            let mut rows = selection.spanned_rows(false, &display_map);
11468            // duplicate line-wise
11469            if whole_lines || selection.start == selection.end {
11470                // Avoid duplicating the same lines twice.
11471                while let Some(next_selection) = selections_iter.peek() {
11472                    let next_rows = next_selection.spanned_rows(false, &display_map);
11473                    if next_rows.start < rows.end {
11474                        rows.end = next_rows.end;
11475                        selections_iter.next().unwrap();
11476                    } else {
11477                        break;
11478                    }
11479                }
11480
11481                // Copy the text from the selected row region and splice it either at the start
11482                // or end of the region.
11483                let start = Point::new(rows.start.0, 0);
11484                let end = Point::new(
11485                    rows.end.previous_row().0,
11486                    buffer.line_len(rows.end.previous_row()),
11487                );
11488                let text = buffer
11489                    .text_for_range(start..end)
11490                    .chain(Some("\n"))
11491                    .collect::<String>();
11492                let insert_location = if upwards {
11493                    Point::new(rows.end.0, 0)
11494                } else {
11495                    start
11496                };
11497                edits.push((insert_location..insert_location, text));
11498            } else {
11499                // duplicate character-wise
11500                let start = selection.start;
11501                let end = selection.end;
11502                let text = buffer.text_for_range(start..end).collect::<String>();
11503                edits.push((selection.end..selection.end, text));
11504            }
11505        }
11506
11507        self.transact(window, cx, |this, _, cx| {
11508            this.buffer.update(cx, |buffer, cx| {
11509                buffer.edit(edits, None, cx);
11510            });
11511
11512            this.request_autoscroll(Autoscroll::fit(), cx);
11513        });
11514    }
11515
11516    pub fn duplicate_line_up(
11517        &mut self,
11518        _: &DuplicateLineUp,
11519        window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        self.duplicate(true, true, window, cx);
11523    }
11524
11525    pub fn duplicate_line_down(
11526        &mut self,
11527        _: &DuplicateLineDown,
11528        window: &mut Window,
11529        cx: &mut Context<Self>,
11530    ) {
11531        self.duplicate(false, true, window, cx);
11532    }
11533
11534    pub fn duplicate_selection(
11535        &mut self,
11536        _: &DuplicateSelection,
11537        window: &mut Window,
11538        cx: &mut Context<Self>,
11539    ) {
11540        self.duplicate(false, false, window, cx);
11541    }
11542
11543    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11545        if self.mode.is_single_line() {
11546            cx.propagate();
11547            return;
11548        }
11549
11550        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11551        let buffer = self.buffer.read(cx).snapshot(cx);
11552
11553        let mut edits = Vec::new();
11554        let mut unfold_ranges = Vec::new();
11555        let mut refold_creases = Vec::new();
11556
11557        let selections = self.selections.all::<Point>(cx);
11558        let mut selections = selections.iter().peekable();
11559        let mut contiguous_row_selections = Vec::new();
11560        let mut new_selections = Vec::new();
11561
11562        while let Some(selection) = selections.next() {
11563            // Find all the selections that span a contiguous row range
11564            let (start_row, end_row) = consume_contiguous_rows(
11565                &mut contiguous_row_selections,
11566                selection,
11567                &display_map,
11568                &mut selections,
11569            );
11570
11571            // Move the text spanned by the row range to be before the line preceding the row range
11572            if start_row.0 > 0 {
11573                let range_to_move = Point::new(
11574                    start_row.previous_row().0,
11575                    buffer.line_len(start_row.previous_row()),
11576                )
11577                    ..Point::new(
11578                        end_row.previous_row().0,
11579                        buffer.line_len(end_row.previous_row()),
11580                    );
11581                let insertion_point = display_map
11582                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11583                    .0;
11584
11585                // Don't move lines across excerpts
11586                if buffer
11587                    .excerpt_containing(insertion_point..range_to_move.end)
11588                    .is_some()
11589                {
11590                    let text = buffer
11591                        .text_for_range(range_to_move.clone())
11592                        .flat_map(|s| s.chars())
11593                        .skip(1)
11594                        .chain(['\n'])
11595                        .collect::<String>();
11596
11597                    edits.push((
11598                        buffer.anchor_after(range_to_move.start)
11599                            ..buffer.anchor_before(range_to_move.end),
11600                        String::new(),
11601                    ));
11602                    let insertion_anchor = buffer.anchor_after(insertion_point);
11603                    edits.push((insertion_anchor..insertion_anchor, text));
11604
11605                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11606
11607                    // Move selections up
11608                    new_selections.extend(contiguous_row_selections.drain(..).map(
11609                        |mut selection| {
11610                            selection.start.row -= row_delta;
11611                            selection.end.row -= row_delta;
11612                            selection
11613                        },
11614                    ));
11615
11616                    // Move folds up
11617                    unfold_ranges.push(range_to_move.clone());
11618                    for fold in display_map.folds_in_range(
11619                        buffer.anchor_before(range_to_move.start)
11620                            ..buffer.anchor_after(range_to_move.end),
11621                    ) {
11622                        let mut start = fold.range.start.to_point(&buffer);
11623                        let mut end = fold.range.end.to_point(&buffer);
11624                        start.row -= row_delta;
11625                        end.row -= row_delta;
11626                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11627                    }
11628                }
11629            }
11630
11631            // If we didn't move line(s), preserve the existing selections
11632            new_selections.append(&mut contiguous_row_selections);
11633        }
11634
11635        self.transact(window, cx, |this, window, cx| {
11636            this.unfold_ranges(&unfold_ranges, true, true, cx);
11637            this.buffer.update(cx, |buffer, cx| {
11638                for (range, text) in edits {
11639                    buffer.edit([(range, text)], None, cx);
11640                }
11641            });
11642            this.fold_creases(refold_creases, true, window, cx);
11643            this.change_selections(Default::default(), window, cx, |s| {
11644                s.select(new_selections);
11645            })
11646        });
11647    }
11648
11649    pub fn move_line_down(
11650        &mut self,
11651        _: &MoveLineDown,
11652        window: &mut Window,
11653        cx: &mut Context<Self>,
11654    ) {
11655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11656        if self.mode.is_single_line() {
11657            cx.propagate();
11658            return;
11659        }
11660
11661        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11662        let buffer = self.buffer.read(cx).snapshot(cx);
11663
11664        let mut edits = Vec::new();
11665        let mut unfold_ranges = Vec::new();
11666        let mut refold_creases = Vec::new();
11667
11668        let selections = self.selections.all::<Point>(cx);
11669        let mut selections = selections.iter().peekable();
11670        let mut contiguous_row_selections = Vec::new();
11671        let mut new_selections = Vec::new();
11672
11673        while let Some(selection) = selections.next() {
11674            // Find all the selections that span a contiguous row range
11675            let (start_row, end_row) = consume_contiguous_rows(
11676                &mut contiguous_row_selections,
11677                selection,
11678                &display_map,
11679                &mut selections,
11680            );
11681
11682            // Move the text spanned by the row range to be after the last line of the row range
11683            if end_row.0 <= buffer.max_point().row {
11684                let range_to_move =
11685                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11686                let insertion_point = display_map
11687                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11688                    .0;
11689
11690                // Don't move lines across excerpt boundaries
11691                if buffer
11692                    .excerpt_containing(range_to_move.start..insertion_point)
11693                    .is_some()
11694                {
11695                    let mut text = String::from("\n");
11696                    text.extend(buffer.text_for_range(range_to_move.clone()));
11697                    text.pop(); // Drop trailing newline
11698                    edits.push((
11699                        buffer.anchor_after(range_to_move.start)
11700                            ..buffer.anchor_before(range_to_move.end),
11701                        String::new(),
11702                    ));
11703                    let insertion_anchor = buffer.anchor_after(insertion_point);
11704                    edits.push((insertion_anchor..insertion_anchor, text));
11705
11706                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11707
11708                    // Move selections down
11709                    new_selections.extend(contiguous_row_selections.drain(..).map(
11710                        |mut selection| {
11711                            selection.start.row += row_delta;
11712                            selection.end.row += row_delta;
11713                            selection
11714                        },
11715                    ));
11716
11717                    // Move folds down
11718                    unfold_ranges.push(range_to_move.clone());
11719                    for fold in display_map.folds_in_range(
11720                        buffer.anchor_before(range_to_move.start)
11721                            ..buffer.anchor_after(range_to_move.end),
11722                    ) {
11723                        let mut start = fold.range.start.to_point(&buffer);
11724                        let mut end = fold.range.end.to_point(&buffer);
11725                        start.row += row_delta;
11726                        end.row += row_delta;
11727                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11728                    }
11729                }
11730            }
11731
11732            // If we didn't move line(s), preserve the existing selections
11733            new_selections.append(&mut contiguous_row_selections);
11734        }
11735
11736        self.transact(window, cx, |this, window, cx| {
11737            this.unfold_ranges(&unfold_ranges, true, true, cx);
11738            this.buffer.update(cx, |buffer, cx| {
11739                for (range, text) in edits {
11740                    buffer.edit([(range, text)], None, cx);
11741                }
11742            });
11743            this.fold_creases(refold_creases, true, window, cx);
11744            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11745        });
11746    }
11747
11748    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11750        let text_layout_details = &self.text_layout_details(window);
11751        self.transact(window, cx, |this, window, cx| {
11752            let edits = this.change_selections(Default::default(), window, cx, |s| {
11753                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11754                s.move_with(|display_map, selection| {
11755                    if !selection.is_empty() {
11756                        return;
11757                    }
11758
11759                    let mut head = selection.head();
11760                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11761                    if head.column() == display_map.line_len(head.row()) {
11762                        transpose_offset = display_map
11763                            .buffer_snapshot
11764                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11765                    }
11766
11767                    if transpose_offset == 0 {
11768                        return;
11769                    }
11770
11771                    *head.column_mut() += 1;
11772                    head = display_map.clip_point(head, Bias::Right);
11773                    let goal = SelectionGoal::HorizontalPosition(
11774                        display_map
11775                            .x_for_display_point(head, text_layout_details)
11776                            .into(),
11777                    );
11778                    selection.collapse_to(head, goal);
11779
11780                    let transpose_start = display_map
11781                        .buffer_snapshot
11782                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11783                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11784                        let transpose_end = display_map
11785                            .buffer_snapshot
11786                            .clip_offset(transpose_offset + 1, Bias::Right);
11787                        if let Some(ch) =
11788                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11789                        {
11790                            edits.push((transpose_start..transpose_offset, String::new()));
11791                            edits.push((transpose_end..transpose_end, ch.to_string()));
11792                        }
11793                    }
11794                });
11795                edits
11796            });
11797            this.buffer
11798                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11799            let selections = this.selections.all::<usize>(cx);
11800            this.change_selections(Default::default(), window, cx, |s| {
11801                s.select(selections);
11802            });
11803        });
11804    }
11805
11806    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11807        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11808        if self.mode.is_single_line() {
11809            cx.propagate();
11810            return;
11811        }
11812
11813        self.rewrap_impl(RewrapOptions::default(), cx)
11814    }
11815
11816    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11817        let buffer = self.buffer.read(cx).snapshot(cx);
11818        let selections = self.selections.all::<Point>(cx);
11819
11820        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11821        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11822            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11823                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11824                .peekable();
11825
11826            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11827                row
11828            } else {
11829                return Vec::new();
11830            };
11831
11832            let language_settings = buffer.language_settings_at(selection.head(), cx);
11833            let language_scope = buffer.language_scope_at(selection.head());
11834
11835            let indent_and_prefix_for_row =
11836                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11837                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11838                    let (comment_prefix, rewrap_prefix) =
11839                        if let Some(language_scope) = &language_scope {
11840                            let indent_end = Point::new(row, indent.len);
11841                            let comment_prefix = language_scope
11842                                .line_comment_prefixes()
11843                                .iter()
11844                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11845                                .map(|prefix| prefix.to_string());
11846                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11847                            let line_text_after_indent = buffer
11848                                .text_for_range(indent_end..line_end)
11849                                .collect::<String>();
11850                            let rewrap_prefix = language_scope
11851                                .rewrap_prefixes()
11852                                .iter()
11853                                .find_map(|prefix_regex| {
11854                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11855                                        if mat.start() == 0 {
11856                                            Some(mat.as_str().to_string())
11857                                        } else {
11858                                            None
11859                                        }
11860                                    })
11861                                })
11862                                .flatten();
11863                            (comment_prefix, rewrap_prefix)
11864                        } else {
11865                            (None, None)
11866                        };
11867                    (indent, comment_prefix, rewrap_prefix)
11868                };
11869
11870            let mut ranges = Vec::new();
11871            let from_empty_selection = selection.is_empty();
11872
11873            let mut current_range_start = first_row;
11874            let mut prev_row = first_row;
11875            let (
11876                mut current_range_indent,
11877                mut current_range_comment_prefix,
11878                mut current_range_rewrap_prefix,
11879            ) = indent_and_prefix_for_row(first_row);
11880
11881            for row in non_blank_rows_iter.skip(1) {
11882                let has_paragraph_break = row > prev_row + 1;
11883
11884                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11885                    indent_and_prefix_for_row(row);
11886
11887                let has_indent_change = row_indent != current_range_indent;
11888                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11889
11890                let has_boundary_change = has_comment_change
11891                    || row_rewrap_prefix.is_some()
11892                    || (has_indent_change && current_range_comment_prefix.is_some());
11893
11894                if has_paragraph_break || has_boundary_change {
11895                    ranges.push((
11896                        language_settings.clone(),
11897                        Point::new(current_range_start, 0)
11898                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11899                        current_range_indent,
11900                        current_range_comment_prefix.clone(),
11901                        current_range_rewrap_prefix.clone(),
11902                        from_empty_selection,
11903                    ));
11904                    current_range_start = row;
11905                    current_range_indent = row_indent;
11906                    current_range_comment_prefix = row_comment_prefix;
11907                    current_range_rewrap_prefix = row_rewrap_prefix;
11908                }
11909                prev_row = row;
11910            }
11911
11912            ranges.push((
11913                language_settings.clone(),
11914                Point::new(current_range_start, 0)
11915                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11916                current_range_indent,
11917                current_range_comment_prefix,
11918                current_range_rewrap_prefix,
11919                from_empty_selection,
11920            ));
11921
11922            ranges
11923        });
11924
11925        let mut edits = Vec::new();
11926        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11927
11928        for (
11929            language_settings,
11930            wrap_range,
11931            indent_size,
11932            comment_prefix,
11933            rewrap_prefix,
11934            from_empty_selection,
11935        ) in wrap_ranges
11936        {
11937            let mut start_row = wrap_range.start.row;
11938            let mut end_row = wrap_range.end.row;
11939
11940            // Skip selections that overlap with a range that has already been rewrapped.
11941            let selection_range = start_row..end_row;
11942            if rewrapped_row_ranges
11943                .iter()
11944                .any(|range| range.overlaps(&selection_range))
11945            {
11946                continue;
11947            }
11948
11949            let tab_size = language_settings.tab_size;
11950
11951            let indent_prefix = indent_size.chars().collect::<String>();
11952            let mut line_prefix = indent_prefix.clone();
11953            let mut inside_comment = false;
11954            if let Some(prefix) = &comment_prefix {
11955                line_prefix.push_str(prefix);
11956                inside_comment = true;
11957            }
11958            if let Some(prefix) = &rewrap_prefix {
11959                line_prefix.push_str(prefix);
11960            }
11961
11962            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11963                RewrapBehavior::InComments => inside_comment,
11964                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11965                RewrapBehavior::Anywhere => true,
11966            };
11967
11968            let should_rewrap = options.override_language_settings
11969                || allow_rewrap_based_on_language
11970                || self.hard_wrap.is_some();
11971            if !should_rewrap {
11972                continue;
11973            }
11974
11975            if from_empty_selection {
11976                'expand_upwards: while start_row > 0 {
11977                    let prev_row = start_row - 1;
11978                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11979                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11980                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11981                    {
11982                        start_row = prev_row;
11983                    } else {
11984                        break 'expand_upwards;
11985                    }
11986                }
11987
11988                'expand_downwards: while end_row < buffer.max_point().row {
11989                    let next_row = end_row + 1;
11990                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11991                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11992                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11993                    {
11994                        end_row = next_row;
11995                    } else {
11996                        break 'expand_downwards;
11997                    }
11998                }
11999            }
12000
12001            let start = Point::new(start_row, 0);
12002            let start_offset = start.to_offset(&buffer);
12003            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12004            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12005            let Some(lines_without_prefixes) = selection_text
12006                .lines()
12007                .enumerate()
12008                .map(|(ix, line)| {
12009                    let line_trimmed = line.trim_start();
12010                    if rewrap_prefix.is_some() && ix > 0 {
12011                        Ok(line_trimmed)
12012                    } else {
12013                        line_trimmed
12014                            .strip_prefix(&line_prefix.trim_start())
12015                            .with_context(|| {
12016                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12017                            })
12018                    }
12019                })
12020                .collect::<Result<Vec<_>, _>>()
12021                .log_err()
12022            else {
12023                continue;
12024            };
12025
12026            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12027                buffer
12028                    .language_settings_at(Point::new(start_row, 0), cx)
12029                    .preferred_line_length as usize
12030            });
12031
12032            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12033                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12034            } else {
12035                line_prefix.clone()
12036            };
12037
12038            let wrapped_text = wrap_with_prefix(
12039                line_prefix,
12040                subsequent_lines_prefix,
12041                lines_without_prefixes.join("\n"),
12042                wrap_column,
12043                tab_size,
12044                options.preserve_existing_whitespace,
12045            );
12046
12047            // TODO: should always use char-based diff while still supporting cursor behavior that
12048            // matches vim.
12049            let mut diff_options = DiffOptions::default();
12050            if options.override_language_settings {
12051                diff_options.max_word_diff_len = 0;
12052                diff_options.max_word_diff_line_count = 0;
12053            } else {
12054                diff_options.max_word_diff_len = usize::MAX;
12055                diff_options.max_word_diff_line_count = usize::MAX;
12056            }
12057
12058            for (old_range, new_text) in
12059                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12060            {
12061                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12062                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12063                edits.push((edit_start..edit_end, new_text));
12064            }
12065
12066            rewrapped_row_ranges.push(start_row..=end_row);
12067        }
12068
12069        self.buffer
12070            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12071    }
12072
12073    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12074        let mut text = String::new();
12075        let buffer = self.buffer.read(cx).snapshot(cx);
12076        let mut selections = self.selections.all::<Point>(cx);
12077        let mut clipboard_selections = Vec::with_capacity(selections.len());
12078        {
12079            let max_point = buffer.max_point();
12080            let mut is_first = true;
12081            for selection in &mut selections {
12082                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12083                if is_entire_line {
12084                    selection.start = Point::new(selection.start.row, 0);
12085                    if !selection.is_empty() && selection.end.column == 0 {
12086                        selection.end = cmp::min(max_point, selection.end);
12087                    } else {
12088                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12089                    }
12090                    selection.goal = SelectionGoal::None;
12091                }
12092                if is_first {
12093                    is_first = false;
12094                } else {
12095                    text += "\n";
12096                }
12097                let mut len = 0;
12098                for chunk in buffer.text_for_range(selection.start..selection.end) {
12099                    text.push_str(chunk);
12100                    len += chunk.len();
12101                }
12102                clipboard_selections.push(ClipboardSelection {
12103                    len,
12104                    is_entire_line,
12105                    first_line_indent: buffer
12106                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12107                        .len,
12108                });
12109            }
12110        }
12111
12112        self.transact(window, cx, |this, window, cx| {
12113            this.change_selections(Default::default(), window, cx, |s| {
12114                s.select(selections);
12115            });
12116            this.insert("", window, cx);
12117        });
12118        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12119    }
12120
12121    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12123        let item = self.cut_common(window, cx);
12124        cx.write_to_clipboard(item);
12125    }
12126
12127    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12129        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12130            s.move_with(|snapshot, sel| {
12131                if sel.is_empty() {
12132                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12133                }
12134            });
12135        });
12136        let item = self.cut_common(window, cx);
12137        cx.set_global(KillRing(item))
12138    }
12139
12140    pub fn kill_ring_yank(
12141        &mut self,
12142        _: &KillRingYank,
12143        window: &mut Window,
12144        cx: &mut Context<Self>,
12145    ) {
12146        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12147        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12148            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12149                (kill_ring.text().to_string(), kill_ring.metadata_json())
12150            } else {
12151                return;
12152            }
12153        } else {
12154            return;
12155        };
12156        self.do_paste(&text, metadata, false, window, cx);
12157    }
12158
12159    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12160        self.do_copy(true, cx);
12161    }
12162
12163    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12164        self.do_copy(false, cx);
12165    }
12166
12167    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12168        let selections = self.selections.all::<Point>(cx);
12169        let buffer = self.buffer.read(cx).read(cx);
12170        let mut text = String::new();
12171
12172        let mut clipboard_selections = Vec::with_capacity(selections.len());
12173        {
12174            let max_point = buffer.max_point();
12175            let mut is_first = true;
12176            for selection in &selections {
12177                let mut start = selection.start;
12178                let mut end = selection.end;
12179                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12180                if is_entire_line {
12181                    start = Point::new(start.row, 0);
12182                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12183                }
12184
12185                let mut trimmed_selections = Vec::new();
12186                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12187                    let row = MultiBufferRow(start.row);
12188                    let first_indent = buffer.indent_size_for_line(row);
12189                    if first_indent.len == 0 || start.column > first_indent.len {
12190                        trimmed_selections.push(start..end);
12191                    } else {
12192                        trimmed_selections.push(
12193                            Point::new(row.0, first_indent.len)
12194                                ..Point::new(row.0, buffer.line_len(row)),
12195                        );
12196                        for row in start.row + 1..=end.row {
12197                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12198                            if row == end.row {
12199                                line_len = end.column;
12200                            }
12201                            if line_len == 0 {
12202                                trimmed_selections
12203                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12204                                continue;
12205                            }
12206                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12207                            if row_indent_size.len >= first_indent.len {
12208                                trimmed_selections.push(
12209                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12210                                );
12211                            } else {
12212                                trimmed_selections.clear();
12213                                trimmed_selections.push(start..end);
12214                                break;
12215                            }
12216                        }
12217                    }
12218                } else {
12219                    trimmed_selections.push(start..end);
12220                }
12221
12222                for trimmed_range in trimmed_selections {
12223                    if is_first {
12224                        is_first = false;
12225                    } else {
12226                        text += "\n";
12227                    }
12228                    let mut len = 0;
12229                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12230                        text.push_str(chunk);
12231                        len += chunk.len();
12232                    }
12233                    clipboard_selections.push(ClipboardSelection {
12234                        len,
12235                        is_entire_line,
12236                        first_line_indent: buffer
12237                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12238                            .len,
12239                    });
12240                }
12241            }
12242        }
12243
12244        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12245            text,
12246            clipboard_selections,
12247        ));
12248    }
12249
12250    pub fn do_paste(
12251        &mut self,
12252        text: &String,
12253        clipboard_selections: Option<Vec<ClipboardSelection>>,
12254        handle_entire_lines: bool,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        if self.read_only(cx) {
12259            return;
12260        }
12261
12262        let clipboard_text = Cow::Borrowed(text);
12263
12264        self.transact(window, cx, |this, window, cx| {
12265            let had_active_edit_prediction = this.has_active_edit_prediction();
12266
12267            if let Some(mut clipboard_selections) = clipboard_selections {
12268                let old_selections = this.selections.all::<usize>(cx);
12269                let all_selections_were_entire_line =
12270                    clipboard_selections.iter().all(|s| s.is_entire_line);
12271                let first_selection_indent_column =
12272                    clipboard_selections.first().map(|s| s.first_line_indent);
12273                if clipboard_selections.len() != old_selections.len() {
12274                    clipboard_selections.drain(..);
12275                }
12276                let cursor_offset = this.selections.last::<usize>(cx).head();
12277                let mut auto_indent_on_paste = true;
12278
12279                this.buffer.update(cx, |buffer, cx| {
12280                    let snapshot = buffer.read(cx);
12281                    auto_indent_on_paste = snapshot
12282                        .language_settings_at(cursor_offset, cx)
12283                        .auto_indent_on_paste;
12284
12285                    let mut start_offset = 0;
12286                    let mut edits = Vec::new();
12287                    let mut original_indent_columns = Vec::new();
12288                    for (ix, selection) in old_selections.iter().enumerate() {
12289                        let to_insert;
12290                        let entire_line;
12291                        let original_indent_column;
12292                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12293                            let end_offset = start_offset + clipboard_selection.len;
12294                            to_insert = &clipboard_text[start_offset..end_offset];
12295                            entire_line = clipboard_selection.is_entire_line;
12296                            start_offset = end_offset + 1;
12297                            original_indent_column = Some(clipboard_selection.first_line_indent);
12298                        } else {
12299                            to_insert = clipboard_text.as_str();
12300                            entire_line = all_selections_were_entire_line;
12301                            original_indent_column = first_selection_indent_column
12302                        }
12303
12304                        // If the corresponding selection was empty when this slice of the
12305                        // clipboard text was written, then the entire line containing the
12306                        // selection was copied. If this selection is also currently empty,
12307                        // then paste the line before the current line of the buffer.
12308                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12309                            let column = selection.start.to_point(&snapshot).column as usize;
12310                            let line_start = selection.start - column;
12311                            line_start..line_start
12312                        } else {
12313                            selection.range()
12314                        };
12315
12316                        edits.push((range, to_insert));
12317                        original_indent_columns.push(original_indent_column);
12318                    }
12319                    drop(snapshot);
12320
12321                    buffer.edit(
12322                        edits,
12323                        if auto_indent_on_paste {
12324                            Some(AutoindentMode::Block {
12325                                original_indent_columns,
12326                            })
12327                        } else {
12328                            None
12329                        },
12330                        cx,
12331                    );
12332                });
12333
12334                let selections = this.selections.all::<usize>(cx);
12335                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12336            } else {
12337                this.insert(&clipboard_text, window, cx);
12338            }
12339
12340            let trigger_in_words =
12341                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12342
12343            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12344        });
12345    }
12346
12347    pub fn diff_clipboard_with_selection(
12348        &mut self,
12349        _: &DiffClipboardWithSelection,
12350        window: &mut Window,
12351        cx: &mut Context<Self>,
12352    ) {
12353        let selections = self.selections.all::<usize>(cx);
12354
12355        if selections.is_empty() {
12356            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12357            return;
12358        };
12359
12360        let clipboard_text = match cx.read_from_clipboard() {
12361            Some(item) => match item.entries().first() {
12362                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12363                _ => None,
12364            },
12365            None => None,
12366        };
12367
12368        let Some(clipboard_text) = clipboard_text else {
12369            log::warn!("Clipboard doesn't contain text.");
12370            return;
12371        };
12372
12373        window.dispatch_action(
12374            Box::new(DiffClipboardWithSelectionData {
12375                clipboard_text,
12376                editor: cx.entity(),
12377            }),
12378            cx,
12379        );
12380    }
12381
12382    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12384        if let Some(item) = cx.read_from_clipboard() {
12385            let entries = item.entries();
12386
12387            match entries.first() {
12388                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12389                // of all the pasted entries.
12390                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12391                    .do_paste(
12392                        clipboard_string.text(),
12393                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12394                        true,
12395                        window,
12396                        cx,
12397                    ),
12398                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12399            }
12400        }
12401    }
12402
12403    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12404        if self.read_only(cx) {
12405            return;
12406        }
12407
12408        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12409
12410        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12411            if let Some((selections, _)) =
12412                self.selection_history.transaction(transaction_id).cloned()
12413            {
12414                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12415                    s.select_anchors(selections.to_vec());
12416                });
12417            } else {
12418                log::error!(
12419                    "No entry in selection_history found for undo. \
12420                     This may correspond to a bug where undo does not update the selection. \
12421                     If this is occurring, please add details to \
12422                     https://github.com/zed-industries/zed/issues/22692"
12423                );
12424            }
12425            self.request_autoscroll(Autoscroll::fit(), cx);
12426            self.unmark_text(window, cx);
12427            self.refresh_edit_prediction(true, false, window, cx);
12428            cx.emit(EditorEvent::Edited { transaction_id });
12429            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12430        }
12431    }
12432
12433    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12434        if self.read_only(cx) {
12435            return;
12436        }
12437
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12439
12440        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12441            if let Some((_, Some(selections))) =
12442                self.selection_history.transaction(transaction_id).cloned()
12443            {
12444                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12445                    s.select_anchors(selections.to_vec());
12446                });
12447            } else {
12448                log::error!(
12449                    "No entry in selection_history found for redo. \
12450                     This may correspond to a bug where undo does not update the selection. \
12451                     If this is occurring, please add details to \
12452                     https://github.com/zed-industries/zed/issues/22692"
12453                );
12454            }
12455            self.request_autoscroll(Autoscroll::fit(), cx);
12456            self.unmark_text(window, cx);
12457            self.refresh_edit_prediction(true, false, window, cx);
12458            cx.emit(EditorEvent::Edited { transaction_id });
12459        }
12460    }
12461
12462    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12463        self.buffer
12464            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12465    }
12466
12467    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12468        self.buffer
12469            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12470    }
12471
12472    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12474        self.change_selections(Default::default(), window, cx, |s| {
12475            s.move_with(|map, selection| {
12476                let cursor = if selection.is_empty() {
12477                    movement::left(map, selection.start)
12478                } else {
12479                    selection.start
12480                };
12481                selection.collapse_to(cursor, SelectionGoal::None);
12482            });
12483        })
12484    }
12485
12486    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12488        self.change_selections(Default::default(), window, cx, |s| {
12489            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12490        })
12491    }
12492
12493    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12494        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12495        self.change_selections(Default::default(), window, cx, |s| {
12496            s.move_with(|map, selection| {
12497                let cursor = if selection.is_empty() {
12498                    movement::right(map, selection.end)
12499                } else {
12500                    selection.end
12501                };
12502                selection.collapse_to(cursor, SelectionGoal::None)
12503            });
12504        })
12505    }
12506
12507    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12509        self.change_selections(Default::default(), window, cx, |s| {
12510            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12511        })
12512    }
12513
12514    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12515        if self.take_rename(true, window, cx).is_some() {
12516            return;
12517        }
12518
12519        if self.mode.is_single_line() {
12520            cx.propagate();
12521            return;
12522        }
12523
12524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12525
12526        let text_layout_details = &self.text_layout_details(window);
12527        let selection_count = self.selections.count();
12528        let first_selection = self.selections.first_anchor();
12529
12530        self.change_selections(Default::default(), window, cx, |s| {
12531            s.move_with(|map, selection| {
12532                if !selection.is_empty() {
12533                    selection.goal = SelectionGoal::None;
12534                }
12535                let (cursor, goal) = movement::up(
12536                    map,
12537                    selection.start,
12538                    selection.goal,
12539                    false,
12540                    text_layout_details,
12541                );
12542                selection.collapse_to(cursor, goal);
12543            });
12544        });
12545
12546        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12547        {
12548            cx.propagate();
12549        }
12550    }
12551
12552    pub fn move_up_by_lines(
12553        &mut self,
12554        action: &MoveUpByLines,
12555        window: &mut Window,
12556        cx: &mut Context<Self>,
12557    ) {
12558        if self.take_rename(true, window, cx).is_some() {
12559            return;
12560        }
12561
12562        if self.mode.is_single_line() {
12563            cx.propagate();
12564            return;
12565        }
12566
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12568
12569        let text_layout_details = &self.text_layout_details(window);
12570
12571        self.change_selections(Default::default(), window, cx, |s| {
12572            s.move_with(|map, selection| {
12573                if !selection.is_empty() {
12574                    selection.goal = SelectionGoal::None;
12575                }
12576                let (cursor, goal) = movement::up_by_rows(
12577                    map,
12578                    selection.start,
12579                    action.lines,
12580                    selection.goal,
12581                    false,
12582                    text_layout_details,
12583                );
12584                selection.collapse_to(cursor, goal);
12585            });
12586        })
12587    }
12588
12589    pub fn move_down_by_lines(
12590        &mut self,
12591        action: &MoveDownByLines,
12592        window: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) {
12595        if self.take_rename(true, window, cx).is_some() {
12596            return;
12597        }
12598
12599        if self.mode.is_single_line() {
12600            cx.propagate();
12601            return;
12602        }
12603
12604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12605
12606        let text_layout_details = &self.text_layout_details(window);
12607
12608        self.change_selections(Default::default(), window, cx, |s| {
12609            s.move_with(|map, selection| {
12610                if !selection.is_empty() {
12611                    selection.goal = SelectionGoal::None;
12612                }
12613                let (cursor, goal) = movement::down_by_rows(
12614                    map,
12615                    selection.start,
12616                    action.lines,
12617                    selection.goal,
12618                    false,
12619                    text_layout_details,
12620                );
12621                selection.collapse_to(cursor, goal);
12622            });
12623        })
12624    }
12625
12626    pub fn select_down_by_lines(
12627        &mut self,
12628        action: &SelectDownByLines,
12629        window: &mut Window,
12630        cx: &mut Context<Self>,
12631    ) {
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12633        let text_layout_details = &self.text_layout_details(window);
12634        self.change_selections(Default::default(), window, cx, |s| {
12635            s.move_heads_with(|map, head, goal| {
12636                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12637            })
12638        })
12639    }
12640
12641    pub fn select_up_by_lines(
12642        &mut self,
12643        action: &SelectUpByLines,
12644        window: &mut Window,
12645        cx: &mut Context<Self>,
12646    ) {
12647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12648        let text_layout_details = &self.text_layout_details(window);
12649        self.change_selections(Default::default(), window, cx, |s| {
12650            s.move_heads_with(|map, head, goal| {
12651                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12652            })
12653        })
12654    }
12655
12656    pub fn select_page_up(
12657        &mut self,
12658        _: &SelectPageUp,
12659        window: &mut Window,
12660        cx: &mut Context<Self>,
12661    ) {
12662        let Some(row_count) = self.visible_row_count() else {
12663            return;
12664        };
12665
12666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12667
12668        let text_layout_details = &self.text_layout_details(window);
12669
12670        self.change_selections(Default::default(), window, cx, |s| {
12671            s.move_heads_with(|map, head, goal| {
12672                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12673            })
12674        })
12675    }
12676
12677    pub fn move_page_up(
12678        &mut self,
12679        action: &MovePageUp,
12680        window: &mut Window,
12681        cx: &mut Context<Self>,
12682    ) {
12683        if self.take_rename(true, window, cx).is_some() {
12684            return;
12685        }
12686
12687        if self
12688            .context_menu
12689            .borrow_mut()
12690            .as_mut()
12691            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12692            .unwrap_or(false)
12693        {
12694            return;
12695        }
12696
12697        if matches!(self.mode, EditorMode::SingleLine) {
12698            cx.propagate();
12699            return;
12700        }
12701
12702        let Some(row_count) = self.visible_row_count() else {
12703            return;
12704        };
12705
12706        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12707
12708        let effects = if action.center_cursor {
12709            SelectionEffects::scroll(Autoscroll::center())
12710        } else {
12711            SelectionEffects::default()
12712        };
12713
12714        let text_layout_details = &self.text_layout_details(window);
12715
12716        self.change_selections(effects, window, cx, |s| {
12717            s.move_with(|map, selection| {
12718                if !selection.is_empty() {
12719                    selection.goal = SelectionGoal::None;
12720                }
12721                let (cursor, goal) = movement::up_by_rows(
12722                    map,
12723                    selection.end,
12724                    row_count,
12725                    selection.goal,
12726                    false,
12727                    text_layout_details,
12728                );
12729                selection.collapse_to(cursor, goal);
12730            });
12731        });
12732    }
12733
12734    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12736        let text_layout_details = &self.text_layout_details(window);
12737        self.change_selections(Default::default(), window, cx, |s| {
12738            s.move_heads_with(|map, head, goal| {
12739                movement::up(map, head, goal, false, text_layout_details)
12740            })
12741        })
12742    }
12743
12744    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12745        self.take_rename(true, window, cx);
12746
12747        if self.mode.is_single_line() {
12748            cx.propagate();
12749            return;
12750        }
12751
12752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12753
12754        let text_layout_details = &self.text_layout_details(window);
12755        let selection_count = self.selections.count();
12756        let first_selection = self.selections.first_anchor();
12757
12758        self.change_selections(Default::default(), window, cx, |s| {
12759            s.move_with(|map, selection| {
12760                if !selection.is_empty() {
12761                    selection.goal = SelectionGoal::None;
12762                }
12763                let (cursor, goal) = movement::down(
12764                    map,
12765                    selection.end,
12766                    selection.goal,
12767                    false,
12768                    text_layout_details,
12769                );
12770                selection.collapse_to(cursor, goal);
12771            });
12772        });
12773
12774        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12775        {
12776            cx.propagate();
12777        }
12778    }
12779
12780    pub fn select_page_down(
12781        &mut self,
12782        _: &SelectPageDown,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        let Some(row_count) = self.visible_row_count() else {
12787            return;
12788        };
12789
12790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12791
12792        let text_layout_details = &self.text_layout_details(window);
12793
12794        self.change_selections(Default::default(), window, cx, |s| {
12795            s.move_heads_with(|map, head, goal| {
12796                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12797            })
12798        })
12799    }
12800
12801    pub fn move_page_down(
12802        &mut self,
12803        action: &MovePageDown,
12804        window: &mut Window,
12805        cx: &mut Context<Self>,
12806    ) {
12807        if self.take_rename(true, window, cx).is_some() {
12808            return;
12809        }
12810
12811        if self
12812            .context_menu
12813            .borrow_mut()
12814            .as_mut()
12815            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12816            .unwrap_or(false)
12817        {
12818            return;
12819        }
12820
12821        if matches!(self.mode, EditorMode::SingleLine) {
12822            cx.propagate();
12823            return;
12824        }
12825
12826        let Some(row_count) = self.visible_row_count() else {
12827            return;
12828        };
12829
12830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12831
12832        let effects = if action.center_cursor {
12833            SelectionEffects::scroll(Autoscroll::center())
12834        } else {
12835            SelectionEffects::default()
12836        };
12837
12838        let text_layout_details = &self.text_layout_details(window);
12839        self.change_selections(effects, window, cx, |s| {
12840            s.move_with(|map, selection| {
12841                if !selection.is_empty() {
12842                    selection.goal = SelectionGoal::None;
12843                }
12844                let (cursor, goal) = movement::down_by_rows(
12845                    map,
12846                    selection.end,
12847                    row_count,
12848                    selection.goal,
12849                    false,
12850                    text_layout_details,
12851                );
12852                selection.collapse_to(cursor, goal);
12853            });
12854        });
12855    }
12856
12857    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12859        let text_layout_details = &self.text_layout_details(window);
12860        self.change_selections(Default::default(), window, cx, |s| {
12861            s.move_heads_with(|map, head, goal| {
12862                movement::down(map, head, goal, false, text_layout_details)
12863            })
12864        });
12865    }
12866
12867    pub fn context_menu_first(
12868        &mut self,
12869        _: &ContextMenuFirst,
12870        window: &mut Window,
12871        cx: &mut Context<Self>,
12872    ) {
12873        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12874            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12875        }
12876    }
12877
12878    pub fn context_menu_prev(
12879        &mut self,
12880        _: &ContextMenuPrevious,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12885            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12886        }
12887    }
12888
12889    pub fn context_menu_next(
12890        &mut self,
12891        _: &ContextMenuNext,
12892        window: &mut Window,
12893        cx: &mut Context<Self>,
12894    ) {
12895        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12896            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12897        }
12898    }
12899
12900    pub fn context_menu_last(
12901        &mut self,
12902        _: &ContextMenuLast,
12903        window: &mut Window,
12904        cx: &mut Context<Self>,
12905    ) {
12906        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12907            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12908        }
12909    }
12910
12911    pub fn signature_help_prev(
12912        &mut self,
12913        _: &SignatureHelpPrevious,
12914        _: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) {
12917        if let Some(popover) = self.signature_help_state.popover_mut() {
12918            if popover.current_signature == 0 {
12919                popover.current_signature = popover.signatures.len() - 1;
12920            } else {
12921                popover.current_signature -= 1;
12922            }
12923            cx.notify();
12924        }
12925    }
12926
12927    pub fn signature_help_next(
12928        &mut self,
12929        _: &SignatureHelpNext,
12930        _: &mut Window,
12931        cx: &mut Context<Self>,
12932    ) {
12933        if let Some(popover) = self.signature_help_state.popover_mut() {
12934            if popover.current_signature + 1 == popover.signatures.len() {
12935                popover.current_signature = 0;
12936            } else {
12937                popover.current_signature += 1;
12938            }
12939            cx.notify();
12940        }
12941    }
12942
12943    pub fn move_to_previous_word_start(
12944        &mut self,
12945        _: &MoveToPreviousWordStart,
12946        window: &mut Window,
12947        cx: &mut Context<Self>,
12948    ) {
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950        self.change_selections(Default::default(), window, cx, |s| {
12951            s.move_cursors_with(|map, head, _| {
12952                (
12953                    movement::previous_word_start(map, head),
12954                    SelectionGoal::None,
12955                )
12956            });
12957        })
12958    }
12959
12960    pub fn move_to_previous_subword_start(
12961        &mut self,
12962        _: &MoveToPreviousSubwordStart,
12963        window: &mut Window,
12964        cx: &mut Context<Self>,
12965    ) {
12966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12967        self.change_selections(Default::default(), window, cx, |s| {
12968            s.move_cursors_with(|map, head, _| {
12969                (
12970                    movement::previous_subword_start(map, head),
12971                    SelectionGoal::None,
12972                )
12973            });
12974        })
12975    }
12976
12977    pub fn select_to_previous_word_start(
12978        &mut self,
12979        _: &SelectToPreviousWordStart,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12984        self.change_selections(Default::default(), window, cx, |s| {
12985            s.move_heads_with(|map, head, _| {
12986                (
12987                    movement::previous_word_start(map, head),
12988                    SelectionGoal::None,
12989                )
12990            });
12991        })
12992    }
12993
12994    pub fn select_to_previous_subword_start(
12995        &mut self,
12996        _: &SelectToPreviousSubwordStart,
12997        window: &mut Window,
12998        cx: &mut Context<Self>,
12999    ) {
13000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13001        self.change_selections(Default::default(), window, cx, |s| {
13002            s.move_heads_with(|map, head, _| {
13003                (
13004                    movement::previous_subword_start(map, head),
13005                    SelectionGoal::None,
13006                )
13007            });
13008        })
13009    }
13010
13011    pub fn delete_to_previous_word_start(
13012        &mut self,
13013        action: &DeleteToPreviousWordStart,
13014        window: &mut Window,
13015        cx: &mut Context<Self>,
13016    ) {
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13018        self.transact(window, cx, |this, window, cx| {
13019            this.select_autoclose_pair(window, cx);
13020            this.change_selections(Default::default(), window, cx, |s| {
13021                s.move_with(|map, selection| {
13022                    if selection.is_empty() {
13023                        let cursor = if action.ignore_newlines {
13024                            movement::previous_word_start(map, selection.head())
13025                        } else {
13026                            movement::previous_word_start_or_newline(map, selection.head())
13027                        };
13028                        selection.set_head(cursor, SelectionGoal::None);
13029                    }
13030                });
13031            });
13032            this.insert("", window, cx);
13033        });
13034    }
13035
13036    pub fn delete_to_previous_subword_start(
13037        &mut self,
13038        _: &DeleteToPreviousSubwordStart,
13039        window: &mut Window,
13040        cx: &mut Context<Self>,
13041    ) {
13042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13043        self.transact(window, cx, |this, window, cx| {
13044            this.select_autoclose_pair(window, cx);
13045            this.change_selections(Default::default(), window, cx, |s| {
13046                s.move_with(|map, selection| {
13047                    if selection.is_empty() {
13048                        let cursor = movement::previous_subword_start(map, selection.head());
13049                        selection.set_head(cursor, SelectionGoal::None);
13050                    }
13051                });
13052            });
13053            this.insert("", window, cx);
13054        });
13055    }
13056
13057    pub fn move_to_next_word_end(
13058        &mut self,
13059        _: &MoveToNextWordEnd,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13064        self.change_selections(Default::default(), window, cx, |s| {
13065            s.move_cursors_with(|map, head, _| {
13066                (movement::next_word_end(map, head), SelectionGoal::None)
13067            });
13068        })
13069    }
13070
13071    pub fn move_to_next_subword_end(
13072        &mut self,
13073        _: &MoveToNextSubwordEnd,
13074        window: &mut Window,
13075        cx: &mut Context<Self>,
13076    ) {
13077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13078        self.change_selections(Default::default(), window, cx, |s| {
13079            s.move_cursors_with(|map, head, _| {
13080                (movement::next_subword_end(map, head), SelectionGoal::None)
13081            });
13082        })
13083    }
13084
13085    pub fn select_to_next_word_end(
13086        &mut self,
13087        _: &SelectToNextWordEnd,
13088        window: &mut Window,
13089        cx: &mut Context<Self>,
13090    ) {
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13092        self.change_selections(Default::default(), window, cx, |s| {
13093            s.move_heads_with(|map, head, _| {
13094                (movement::next_word_end(map, head), SelectionGoal::None)
13095            });
13096        })
13097    }
13098
13099    pub fn select_to_next_subword_end(
13100        &mut self,
13101        _: &SelectToNextSubwordEnd,
13102        window: &mut Window,
13103        cx: &mut Context<Self>,
13104    ) {
13105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13106        self.change_selections(Default::default(), window, cx, |s| {
13107            s.move_heads_with(|map, head, _| {
13108                (movement::next_subword_end(map, head), SelectionGoal::None)
13109            });
13110        })
13111    }
13112
13113    pub fn delete_to_next_word_end(
13114        &mut self,
13115        action: &DeleteToNextWordEnd,
13116        window: &mut Window,
13117        cx: &mut Context<Self>,
13118    ) {
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13120        self.transact(window, cx, |this, window, cx| {
13121            this.change_selections(Default::default(), window, cx, |s| {
13122                s.move_with(|map, selection| {
13123                    if selection.is_empty() {
13124                        let cursor = if action.ignore_newlines {
13125                            movement::next_word_end(map, selection.head())
13126                        } else {
13127                            movement::next_word_end_or_newline(map, selection.head())
13128                        };
13129                        selection.set_head(cursor, SelectionGoal::None);
13130                    }
13131                });
13132            });
13133            this.insert("", window, cx);
13134        });
13135    }
13136
13137    pub fn delete_to_next_subword_end(
13138        &mut self,
13139        _: &DeleteToNextSubwordEnd,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13144        self.transact(window, cx, |this, window, cx| {
13145            this.change_selections(Default::default(), window, cx, |s| {
13146                s.move_with(|map, selection| {
13147                    if selection.is_empty() {
13148                        let cursor = movement::next_subword_end(map, selection.head());
13149                        selection.set_head(cursor, SelectionGoal::None);
13150                    }
13151                });
13152            });
13153            this.insert("", window, cx);
13154        });
13155    }
13156
13157    pub fn move_to_beginning_of_line(
13158        &mut self,
13159        action: &MoveToBeginningOfLine,
13160        window: &mut Window,
13161        cx: &mut Context<Self>,
13162    ) {
13163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13164        self.change_selections(Default::default(), window, cx, |s| {
13165            s.move_cursors_with(|map, head, _| {
13166                (
13167                    movement::indented_line_beginning(
13168                        map,
13169                        head,
13170                        action.stop_at_soft_wraps,
13171                        action.stop_at_indent,
13172                    ),
13173                    SelectionGoal::None,
13174                )
13175            });
13176        })
13177    }
13178
13179    pub fn select_to_beginning_of_line(
13180        &mut self,
13181        action: &SelectToBeginningOfLine,
13182        window: &mut Window,
13183        cx: &mut Context<Self>,
13184    ) {
13185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13186        self.change_selections(Default::default(), window, cx, |s| {
13187            s.move_heads_with(|map, head, _| {
13188                (
13189                    movement::indented_line_beginning(
13190                        map,
13191                        head,
13192                        action.stop_at_soft_wraps,
13193                        action.stop_at_indent,
13194                    ),
13195                    SelectionGoal::None,
13196                )
13197            });
13198        });
13199    }
13200
13201    pub fn delete_to_beginning_of_line(
13202        &mut self,
13203        action: &DeleteToBeginningOfLine,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208        self.transact(window, cx, |this, window, cx| {
13209            this.change_selections(Default::default(), window, cx, |s| {
13210                s.move_with(|_, selection| {
13211                    selection.reversed = true;
13212                });
13213            });
13214
13215            this.select_to_beginning_of_line(
13216                &SelectToBeginningOfLine {
13217                    stop_at_soft_wraps: false,
13218                    stop_at_indent: action.stop_at_indent,
13219                },
13220                window,
13221                cx,
13222            );
13223            this.backspace(&Backspace, window, cx);
13224        });
13225    }
13226
13227    pub fn move_to_end_of_line(
13228        &mut self,
13229        action: &MoveToEndOfLine,
13230        window: &mut Window,
13231        cx: &mut Context<Self>,
13232    ) {
13233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13234        self.change_selections(Default::default(), window, cx, |s| {
13235            s.move_cursors_with(|map, head, _| {
13236                (
13237                    movement::line_end(map, head, action.stop_at_soft_wraps),
13238                    SelectionGoal::None,
13239                )
13240            });
13241        })
13242    }
13243
13244    pub fn select_to_end_of_line(
13245        &mut self,
13246        action: &SelectToEndOfLine,
13247        window: &mut Window,
13248        cx: &mut Context<Self>,
13249    ) {
13250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13251        self.change_selections(Default::default(), window, cx, |s| {
13252            s.move_heads_with(|map, head, _| {
13253                (
13254                    movement::line_end(map, head, action.stop_at_soft_wraps),
13255                    SelectionGoal::None,
13256                )
13257            });
13258        })
13259    }
13260
13261    pub fn delete_to_end_of_line(
13262        &mut self,
13263        _: &DeleteToEndOfLine,
13264        window: &mut Window,
13265        cx: &mut Context<Self>,
13266    ) {
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13268        self.transact(window, cx, |this, window, cx| {
13269            this.select_to_end_of_line(
13270                &SelectToEndOfLine {
13271                    stop_at_soft_wraps: false,
13272                },
13273                window,
13274                cx,
13275            );
13276            this.delete(&Delete, window, cx);
13277        });
13278    }
13279
13280    pub fn cut_to_end_of_line(
13281        &mut self,
13282        _: &CutToEndOfLine,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13287        self.transact(window, cx, |this, window, cx| {
13288            this.select_to_end_of_line(
13289                &SelectToEndOfLine {
13290                    stop_at_soft_wraps: false,
13291                },
13292                window,
13293                cx,
13294            );
13295            this.cut(&Cut, window, cx);
13296        });
13297    }
13298
13299    pub fn move_to_start_of_paragraph(
13300        &mut self,
13301        _: &MoveToStartOfParagraph,
13302        window: &mut Window,
13303        cx: &mut Context<Self>,
13304    ) {
13305        if matches!(self.mode, EditorMode::SingleLine) {
13306            cx.propagate();
13307            return;
13308        }
13309        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13310        self.change_selections(Default::default(), window, cx, |s| {
13311            s.move_with(|map, selection| {
13312                selection.collapse_to(
13313                    movement::start_of_paragraph(map, selection.head(), 1),
13314                    SelectionGoal::None,
13315                )
13316            });
13317        })
13318    }
13319
13320    pub fn move_to_end_of_paragraph(
13321        &mut self,
13322        _: &MoveToEndOfParagraph,
13323        window: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) {
13326        if matches!(self.mode, EditorMode::SingleLine) {
13327            cx.propagate();
13328            return;
13329        }
13330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13331        self.change_selections(Default::default(), window, cx, |s| {
13332            s.move_with(|map, selection| {
13333                selection.collapse_to(
13334                    movement::end_of_paragraph(map, selection.head(), 1),
13335                    SelectionGoal::None,
13336                )
13337            });
13338        })
13339    }
13340
13341    pub fn select_to_start_of_paragraph(
13342        &mut self,
13343        _: &SelectToStartOfParagraph,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        if matches!(self.mode, EditorMode::SingleLine) {
13348            cx.propagate();
13349            return;
13350        }
13351        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13352        self.change_selections(Default::default(), window, cx, |s| {
13353            s.move_heads_with(|map, head, _| {
13354                (
13355                    movement::start_of_paragraph(map, head, 1),
13356                    SelectionGoal::None,
13357                )
13358            });
13359        })
13360    }
13361
13362    pub fn select_to_end_of_paragraph(
13363        &mut self,
13364        _: &SelectToEndOfParagraph,
13365        window: &mut Window,
13366        cx: &mut Context<Self>,
13367    ) {
13368        if matches!(self.mode, EditorMode::SingleLine) {
13369            cx.propagate();
13370            return;
13371        }
13372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13373        self.change_selections(Default::default(), window, cx, |s| {
13374            s.move_heads_with(|map, head, _| {
13375                (
13376                    movement::end_of_paragraph(map, head, 1),
13377                    SelectionGoal::None,
13378                )
13379            });
13380        })
13381    }
13382
13383    pub fn move_to_start_of_excerpt(
13384        &mut self,
13385        _: &MoveToStartOfExcerpt,
13386        window: &mut Window,
13387        cx: &mut Context<Self>,
13388    ) {
13389        if matches!(self.mode, EditorMode::SingleLine) {
13390            cx.propagate();
13391            return;
13392        }
13393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13394        self.change_selections(Default::default(), window, cx, |s| {
13395            s.move_with(|map, selection| {
13396                selection.collapse_to(
13397                    movement::start_of_excerpt(
13398                        map,
13399                        selection.head(),
13400                        workspace::searchable::Direction::Prev,
13401                    ),
13402                    SelectionGoal::None,
13403                )
13404            });
13405        })
13406    }
13407
13408    pub fn move_to_start_of_next_excerpt(
13409        &mut self,
13410        _: &MoveToStartOfNextExcerpt,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) {
13414        if matches!(self.mode, EditorMode::SingleLine) {
13415            cx.propagate();
13416            return;
13417        }
13418
13419        self.change_selections(Default::default(), window, cx, |s| {
13420            s.move_with(|map, selection| {
13421                selection.collapse_to(
13422                    movement::start_of_excerpt(
13423                        map,
13424                        selection.head(),
13425                        workspace::searchable::Direction::Next,
13426                    ),
13427                    SelectionGoal::None,
13428                )
13429            });
13430        })
13431    }
13432
13433    pub fn move_to_end_of_excerpt(
13434        &mut self,
13435        _: &MoveToEndOfExcerpt,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) {
13439        if matches!(self.mode, EditorMode::SingleLine) {
13440            cx.propagate();
13441            return;
13442        }
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.move_with(|map, selection| {
13446                selection.collapse_to(
13447                    movement::end_of_excerpt(
13448                        map,
13449                        selection.head(),
13450                        workspace::searchable::Direction::Next,
13451                    ),
13452                    SelectionGoal::None,
13453                )
13454            });
13455        })
13456    }
13457
13458    pub fn move_to_end_of_previous_excerpt(
13459        &mut self,
13460        _: &MoveToEndOfPreviousExcerpt,
13461        window: &mut Window,
13462        cx: &mut Context<Self>,
13463    ) {
13464        if matches!(self.mode, EditorMode::SingleLine) {
13465            cx.propagate();
13466            return;
13467        }
13468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13469        self.change_selections(Default::default(), window, cx, |s| {
13470            s.move_with(|map, selection| {
13471                selection.collapse_to(
13472                    movement::end_of_excerpt(
13473                        map,
13474                        selection.head(),
13475                        workspace::searchable::Direction::Prev,
13476                    ),
13477                    SelectionGoal::None,
13478                )
13479            });
13480        })
13481    }
13482
13483    pub fn select_to_start_of_excerpt(
13484        &mut self,
13485        _: &SelectToStartOfExcerpt,
13486        window: &mut Window,
13487        cx: &mut Context<Self>,
13488    ) {
13489        if matches!(self.mode, EditorMode::SingleLine) {
13490            cx.propagate();
13491            return;
13492        }
13493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13494        self.change_selections(Default::default(), window, cx, |s| {
13495            s.move_heads_with(|map, head, _| {
13496                (
13497                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13498                    SelectionGoal::None,
13499                )
13500            });
13501        })
13502    }
13503
13504    pub fn select_to_start_of_next_excerpt(
13505        &mut self,
13506        _: &SelectToStartOfNextExcerpt,
13507        window: &mut Window,
13508        cx: &mut Context<Self>,
13509    ) {
13510        if matches!(self.mode, EditorMode::SingleLine) {
13511            cx.propagate();
13512            return;
13513        }
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13515        self.change_selections(Default::default(), window, cx, |s| {
13516            s.move_heads_with(|map, head, _| {
13517                (
13518                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13519                    SelectionGoal::None,
13520                )
13521            });
13522        })
13523    }
13524
13525    pub fn select_to_end_of_excerpt(
13526        &mut self,
13527        _: &SelectToEndOfExcerpt,
13528        window: &mut Window,
13529        cx: &mut Context<Self>,
13530    ) {
13531        if matches!(self.mode, EditorMode::SingleLine) {
13532            cx.propagate();
13533            return;
13534        }
13535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13536        self.change_selections(Default::default(), window, cx, |s| {
13537            s.move_heads_with(|map, head, _| {
13538                (
13539                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13540                    SelectionGoal::None,
13541                )
13542            });
13543        })
13544    }
13545
13546    pub fn select_to_end_of_previous_excerpt(
13547        &mut self,
13548        _: &SelectToEndOfPreviousExcerpt,
13549        window: &mut Window,
13550        cx: &mut Context<Self>,
13551    ) {
13552        if matches!(self.mode, EditorMode::SingleLine) {
13553            cx.propagate();
13554            return;
13555        }
13556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13557        self.change_selections(Default::default(), window, cx, |s| {
13558            s.move_heads_with(|map, head, _| {
13559                (
13560                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13561                    SelectionGoal::None,
13562                )
13563            });
13564        })
13565    }
13566
13567    pub fn move_to_beginning(
13568        &mut self,
13569        _: &MoveToBeginning,
13570        window: &mut Window,
13571        cx: &mut Context<Self>,
13572    ) {
13573        if matches!(self.mode, EditorMode::SingleLine) {
13574            cx.propagate();
13575            return;
13576        }
13577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13578        self.change_selections(Default::default(), window, cx, |s| {
13579            s.select_ranges(vec![0..0]);
13580        });
13581    }
13582
13583    pub fn select_to_beginning(
13584        &mut self,
13585        _: &SelectToBeginning,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        let mut selection = self.selections.last::<Point>(cx);
13590        selection.set_head(Point::zero(), SelectionGoal::None);
13591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13592        self.change_selections(Default::default(), window, cx, |s| {
13593            s.select(vec![selection]);
13594        });
13595    }
13596
13597    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13598        if matches!(self.mode, EditorMode::SingleLine) {
13599            cx.propagate();
13600            return;
13601        }
13602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13603        let cursor = self.buffer.read(cx).read(cx).len();
13604        self.change_selections(Default::default(), window, cx, |s| {
13605            s.select_ranges(vec![cursor..cursor])
13606        });
13607    }
13608
13609    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13610        self.nav_history = nav_history;
13611    }
13612
13613    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13614        self.nav_history.as_ref()
13615    }
13616
13617    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13618        self.push_to_nav_history(
13619            self.selections.newest_anchor().head(),
13620            None,
13621            false,
13622            true,
13623            cx,
13624        );
13625    }
13626
13627    fn push_to_nav_history(
13628        &mut self,
13629        cursor_anchor: Anchor,
13630        new_position: Option<Point>,
13631        is_deactivate: bool,
13632        always: bool,
13633        cx: &mut Context<Self>,
13634    ) {
13635        if let Some(nav_history) = self.nav_history.as_mut() {
13636            let buffer = self.buffer.read(cx).read(cx);
13637            let cursor_position = cursor_anchor.to_point(&buffer);
13638            let scroll_state = self.scroll_manager.anchor();
13639            let scroll_top_row = scroll_state.top_row(&buffer);
13640            drop(buffer);
13641
13642            if let Some(new_position) = new_position {
13643                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13644                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13645                    return;
13646                }
13647            }
13648
13649            nav_history.push(
13650                Some(NavigationData {
13651                    cursor_anchor,
13652                    cursor_position,
13653                    scroll_anchor: scroll_state,
13654                    scroll_top_row,
13655                }),
13656                cx,
13657            );
13658            cx.emit(EditorEvent::PushedToNavHistory {
13659                anchor: cursor_anchor,
13660                is_deactivate,
13661            })
13662        }
13663    }
13664
13665    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13667        let buffer = self.buffer.read(cx).snapshot(cx);
13668        let mut selection = self.selections.first::<usize>(cx);
13669        selection.set_head(buffer.len(), SelectionGoal::None);
13670        self.change_selections(Default::default(), window, cx, |s| {
13671            s.select(vec![selection]);
13672        });
13673    }
13674
13675    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13676        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13677        let end = self.buffer.read(cx).read(cx).len();
13678        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13679            s.select_ranges(vec![0..end]);
13680        });
13681    }
13682
13683    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13685        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13686        let mut selections = self.selections.all::<Point>(cx);
13687        let max_point = display_map.buffer_snapshot.max_point();
13688        for selection in &mut selections {
13689            let rows = selection.spanned_rows(true, &display_map);
13690            selection.start = Point::new(rows.start.0, 0);
13691            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13692            selection.reversed = false;
13693        }
13694        self.change_selections(Default::default(), window, cx, |s| {
13695            s.select(selections);
13696        });
13697    }
13698
13699    pub fn split_selection_into_lines(
13700        &mut self,
13701        action: &SplitSelectionIntoLines,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        let selections = self
13706            .selections
13707            .all::<Point>(cx)
13708            .into_iter()
13709            .map(|selection| selection.start..selection.end)
13710            .collect::<Vec<_>>();
13711        self.unfold_ranges(&selections, true, true, cx);
13712
13713        let mut new_selection_ranges = Vec::new();
13714        {
13715            let buffer = self.buffer.read(cx).read(cx);
13716            for selection in selections {
13717                for row in selection.start.row..selection.end.row {
13718                    let line_start = Point::new(row, 0);
13719                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13720
13721                    if action.keep_selections {
13722                        // Keep the selection range for each line
13723                        let selection_start = if row == selection.start.row {
13724                            selection.start
13725                        } else {
13726                            line_start
13727                        };
13728                        new_selection_ranges.push(selection_start..line_end);
13729                    } else {
13730                        // Collapse to cursor at end of line
13731                        new_selection_ranges.push(line_end..line_end);
13732                    }
13733                }
13734
13735                let is_multiline_selection = selection.start.row != selection.end.row;
13736                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13737                // so this action feels more ergonomic when paired with other selection operations
13738                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13739                if !should_skip_last {
13740                    if action.keep_selections {
13741                        if is_multiline_selection {
13742                            let line_start = Point::new(selection.end.row, 0);
13743                            new_selection_ranges.push(line_start..selection.end);
13744                        } else {
13745                            new_selection_ranges.push(selection.start..selection.end);
13746                        }
13747                    } else {
13748                        new_selection_ranges.push(selection.end..selection.end);
13749                    }
13750                }
13751            }
13752        }
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.select_ranges(new_selection_ranges);
13755        });
13756    }
13757
13758    pub fn add_selection_above(
13759        &mut self,
13760        _: &AddSelectionAbove,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        self.add_selection(true, window, cx);
13765    }
13766
13767    pub fn add_selection_below(
13768        &mut self,
13769        _: &AddSelectionBelow,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        self.add_selection(false, window, cx);
13774    }
13775
13776    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778
13779        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13780        let all_selections = self.selections.all::<Point>(cx);
13781        let text_layout_details = self.text_layout_details(window);
13782
13783        let (mut columnar_selections, new_selections_to_columnarize) = {
13784            if let Some(state) = self.add_selections_state.as_ref() {
13785                let columnar_selection_ids: HashSet<_> = state
13786                    .groups
13787                    .iter()
13788                    .flat_map(|group| group.stack.iter())
13789                    .copied()
13790                    .collect();
13791
13792                all_selections
13793                    .into_iter()
13794                    .partition(|s| columnar_selection_ids.contains(&s.id))
13795            } else {
13796                (Vec::new(), all_selections)
13797            }
13798        };
13799
13800        let mut state = self
13801            .add_selections_state
13802            .take()
13803            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13804
13805        for selection in new_selections_to_columnarize {
13806            let range = selection.display_range(&display_map).sorted();
13807            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13808            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13809            let positions = start_x.min(end_x)..start_x.max(end_x);
13810            let mut stack = Vec::new();
13811            for row in range.start.row().0..=range.end.row().0 {
13812                if let Some(selection) = self.selections.build_columnar_selection(
13813                    &display_map,
13814                    DisplayRow(row),
13815                    &positions,
13816                    selection.reversed,
13817                    &text_layout_details,
13818                ) {
13819                    stack.push(selection.id);
13820                    columnar_selections.push(selection);
13821                }
13822            }
13823            if !stack.is_empty() {
13824                if above {
13825                    stack.reverse();
13826                }
13827                state.groups.push(AddSelectionsGroup { above, stack });
13828            }
13829        }
13830
13831        let mut final_selections = Vec::new();
13832        let end_row = if above {
13833            DisplayRow(0)
13834        } else {
13835            display_map.max_point().row()
13836        };
13837
13838        let mut last_added_item_per_group = HashMap::default();
13839        for group in state.groups.iter_mut() {
13840            if let Some(last_id) = group.stack.last() {
13841                last_added_item_per_group.insert(*last_id, group);
13842            }
13843        }
13844
13845        for selection in columnar_selections {
13846            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13847                if above == group.above {
13848                    let range = selection.display_range(&display_map).sorted();
13849                    debug_assert_eq!(range.start.row(), range.end.row());
13850                    let mut row = range.start.row();
13851                    let positions =
13852                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13853                            px(start)..px(end)
13854                        } else {
13855                            let start_x =
13856                                display_map.x_for_display_point(range.start, &text_layout_details);
13857                            let end_x =
13858                                display_map.x_for_display_point(range.end, &text_layout_details);
13859                            start_x.min(end_x)..start_x.max(end_x)
13860                        };
13861
13862                    let mut maybe_new_selection = None;
13863                    while row != end_row {
13864                        if above {
13865                            row.0 -= 1;
13866                        } else {
13867                            row.0 += 1;
13868                        }
13869                        if let Some(new_selection) = self.selections.build_columnar_selection(
13870                            &display_map,
13871                            row,
13872                            &positions,
13873                            selection.reversed,
13874                            &text_layout_details,
13875                        ) {
13876                            maybe_new_selection = Some(new_selection);
13877                            break;
13878                        }
13879                    }
13880
13881                    if let Some(new_selection) = maybe_new_selection {
13882                        group.stack.push(new_selection.id);
13883                        if above {
13884                            final_selections.push(new_selection);
13885                            final_selections.push(selection);
13886                        } else {
13887                            final_selections.push(selection);
13888                            final_selections.push(new_selection);
13889                        }
13890                    } else {
13891                        final_selections.push(selection);
13892                    }
13893                } else {
13894                    group.stack.pop();
13895                }
13896            } else {
13897                final_selections.push(selection);
13898            }
13899        }
13900
13901        self.change_selections(Default::default(), window, cx, |s| {
13902            s.select(final_selections);
13903        });
13904
13905        let final_selection_ids: HashSet<_> = self
13906            .selections
13907            .all::<Point>(cx)
13908            .iter()
13909            .map(|s| s.id)
13910            .collect();
13911        state.groups.retain_mut(|group| {
13912            // selections might get merged above so we remove invalid items from stacks
13913            group.stack.retain(|id| final_selection_ids.contains(id));
13914
13915            // single selection in stack can be treated as initial state
13916            group.stack.len() > 1
13917        });
13918
13919        if !state.groups.is_empty() {
13920            self.add_selections_state = Some(state);
13921        }
13922    }
13923
13924    fn select_match_ranges(
13925        &mut self,
13926        range: Range<usize>,
13927        reversed: bool,
13928        replace_newest: bool,
13929        auto_scroll: Option<Autoscroll>,
13930        window: &mut Window,
13931        cx: &mut Context<Editor>,
13932    ) {
13933        self.unfold_ranges(
13934            std::slice::from_ref(&range),
13935            false,
13936            auto_scroll.is_some(),
13937            cx,
13938        );
13939        let effects = if let Some(scroll) = auto_scroll {
13940            SelectionEffects::scroll(scroll)
13941        } else {
13942            SelectionEffects::no_scroll()
13943        };
13944        self.change_selections(effects, window, cx, |s| {
13945            if replace_newest {
13946                s.delete(s.newest_anchor().id);
13947            }
13948            if reversed {
13949                s.insert_range(range.end..range.start);
13950            } else {
13951                s.insert_range(range);
13952            }
13953        });
13954    }
13955
13956    pub fn select_next_match_internal(
13957        &mut self,
13958        display_map: &DisplaySnapshot,
13959        replace_newest: bool,
13960        autoscroll: Option<Autoscroll>,
13961        window: &mut Window,
13962        cx: &mut Context<Self>,
13963    ) -> Result<()> {
13964        let buffer = &display_map.buffer_snapshot;
13965        let mut selections = self.selections.all::<usize>(cx);
13966        if let Some(mut select_next_state) = self.select_next_state.take() {
13967            let query = &select_next_state.query;
13968            if !select_next_state.done {
13969                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13970                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13971                let mut next_selected_range = None;
13972
13973                let bytes_after_last_selection =
13974                    buffer.bytes_in_range(last_selection.end..buffer.len());
13975                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13976                let query_matches = query
13977                    .stream_find_iter(bytes_after_last_selection)
13978                    .map(|result| (last_selection.end, result))
13979                    .chain(
13980                        query
13981                            .stream_find_iter(bytes_before_first_selection)
13982                            .map(|result| (0, result)),
13983                    );
13984
13985                for (start_offset, query_match) in query_matches {
13986                    let query_match = query_match.unwrap(); // can only fail due to I/O
13987                    let offset_range =
13988                        start_offset + query_match.start()..start_offset + query_match.end();
13989
13990                    if !select_next_state.wordwise
13991                        || (!buffer.is_inside_word(offset_range.start, false)
13992                            && !buffer.is_inside_word(offset_range.end, false))
13993                    {
13994                        // TODO: This is n^2, because we might check all the selections
13995                        if !selections
13996                            .iter()
13997                            .any(|selection| selection.range().overlaps(&offset_range))
13998                        {
13999                            next_selected_range = Some(offset_range);
14000                            break;
14001                        }
14002                    }
14003                }
14004
14005                if let Some(next_selected_range) = next_selected_range {
14006                    self.select_match_ranges(
14007                        next_selected_range,
14008                        last_selection.reversed,
14009                        replace_newest,
14010                        autoscroll,
14011                        window,
14012                        cx,
14013                    );
14014                } else {
14015                    select_next_state.done = true;
14016                }
14017            }
14018
14019            self.select_next_state = Some(select_next_state);
14020        } else {
14021            let mut only_carets = true;
14022            let mut same_text_selected = true;
14023            let mut selected_text = None;
14024
14025            let mut selections_iter = selections.iter().peekable();
14026            while let Some(selection) = selections_iter.next() {
14027                if selection.start != selection.end {
14028                    only_carets = false;
14029                }
14030
14031                if same_text_selected {
14032                    if selected_text.is_none() {
14033                        selected_text =
14034                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14035                    }
14036
14037                    if let Some(next_selection) = selections_iter.peek() {
14038                        if next_selection.range().len() == selection.range().len() {
14039                            let next_selected_text = buffer
14040                                .text_for_range(next_selection.range())
14041                                .collect::<String>();
14042                            if Some(next_selected_text) != selected_text {
14043                                same_text_selected = false;
14044                                selected_text = None;
14045                            }
14046                        } else {
14047                            same_text_selected = false;
14048                            selected_text = None;
14049                        }
14050                    }
14051                }
14052            }
14053
14054            if only_carets {
14055                for selection in &mut selections {
14056                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14057                    selection.start = word_range.start;
14058                    selection.end = word_range.end;
14059                    selection.goal = SelectionGoal::None;
14060                    selection.reversed = false;
14061                    self.select_match_ranges(
14062                        selection.start..selection.end,
14063                        selection.reversed,
14064                        replace_newest,
14065                        autoscroll,
14066                        window,
14067                        cx,
14068                    );
14069                }
14070
14071                if selections.len() == 1 {
14072                    let selection = selections
14073                        .last()
14074                        .expect("ensured that there's only one selection");
14075                    let query = buffer
14076                        .text_for_range(selection.start..selection.end)
14077                        .collect::<String>();
14078                    let is_empty = query.is_empty();
14079                    let select_state = SelectNextState {
14080                        query: AhoCorasick::new(&[query])?,
14081                        wordwise: true,
14082                        done: is_empty,
14083                    };
14084                    self.select_next_state = Some(select_state);
14085                } else {
14086                    self.select_next_state = None;
14087                }
14088            } else if let Some(selected_text) = selected_text {
14089                self.select_next_state = Some(SelectNextState {
14090                    query: AhoCorasick::new(&[selected_text])?,
14091                    wordwise: false,
14092                    done: false,
14093                });
14094                self.select_next_match_internal(
14095                    display_map,
14096                    replace_newest,
14097                    autoscroll,
14098                    window,
14099                    cx,
14100                )?;
14101            }
14102        }
14103        Ok(())
14104    }
14105
14106    pub fn select_all_matches(
14107        &mut self,
14108        _action: &SelectAllMatches,
14109        window: &mut Window,
14110        cx: &mut Context<Self>,
14111    ) -> Result<()> {
14112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14113
14114        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14115
14116        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14117        let Some(select_next_state) = self.select_next_state.as_mut() else {
14118            return Ok(());
14119        };
14120        if select_next_state.done {
14121            return Ok(());
14122        }
14123
14124        let mut new_selections = Vec::new();
14125
14126        let reversed = self.selections.oldest::<usize>(cx).reversed;
14127        let buffer = &display_map.buffer_snapshot;
14128        let query_matches = select_next_state
14129            .query
14130            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14131
14132        for query_match in query_matches.into_iter() {
14133            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14134            let offset_range = if reversed {
14135                query_match.end()..query_match.start()
14136            } else {
14137                query_match.start()..query_match.end()
14138            };
14139
14140            if !select_next_state.wordwise
14141                || (!buffer.is_inside_word(offset_range.start, false)
14142                    && !buffer.is_inside_word(offset_range.end, false))
14143            {
14144                new_selections.push(offset_range.start..offset_range.end);
14145            }
14146        }
14147
14148        select_next_state.done = true;
14149
14150        if new_selections.is_empty() {
14151            log::error!("bug: new_selections is empty in select_all_matches");
14152            return Ok(());
14153        }
14154
14155        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14156        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14157            selections.select_ranges(new_selections)
14158        });
14159
14160        Ok(())
14161    }
14162
14163    pub fn select_next(
14164        &mut self,
14165        action: &SelectNext,
14166        window: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) -> Result<()> {
14169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14171        self.select_next_match_internal(
14172            &display_map,
14173            action.replace_newest,
14174            Some(Autoscroll::newest()),
14175            window,
14176            cx,
14177        )?;
14178        Ok(())
14179    }
14180
14181    pub fn select_previous(
14182        &mut self,
14183        action: &SelectPrevious,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) -> Result<()> {
14187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14189        let buffer = &display_map.buffer_snapshot;
14190        let mut selections = self.selections.all::<usize>(cx);
14191        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14192            let query = &select_prev_state.query;
14193            if !select_prev_state.done {
14194                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14195                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14196                let mut next_selected_range = None;
14197                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14198                let bytes_before_last_selection =
14199                    buffer.reversed_bytes_in_range(0..last_selection.start);
14200                let bytes_after_first_selection =
14201                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14202                let query_matches = query
14203                    .stream_find_iter(bytes_before_last_selection)
14204                    .map(|result| (last_selection.start, result))
14205                    .chain(
14206                        query
14207                            .stream_find_iter(bytes_after_first_selection)
14208                            .map(|result| (buffer.len(), result)),
14209                    );
14210                for (end_offset, query_match) in query_matches {
14211                    let query_match = query_match.unwrap(); // can only fail due to I/O
14212                    let offset_range =
14213                        end_offset - query_match.end()..end_offset - query_match.start();
14214
14215                    if !select_prev_state.wordwise
14216                        || (!buffer.is_inside_word(offset_range.start, false)
14217                            && !buffer.is_inside_word(offset_range.end, false))
14218                    {
14219                        next_selected_range = Some(offset_range);
14220                        break;
14221                    }
14222                }
14223
14224                if let Some(next_selected_range) = next_selected_range {
14225                    self.select_match_ranges(
14226                        next_selected_range,
14227                        last_selection.reversed,
14228                        action.replace_newest,
14229                        Some(Autoscroll::newest()),
14230                        window,
14231                        cx,
14232                    );
14233                } else {
14234                    select_prev_state.done = true;
14235                }
14236            }
14237
14238            self.select_prev_state = Some(select_prev_state);
14239        } else {
14240            let mut only_carets = true;
14241            let mut same_text_selected = true;
14242            let mut selected_text = None;
14243
14244            let mut selections_iter = selections.iter().peekable();
14245            while let Some(selection) = selections_iter.next() {
14246                if selection.start != selection.end {
14247                    only_carets = false;
14248                }
14249
14250                if same_text_selected {
14251                    if selected_text.is_none() {
14252                        selected_text =
14253                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14254                    }
14255
14256                    if let Some(next_selection) = selections_iter.peek() {
14257                        if next_selection.range().len() == selection.range().len() {
14258                            let next_selected_text = buffer
14259                                .text_for_range(next_selection.range())
14260                                .collect::<String>();
14261                            if Some(next_selected_text) != selected_text {
14262                                same_text_selected = false;
14263                                selected_text = None;
14264                            }
14265                        } else {
14266                            same_text_selected = false;
14267                            selected_text = None;
14268                        }
14269                    }
14270                }
14271            }
14272
14273            if only_carets {
14274                for selection in &mut selections {
14275                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14276                    selection.start = word_range.start;
14277                    selection.end = word_range.end;
14278                    selection.goal = SelectionGoal::None;
14279                    selection.reversed = false;
14280                    self.select_match_ranges(
14281                        selection.start..selection.end,
14282                        selection.reversed,
14283                        action.replace_newest,
14284                        Some(Autoscroll::newest()),
14285                        window,
14286                        cx,
14287                    );
14288                }
14289                if selections.len() == 1 {
14290                    let selection = selections
14291                        .last()
14292                        .expect("ensured that there's only one selection");
14293                    let query = buffer
14294                        .text_for_range(selection.start..selection.end)
14295                        .collect::<String>();
14296                    let is_empty = query.is_empty();
14297                    let select_state = SelectNextState {
14298                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14299                        wordwise: true,
14300                        done: is_empty,
14301                    };
14302                    self.select_prev_state = Some(select_state);
14303                } else {
14304                    self.select_prev_state = None;
14305                }
14306            } else if let Some(selected_text) = selected_text {
14307                self.select_prev_state = Some(SelectNextState {
14308                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14309                    wordwise: false,
14310                    done: false,
14311                });
14312                self.select_previous(action, window, cx)?;
14313            }
14314        }
14315        Ok(())
14316    }
14317
14318    pub fn find_next_match(
14319        &mut self,
14320        _: &FindNextMatch,
14321        window: &mut Window,
14322        cx: &mut Context<Self>,
14323    ) -> Result<()> {
14324        let selections = self.selections.disjoint_anchors();
14325        match selections.first() {
14326            Some(first) if selections.len() >= 2 => {
14327                self.change_selections(Default::default(), window, cx, |s| {
14328                    s.select_ranges([first.range()]);
14329                });
14330            }
14331            _ => self.select_next(
14332                &SelectNext {
14333                    replace_newest: true,
14334                },
14335                window,
14336                cx,
14337            )?,
14338        }
14339        Ok(())
14340    }
14341
14342    pub fn find_previous_match(
14343        &mut self,
14344        _: &FindPreviousMatch,
14345        window: &mut Window,
14346        cx: &mut Context<Self>,
14347    ) -> Result<()> {
14348        let selections = self.selections.disjoint_anchors();
14349        match selections.last() {
14350            Some(last) if selections.len() >= 2 => {
14351                self.change_selections(Default::default(), window, cx, |s| {
14352                    s.select_ranges([last.range()]);
14353                });
14354            }
14355            _ => self.select_previous(
14356                &SelectPrevious {
14357                    replace_newest: true,
14358                },
14359                window,
14360                cx,
14361            )?,
14362        }
14363        Ok(())
14364    }
14365
14366    pub fn toggle_comments(
14367        &mut self,
14368        action: &ToggleComments,
14369        window: &mut Window,
14370        cx: &mut Context<Self>,
14371    ) {
14372        if self.read_only(cx) {
14373            return;
14374        }
14375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14376        let text_layout_details = &self.text_layout_details(window);
14377        self.transact(window, cx, |this, window, cx| {
14378            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14379            let mut edits = Vec::new();
14380            let mut selection_edit_ranges = Vec::new();
14381            let mut last_toggled_row = None;
14382            let snapshot = this.buffer.read(cx).read(cx);
14383            let empty_str: Arc<str> = Arc::default();
14384            let mut suffixes_inserted = Vec::new();
14385            let ignore_indent = action.ignore_indent;
14386
14387            fn comment_prefix_range(
14388                snapshot: &MultiBufferSnapshot,
14389                row: MultiBufferRow,
14390                comment_prefix: &str,
14391                comment_prefix_whitespace: &str,
14392                ignore_indent: bool,
14393            ) -> Range<Point> {
14394                let indent_size = if ignore_indent {
14395                    0
14396                } else {
14397                    snapshot.indent_size_for_line(row).len
14398                };
14399
14400                let start = Point::new(row.0, indent_size);
14401
14402                let mut line_bytes = snapshot
14403                    .bytes_in_range(start..snapshot.max_point())
14404                    .flatten()
14405                    .copied();
14406
14407                // If this line currently begins with the line comment prefix, then record
14408                // the range containing the prefix.
14409                if line_bytes
14410                    .by_ref()
14411                    .take(comment_prefix.len())
14412                    .eq(comment_prefix.bytes())
14413                {
14414                    // Include any whitespace that matches the comment prefix.
14415                    let matching_whitespace_len = line_bytes
14416                        .zip(comment_prefix_whitespace.bytes())
14417                        .take_while(|(a, b)| a == b)
14418                        .count() as u32;
14419                    let end = Point::new(
14420                        start.row,
14421                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14422                    );
14423                    start..end
14424                } else {
14425                    start..start
14426                }
14427            }
14428
14429            fn comment_suffix_range(
14430                snapshot: &MultiBufferSnapshot,
14431                row: MultiBufferRow,
14432                comment_suffix: &str,
14433                comment_suffix_has_leading_space: bool,
14434            ) -> Range<Point> {
14435                let end = Point::new(row.0, snapshot.line_len(row));
14436                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14437
14438                let mut line_end_bytes = snapshot
14439                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14440                    .flatten()
14441                    .copied();
14442
14443                let leading_space_len = if suffix_start_column > 0
14444                    && line_end_bytes.next() == Some(b' ')
14445                    && comment_suffix_has_leading_space
14446                {
14447                    1
14448                } else {
14449                    0
14450                };
14451
14452                // If this line currently begins with the line comment prefix, then record
14453                // the range containing the prefix.
14454                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14455                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14456                    start..end
14457                } else {
14458                    end..end
14459                }
14460            }
14461
14462            // TODO: Handle selections that cross excerpts
14463            for selection in &mut selections {
14464                let start_column = snapshot
14465                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14466                    .len;
14467                let language = if let Some(language) =
14468                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14469                {
14470                    language
14471                } else {
14472                    continue;
14473                };
14474
14475                selection_edit_ranges.clear();
14476
14477                // If multiple selections contain a given row, avoid processing that
14478                // row more than once.
14479                let mut start_row = MultiBufferRow(selection.start.row);
14480                if last_toggled_row == Some(start_row) {
14481                    start_row = start_row.next_row();
14482                }
14483                let end_row =
14484                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14485                        MultiBufferRow(selection.end.row - 1)
14486                    } else {
14487                        MultiBufferRow(selection.end.row)
14488                    };
14489                last_toggled_row = Some(end_row);
14490
14491                if start_row > end_row {
14492                    continue;
14493                }
14494
14495                // If the language has line comments, toggle those.
14496                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14497
14498                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14499                if ignore_indent {
14500                    full_comment_prefixes = full_comment_prefixes
14501                        .into_iter()
14502                        .map(|s| Arc::from(s.trim_end()))
14503                        .collect();
14504                }
14505
14506                if !full_comment_prefixes.is_empty() {
14507                    let first_prefix = full_comment_prefixes
14508                        .first()
14509                        .expect("prefixes is non-empty");
14510                    let prefix_trimmed_lengths = full_comment_prefixes
14511                        .iter()
14512                        .map(|p| p.trim_end_matches(' ').len())
14513                        .collect::<SmallVec<[usize; 4]>>();
14514
14515                    let mut all_selection_lines_are_comments = true;
14516
14517                    for row in start_row.0..=end_row.0 {
14518                        let row = MultiBufferRow(row);
14519                        if start_row < end_row && snapshot.is_line_blank(row) {
14520                            continue;
14521                        }
14522
14523                        let prefix_range = full_comment_prefixes
14524                            .iter()
14525                            .zip(prefix_trimmed_lengths.iter().copied())
14526                            .map(|(prefix, trimmed_prefix_len)| {
14527                                comment_prefix_range(
14528                                    snapshot.deref(),
14529                                    row,
14530                                    &prefix[..trimmed_prefix_len],
14531                                    &prefix[trimmed_prefix_len..],
14532                                    ignore_indent,
14533                                )
14534                            })
14535                            .max_by_key(|range| range.end.column - range.start.column)
14536                            .expect("prefixes is non-empty");
14537
14538                        if prefix_range.is_empty() {
14539                            all_selection_lines_are_comments = false;
14540                        }
14541
14542                        selection_edit_ranges.push(prefix_range);
14543                    }
14544
14545                    if all_selection_lines_are_comments {
14546                        edits.extend(
14547                            selection_edit_ranges
14548                                .iter()
14549                                .cloned()
14550                                .map(|range| (range, empty_str.clone())),
14551                        );
14552                    } else {
14553                        let min_column = selection_edit_ranges
14554                            .iter()
14555                            .map(|range| range.start.column)
14556                            .min()
14557                            .unwrap_or(0);
14558                        edits.extend(selection_edit_ranges.iter().map(|range| {
14559                            let position = Point::new(range.start.row, min_column);
14560                            (position..position, first_prefix.clone())
14561                        }));
14562                    }
14563                } else if let Some(BlockCommentConfig {
14564                    start: full_comment_prefix,
14565                    end: comment_suffix,
14566                    ..
14567                }) = language.block_comment()
14568                {
14569                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14570                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14571                    let prefix_range = comment_prefix_range(
14572                        snapshot.deref(),
14573                        start_row,
14574                        comment_prefix,
14575                        comment_prefix_whitespace,
14576                        ignore_indent,
14577                    );
14578                    let suffix_range = comment_suffix_range(
14579                        snapshot.deref(),
14580                        end_row,
14581                        comment_suffix.trim_start_matches(' '),
14582                        comment_suffix.starts_with(' '),
14583                    );
14584
14585                    if prefix_range.is_empty() || suffix_range.is_empty() {
14586                        edits.push((
14587                            prefix_range.start..prefix_range.start,
14588                            full_comment_prefix.clone(),
14589                        ));
14590                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14591                        suffixes_inserted.push((end_row, comment_suffix.len()));
14592                    } else {
14593                        edits.push((prefix_range, empty_str.clone()));
14594                        edits.push((suffix_range, empty_str.clone()));
14595                    }
14596                } else {
14597                    continue;
14598                }
14599            }
14600
14601            drop(snapshot);
14602            this.buffer.update(cx, |buffer, cx| {
14603                buffer.edit(edits, None, cx);
14604            });
14605
14606            // Adjust selections so that they end before any comment suffixes that
14607            // were inserted.
14608            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14609            let mut selections = this.selections.all::<Point>(cx);
14610            let snapshot = this.buffer.read(cx).read(cx);
14611            for selection in &mut selections {
14612                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14613                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14614                        Ordering::Less => {
14615                            suffixes_inserted.next();
14616                            continue;
14617                        }
14618                        Ordering::Greater => break,
14619                        Ordering::Equal => {
14620                            if selection.end.column == snapshot.line_len(row) {
14621                                if selection.is_empty() {
14622                                    selection.start.column -= suffix_len as u32;
14623                                }
14624                                selection.end.column -= suffix_len as u32;
14625                            }
14626                            break;
14627                        }
14628                    }
14629                }
14630            }
14631
14632            drop(snapshot);
14633            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14634
14635            let selections = this.selections.all::<Point>(cx);
14636            let selections_on_single_row = selections.windows(2).all(|selections| {
14637                selections[0].start.row == selections[1].start.row
14638                    && selections[0].end.row == selections[1].end.row
14639                    && selections[0].start.row == selections[0].end.row
14640            });
14641            let selections_selecting = selections
14642                .iter()
14643                .any(|selection| selection.start != selection.end);
14644            let advance_downwards = action.advance_downwards
14645                && selections_on_single_row
14646                && !selections_selecting
14647                && !matches!(this.mode, EditorMode::SingleLine);
14648
14649            if advance_downwards {
14650                let snapshot = this.buffer.read(cx).snapshot(cx);
14651
14652                this.change_selections(Default::default(), window, cx, |s| {
14653                    s.move_cursors_with(|display_snapshot, display_point, _| {
14654                        let mut point = display_point.to_point(display_snapshot);
14655                        point.row += 1;
14656                        point = snapshot.clip_point(point, Bias::Left);
14657                        let display_point = point.to_display_point(display_snapshot);
14658                        let goal = SelectionGoal::HorizontalPosition(
14659                            display_snapshot
14660                                .x_for_display_point(display_point, text_layout_details)
14661                                .into(),
14662                        );
14663                        (display_point, goal)
14664                    })
14665                });
14666            }
14667        });
14668    }
14669
14670    pub fn select_enclosing_symbol(
14671        &mut self,
14672        _: &SelectEnclosingSymbol,
14673        window: &mut Window,
14674        cx: &mut Context<Self>,
14675    ) {
14676        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14677
14678        let buffer = self.buffer.read(cx).snapshot(cx);
14679        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14680
14681        fn update_selection(
14682            selection: &Selection<usize>,
14683            buffer_snap: &MultiBufferSnapshot,
14684        ) -> Option<Selection<usize>> {
14685            let cursor = selection.head();
14686            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14687            for symbol in symbols.iter().rev() {
14688                let start = symbol.range.start.to_offset(buffer_snap);
14689                let end = symbol.range.end.to_offset(buffer_snap);
14690                let new_range = start..end;
14691                if start < selection.start || end > selection.end {
14692                    return Some(Selection {
14693                        id: selection.id,
14694                        start: new_range.start,
14695                        end: new_range.end,
14696                        goal: SelectionGoal::None,
14697                        reversed: selection.reversed,
14698                    });
14699                }
14700            }
14701            None
14702        }
14703
14704        let mut selected_larger_symbol = false;
14705        let new_selections = old_selections
14706            .iter()
14707            .map(|selection| match update_selection(selection, &buffer) {
14708                Some(new_selection) => {
14709                    if new_selection.range() != selection.range() {
14710                        selected_larger_symbol = true;
14711                    }
14712                    new_selection
14713                }
14714                None => selection.clone(),
14715            })
14716            .collect::<Vec<_>>();
14717
14718        if selected_larger_symbol {
14719            self.change_selections(Default::default(), window, cx, |s| {
14720                s.select(new_selections);
14721            });
14722        }
14723    }
14724
14725    pub fn select_larger_syntax_node(
14726        &mut self,
14727        _: &SelectLargerSyntaxNode,
14728        window: &mut Window,
14729        cx: &mut Context<Self>,
14730    ) {
14731        let Some(visible_row_count) = self.visible_row_count() else {
14732            return;
14733        };
14734        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14735        if old_selections.is_empty() {
14736            return;
14737        }
14738
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14740
14741        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14742        let buffer = self.buffer.read(cx).snapshot(cx);
14743
14744        let mut selected_larger_node = false;
14745        let mut new_selections = old_selections
14746            .iter()
14747            .map(|selection| {
14748                let old_range = selection.start..selection.end;
14749
14750                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14751                    // manually select word at selection
14752                    if ["string_content", "inline"].contains(&node.kind()) {
14753                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14754                        // ignore if word is already selected
14755                        if !word_range.is_empty() && old_range != word_range {
14756                            let (last_word_range, _) =
14757                                buffer.surrounding_word(old_range.end, false);
14758                            // only select word if start and end point belongs to same word
14759                            if word_range == last_word_range {
14760                                selected_larger_node = true;
14761                                return Selection {
14762                                    id: selection.id,
14763                                    start: word_range.start,
14764                                    end: word_range.end,
14765                                    goal: SelectionGoal::None,
14766                                    reversed: selection.reversed,
14767                                };
14768                            }
14769                        }
14770                    }
14771                }
14772
14773                let mut new_range = old_range.clone();
14774                while let Some((_node, containing_range)) =
14775                    buffer.syntax_ancestor(new_range.clone())
14776                {
14777                    new_range = match containing_range {
14778                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14779                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14780                    };
14781                    if !display_map.intersects_fold(new_range.start)
14782                        && !display_map.intersects_fold(new_range.end)
14783                    {
14784                        break;
14785                    }
14786                }
14787
14788                selected_larger_node |= new_range != old_range;
14789                Selection {
14790                    id: selection.id,
14791                    start: new_range.start,
14792                    end: new_range.end,
14793                    goal: SelectionGoal::None,
14794                    reversed: selection.reversed,
14795                }
14796            })
14797            .collect::<Vec<_>>();
14798
14799        if !selected_larger_node {
14800            return; // don't put this call in the history
14801        }
14802
14803        // scroll based on transformation done to the last selection created by the user
14804        let (last_old, last_new) = old_selections
14805            .last()
14806            .zip(new_selections.last().cloned())
14807            .expect("old_selections isn't empty");
14808
14809        // revert selection
14810        let is_selection_reversed = {
14811            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14812            new_selections.last_mut().expect("checked above").reversed =
14813                should_newest_selection_be_reversed;
14814            should_newest_selection_be_reversed
14815        };
14816
14817        if selected_larger_node {
14818            self.select_syntax_node_history.disable_clearing = true;
14819            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14820                s.select(new_selections.clone());
14821            });
14822            self.select_syntax_node_history.disable_clearing = false;
14823        }
14824
14825        let start_row = last_new.start.to_display_point(&display_map).row().0;
14826        let end_row = last_new.end.to_display_point(&display_map).row().0;
14827        let selection_height = end_row - start_row + 1;
14828        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14829
14830        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14831        let scroll_behavior = if fits_on_the_screen {
14832            self.request_autoscroll(Autoscroll::fit(), cx);
14833            SelectSyntaxNodeScrollBehavior::FitSelection
14834        } else if is_selection_reversed {
14835            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14836            SelectSyntaxNodeScrollBehavior::CursorTop
14837        } else {
14838            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14839            SelectSyntaxNodeScrollBehavior::CursorBottom
14840        };
14841
14842        self.select_syntax_node_history.push((
14843            old_selections,
14844            scroll_behavior,
14845            is_selection_reversed,
14846        ));
14847    }
14848
14849    pub fn select_smaller_syntax_node(
14850        &mut self,
14851        _: &SelectSmallerSyntaxNode,
14852        window: &mut Window,
14853        cx: &mut Context<Self>,
14854    ) {
14855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14856
14857        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14858            self.select_syntax_node_history.pop()
14859        {
14860            if let Some(selection) = selections.last_mut() {
14861                selection.reversed = is_selection_reversed;
14862            }
14863
14864            self.select_syntax_node_history.disable_clearing = true;
14865            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14866                s.select(selections.to_vec());
14867            });
14868            self.select_syntax_node_history.disable_clearing = false;
14869
14870            match scroll_behavior {
14871                SelectSyntaxNodeScrollBehavior::CursorTop => {
14872                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14873                }
14874                SelectSyntaxNodeScrollBehavior::FitSelection => {
14875                    self.request_autoscroll(Autoscroll::fit(), cx);
14876                }
14877                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14878                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14879                }
14880            }
14881        }
14882    }
14883
14884    pub fn unwrap_syntax_node(
14885        &mut self,
14886        _: &UnwrapSyntaxNode,
14887        window: &mut Window,
14888        cx: &mut Context<Self>,
14889    ) {
14890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14891
14892        let buffer = self.buffer.read(cx).snapshot(cx);
14893        let selections = self
14894            .selections
14895            .all::<usize>(cx)
14896            .into_iter()
14897            // subtracting the offset requires sorting
14898            .sorted_by_key(|i| i.start);
14899
14900        let full_edits = selections
14901            .into_iter()
14902            .filter_map(|selection| {
14903                // Only requires two branches once if-let-chains stabilize (#53667)
14904                let child = if !selection.is_empty() {
14905                    selection.range()
14906                } else if let Some((_, ancestor_range)) =
14907                    buffer.syntax_ancestor(selection.start..selection.end)
14908                {
14909                    match ancestor_range {
14910                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14911                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14912                    }
14913                } else {
14914                    selection.range()
14915                };
14916
14917                let mut parent = child.clone();
14918                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14919                    parent = match ancestor_range {
14920                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14921                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14922                    };
14923                    if parent.start < child.start || parent.end > child.end {
14924                        break;
14925                    }
14926                }
14927
14928                if parent == child {
14929                    return None;
14930                }
14931                let text = buffer.text_for_range(child).collect::<String>();
14932                Some((selection.id, parent, text))
14933            })
14934            .collect::<Vec<_>>();
14935
14936        self.transact(window, cx, |this, window, cx| {
14937            this.buffer.update(cx, |buffer, cx| {
14938                buffer.edit(
14939                    full_edits
14940                        .iter()
14941                        .map(|(_, p, t)| (p.clone(), t.clone()))
14942                        .collect::<Vec<_>>(),
14943                    None,
14944                    cx,
14945                );
14946            });
14947            this.change_selections(Default::default(), window, cx, |s| {
14948                let mut offset = 0;
14949                let mut selections = vec![];
14950                for (id, parent, text) in full_edits {
14951                    let start = parent.start - offset;
14952                    offset += parent.len() - text.len();
14953                    selections.push(Selection {
14954                        id,
14955                        start,
14956                        end: start + text.len(),
14957                        reversed: false,
14958                        goal: Default::default(),
14959                    });
14960                }
14961                s.select(selections);
14962            });
14963        });
14964    }
14965
14966    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14967        if !EditorSettings::get_global(cx).gutter.runnables {
14968            self.clear_tasks();
14969            return Task::ready(());
14970        }
14971        let project = self.project().map(Entity::downgrade);
14972        let task_sources = self.lsp_task_sources(cx);
14973        let multi_buffer = self.buffer.downgrade();
14974        cx.spawn_in(window, async move |editor, cx| {
14975            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14976            let Some(project) = project.and_then(|p| p.upgrade()) else {
14977                return;
14978            };
14979            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14980                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14981            }) else {
14982                return;
14983            };
14984
14985            let hide_runnables = project
14986                .update(cx, |project, _| project.is_via_collab())
14987                .unwrap_or(true);
14988            if hide_runnables {
14989                return;
14990            }
14991            let new_rows =
14992                cx.background_spawn({
14993                    let snapshot = display_snapshot.clone();
14994                    async move {
14995                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14996                    }
14997                })
14998                    .await;
14999            let Ok(lsp_tasks) =
15000                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15001            else {
15002                return;
15003            };
15004            let lsp_tasks = lsp_tasks.await;
15005
15006            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15007                lsp_tasks
15008                    .into_iter()
15009                    .flat_map(|(kind, tasks)| {
15010                        tasks.into_iter().filter_map(move |(location, task)| {
15011                            Some((kind.clone(), location?, task))
15012                        })
15013                    })
15014                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15015                        let buffer = location.target.buffer;
15016                        let buffer_snapshot = buffer.read(cx).snapshot();
15017                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15018                            |(excerpt_id, snapshot, _)| {
15019                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15020                                    display_snapshot
15021                                        .buffer_snapshot
15022                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15023                                } else {
15024                                    None
15025                                }
15026                            },
15027                        );
15028                        if let Some(offset) = offset {
15029                            let task_buffer_range =
15030                                location.target.range.to_point(&buffer_snapshot);
15031                            let context_buffer_range =
15032                                task_buffer_range.to_offset(&buffer_snapshot);
15033                            let context_range = BufferOffset(context_buffer_range.start)
15034                                ..BufferOffset(context_buffer_range.end);
15035
15036                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15037                                .or_insert_with(|| RunnableTasks {
15038                                    templates: Vec::new(),
15039                                    offset,
15040                                    column: task_buffer_range.start.column,
15041                                    extra_variables: HashMap::default(),
15042                                    context_range,
15043                                })
15044                                .templates
15045                                .push((kind, task.original_task().clone()));
15046                        }
15047
15048                        acc
15049                    })
15050            }) else {
15051                return;
15052            };
15053
15054            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15055                buffer.language_settings(cx).tasks.prefer_lsp
15056            }) else {
15057                return;
15058            };
15059
15060            let rows = Self::runnable_rows(
15061                project,
15062                display_snapshot,
15063                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15064                new_rows,
15065                cx.clone(),
15066            )
15067            .await;
15068            editor
15069                .update(cx, |editor, _| {
15070                    editor.clear_tasks();
15071                    for (key, mut value) in rows {
15072                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15073                            value.templates.extend(lsp_tasks.templates);
15074                        }
15075
15076                        editor.insert_tasks(key, value);
15077                    }
15078                    for (key, value) in lsp_tasks_by_rows {
15079                        editor.insert_tasks(key, value);
15080                    }
15081                })
15082                .ok();
15083        })
15084    }
15085    fn fetch_runnable_ranges(
15086        snapshot: &DisplaySnapshot,
15087        range: Range<Anchor>,
15088    ) -> Vec<language::RunnableRange> {
15089        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15090    }
15091
15092    fn runnable_rows(
15093        project: Entity<Project>,
15094        snapshot: DisplaySnapshot,
15095        prefer_lsp: bool,
15096        runnable_ranges: Vec<RunnableRange>,
15097        cx: AsyncWindowContext,
15098    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15099        cx.spawn(async move |cx| {
15100            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15101            for mut runnable in runnable_ranges {
15102                let Some(tasks) = cx
15103                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15104                    .ok()
15105                else {
15106                    continue;
15107                };
15108                let mut tasks = tasks.await;
15109
15110                if prefer_lsp {
15111                    tasks.retain(|(task_kind, _)| {
15112                        !matches!(task_kind, TaskSourceKind::Language { .. })
15113                    });
15114                }
15115                if tasks.is_empty() {
15116                    continue;
15117                }
15118
15119                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15120                let Some(row) = snapshot
15121                    .buffer_snapshot
15122                    .buffer_line_for_row(MultiBufferRow(point.row))
15123                    .map(|(_, range)| range.start.row)
15124                else {
15125                    continue;
15126                };
15127
15128                let context_range =
15129                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15130                runnable_rows.push((
15131                    (runnable.buffer_id, row),
15132                    RunnableTasks {
15133                        templates: tasks,
15134                        offset: snapshot
15135                            .buffer_snapshot
15136                            .anchor_before(runnable.run_range.start),
15137                        context_range,
15138                        column: point.column,
15139                        extra_variables: runnable.extra_captures,
15140                    },
15141                ));
15142            }
15143            runnable_rows
15144        })
15145    }
15146
15147    fn templates_with_tags(
15148        project: &Entity<Project>,
15149        runnable: &mut Runnable,
15150        cx: &mut App,
15151    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15152        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15153            let (worktree_id, file) = project
15154                .buffer_for_id(runnable.buffer, cx)
15155                .and_then(|buffer| buffer.read(cx).file())
15156                .map(|file| (file.worktree_id(cx), file.clone()))
15157                .unzip();
15158
15159            (
15160                project.task_store().read(cx).task_inventory().cloned(),
15161                worktree_id,
15162                file,
15163            )
15164        });
15165
15166        let tags = mem::take(&mut runnable.tags);
15167        let language = runnable.language.clone();
15168        cx.spawn(async move |cx| {
15169            let mut templates_with_tags = Vec::new();
15170            if let Some(inventory) = inventory {
15171                for RunnableTag(tag) in tags {
15172                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15173                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15174                    }) else {
15175                        return templates_with_tags;
15176                    };
15177                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15178                        move |(_, template)| {
15179                            template.tags.iter().any(|source_tag| source_tag == &tag)
15180                        },
15181                    ));
15182                }
15183            }
15184            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15185
15186            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15187                // Strongest source wins; if we have worktree tag binding, prefer that to
15188                // global and language bindings;
15189                // if we have a global binding, prefer that to language binding.
15190                let first_mismatch = templates_with_tags
15191                    .iter()
15192                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15193                if let Some(index) = first_mismatch {
15194                    templates_with_tags.truncate(index);
15195                }
15196            }
15197
15198            templates_with_tags
15199        })
15200    }
15201
15202    pub fn move_to_enclosing_bracket(
15203        &mut self,
15204        _: &MoveToEnclosingBracket,
15205        window: &mut Window,
15206        cx: &mut Context<Self>,
15207    ) {
15208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15209        self.change_selections(Default::default(), window, cx, |s| {
15210            s.move_offsets_with(|snapshot, selection| {
15211                let Some(enclosing_bracket_ranges) =
15212                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15213                else {
15214                    return;
15215                };
15216
15217                let mut best_length = usize::MAX;
15218                let mut best_inside = false;
15219                let mut best_in_bracket_range = false;
15220                let mut best_destination = None;
15221                for (open, close) in enclosing_bracket_ranges {
15222                    let close = close.to_inclusive();
15223                    let length = close.end() - open.start;
15224                    let inside = selection.start >= open.end && selection.end <= *close.start();
15225                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15226                        || close.contains(&selection.head());
15227
15228                    // If best is next to a bracket and current isn't, skip
15229                    if !in_bracket_range && best_in_bracket_range {
15230                        continue;
15231                    }
15232
15233                    // Prefer smaller lengths unless best is inside and current isn't
15234                    if length > best_length && (best_inside || !inside) {
15235                        continue;
15236                    }
15237
15238                    best_length = length;
15239                    best_inside = inside;
15240                    best_in_bracket_range = in_bracket_range;
15241                    best_destination = Some(
15242                        if close.contains(&selection.start) && close.contains(&selection.end) {
15243                            if inside { open.end } else { open.start }
15244                        } else if inside {
15245                            *close.start()
15246                        } else {
15247                            *close.end()
15248                        },
15249                    );
15250                }
15251
15252                if let Some(destination) = best_destination {
15253                    selection.collapse_to(destination, SelectionGoal::None);
15254                }
15255            })
15256        });
15257    }
15258
15259    pub fn undo_selection(
15260        &mut self,
15261        _: &UndoSelection,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15266        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15267            self.selection_history.mode = SelectionHistoryMode::Undoing;
15268            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15269                this.end_selection(window, cx);
15270                this.change_selections(
15271                    SelectionEffects::scroll(Autoscroll::newest()),
15272                    window,
15273                    cx,
15274                    |s| s.select_anchors(entry.selections.to_vec()),
15275                );
15276            });
15277            self.selection_history.mode = SelectionHistoryMode::Normal;
15278
15279            self.select_next_state = entry.select_next_state;
15280            self.select_prev_state = entry.select_prev_state;
15281            self.add_selections_state = entry.add_selections_state;
15282        }
15283    }
15284
15285    pub fn redo_selection(
15286        &mut self,
15287        _: &RedoSelection,
15288        window: &mut Window,
15289        cx: &mut Context<Self>,
15290    ) {
15291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15292        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15293            self.selection_history.mode = SelectionHistoryMode::Redoing;
15294            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15295                this.end_selection(window, cx);
15296                this.change_selections(
15297                    SelectionEffects::scroll(Autoscroll::newest()),
15298                    window,
15299                    cx,
15300                    |s| s.select_anchors(entry.selections.to_vec()),
15301                );
15302            });
15303            self.selection_history.mode = SelectionHistoryMode::Normal;
15304
15305            self.select_next_state = entry.select_next_state;
15306            self.select_prev_state = entry.select_prev_state;
15307            self.add_selections_state = entry.add_selections_state;
15308        }
15309    }
15310
15311    pub fn expand_excerpts(
15312        &mut self,
15313        action: &ExpandExcerpts,
15314        _: &mut Window,
15315        cx: &mut Context<Self>,
15316    ) {
15317        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15318    }
15319
15320    pub fn expand_excerpts_down(
15321        &mut self,
15322        action: &ExpandExcerptsDown,
15323        _: &mut Window,
15324        cx: &mut Context<Self>,
15325    ) {
15326        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15327    }
15328
15329    pub fn expand_excerpts_up(
15330        &mut self,
15331        action: &ExpandExcerptsUp,
15332        _: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) {
15335        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15336    }
15337
15338    pub fn expand_excerpts_for_direction(
15339        &mut self,
15340        lines: u32,
15341        direction: ExpandExcerptDirection,
15342
15343        cx: &mut Context<Self>,
15344    ) {
15345        let selections = self.selections.disjoint_anchors();
15346
15347        let lines = if lines == 0 {
15348            EditorSettings::get_global(cx).expand_excerpt_lines
15349        } else {
15350            lines
15351        };
15352
15353        self.buffer.update(cx, |buffer, cx| {
15354            let snapshot = buffer.snapshot(cx);
15355            let mut excerpt_ids = selections
15356                .iter()
15357                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15358                .collect::<Vec<_>>();
15359            excerpt_ids.sort();
15360            excerpt_ids.dedup();
15361            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15362        })
15363    }
15364
15365    pub fn expand_excerpt(
15366        &mut self,
15367        excerpt: ExcerptId,
15368        direction: ExpandExcerptDirection,
15369        window: &mut Window,
15370        cx: &mut Context<Self>,
15371    ) {
15372        let current_scroll_position = self.scroll_position(cx);
15373        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15374        let mut should_scroll_up = false;
15375
15376        if direction == ExpandExcerptDirection::Down {
15377            let multi_buffer = self.buffer.read(cx);
15378            let snapshot = multi_buffer.snapshot(cx);
15379            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15380                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15381                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15382            {
15383                let buffer_snapshot = buffer.read(cx).snapshot();
15384                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15385                let last_row = buffer_snapshot.max_point().row;
15386                let lines_below = last_row.saturating_sub(excerpt_end_row);
15387                should_scroll_up = lines_below >= lines_to_expand;
15388            }
15389        }
15390
15391        self.buffer.update(cx, |buffer, cx| {
15392            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15393        });
15394
15395        if should_scroll_up {
15396            let new_scroll_position =
15397                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15398            self.set_scroll_position(new_scroll_position, window, cx);
15399        }
15400    }
15401
15402    pub fn go_to_singleton_buffer_point(
15403        &mut self,
15404        point: Point,
15405        window: &mut Window,
15406        cx: &mut Context<Self>,
15407    ) {
15408        self.go_to_singleton_buffer_range(point..point, window, cx);
15409    }
15410
15411    pub fn go_to_singleton_buffer_range(
15412        &mut self,
15413        range: Range<Point>,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) {
15417        let multibuffer = self.buffer().read(cx);
15418        let Some(buffer) = multibuffer.as_singleton() else {
15419            return;
15420        };
15421        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15422            return;
15423        };
15424        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15425            return;
15426        };
15427        self.change_selections(
15428            SelectionEffects::default().nav_history(true),
15429            window,
15430            cx,
15431            |s| s.select_anchor_ranges([start..end]),
15432        );
15433    }
15434
15435    pub fn go_to_diagnostic(
15436        &mut self,
15437        action: &GoToDiagnostic,
15438        window: &mut Window,
15439        cx: &mut Context<Self>,
15440    ) {
15441        if !self.diagnostics_enabled() {
15442            return;
15443        }
15444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15445        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15446    }
15447
15448    pub fn go_to_prev_diagnostic(
15449        &mut self,
15450        action: &GoToPreviousDiagnostic,
15451        window: &mut Window,
15452        cx: &mut Context<Self>,
15453    ) {
15454        if !self.diagnostics_enabled() {
15455            return;
15456        }
15457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15458        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15459    }
15460
15461    pub fn go_to_diagnostic_impl(
15462        &mut self,
15463        direction: Direction,
15464        severity: GoToDiagnosticSeverityFilter,
15465        window: &mut Window,
15466        cx: &mut Context<Self>,
15467    ) {
15468        let buffer = self.buffer.read(cx).snapshot(cx);
15469        let selection = self.selections.newest::<usize>(cx);
15470
15471        let mut active_group_id = None;
15472        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15473            && active_group.active_range.start.to_offset(&buffer) == selection.start
15474        {
15475            active_group_id = Some(active_group.group_id);
15476        }
15477
15478        fn filtered(
15479            snapshot: EditorSnapshot,
15480            severity: GoToDiagnosticSeverityFilter,
15481            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15482        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15483            diagnostics
15484                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15485                .filter(|entry| entry.range.start != entry.range.end)
15486                .filter(|entry| !entry.diagnostic.is_unnecessary)
15487                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15488        }
15489
15490        let snapshot = self.snapshot(window, cx);
15491        let before = filtered(
15492            snapshot.clone(),
15493            severity,
15494            buffer
15495                .diagnostics_in_range(0..selection.start)
15496                .filter(|entry| entry.range.start <= selection.start),
15497        );
15498        let after = filtered(
15499            snapshot,
15500            severity,
15501            buffer
15502                .diagnostics_in_range(selection.start..buffer.len())
15503                .filter(|entry| entry.range.start >= selection.start),
15504        );
15505
15506        let mut found: Option<DiagnosticEntry<usize>> = None;
15507        if direction == Direction::Prev {
15508            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15509            {
15510                for diagnostic in prev_diagnostics.into_iter().rev() {
15511                    if diagnostic.range.start != selection.start
15512                        || active_group_id
15513                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15514                    {
15515                        found = Some(diagnostic);
15516                        break 'outer;
15517                    }
15518                }
15519            }
15520        } else {
15521            for diagnostic in after.chain(before) {
15522                if diagnostic.range.start != selection.start
15523                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15524                {
15525                    found = Some(diagnostic);
15526                    break;
15527                }
15528            }
15529        }
15530        let Some(next_diagnostic) = found else {
15531            return;
15532        };
15533
15534        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15535        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15536            return;
15537        };
15538        self.change_selections(Default::default(), window, cx, |s| {
15539            s.select_ranges(vec![
15540                next_diagnostic.range.start..next_diagnostic.range.start,
15541            ])
15542        });
15543        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15544        self.refresh_edit_prediction(false, true, window, cx);
15545    }
15546
15547    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15549        let snapshot = self.snapshot(window, cx);
15550        let selection = self.selections.newest::<Point>(cx);
15551        self.go_to_hunk_before_or_after_position(
15552            &snapshot,
15553            selection.head(),
15554            Direction::Next,
15555            window,
15556            cx,
15557        );
15558    }
15559
15560    pub fn go_to_hunk_before_or_after_position(
15561        &mut self,
15562        snapshot: &EditorSnapshot,
15563        position: Point,
15564        direction: Direction,
15565        window: &mut Window,
15566        cx: &mut Context<Editor>,
15567    ) {
15568        let row = if direction == Direction::Next {
15569            self.hunk_after_position(snapshot, position)
15570                .map(|hunk| hunk.row_range.start)
15571        } else {
15572            self.hunk_before_position(snapshot, position)
15573        };
15574
15575        if let Some(row) = row {
15576            let destination = Point::new(row.0, 0);
15577            let autoscroll = Autoscroll::center();
15578
15579            self.unfold_ranges(&[destination..destination], false, false, cx);
15580            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15581                s.select_ranges([destination..destination]);
15582            });
15583        }
15584    }
15585
15586    fn hunk_after_position(
15587        &mut self,
15588        snapshot: &EditorSnapshot,
15589        position: Point,
15590    ) -> Option<MultiBufferDiffHunk> {
15591        snapshot
15592            .buffer_snapshot
15593            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15594            .find(|hunk| hunk.row_range.start.0 > position.row)
15595            .or_else(|| {
15596                snapshot
15597                    .buffer_snapshot
15598                    .diff_hunks_in_range(Point::zero()..position)
15599                    .find(|hunk| hunk.row_range.end.0 < position.row)
15600            })
15601    }
15602
15603    fn go_to_prev_hunk(
15604        &mut self,
15605        _: &GoToPreviousHunk,
15606        window: &mut Window,
15607        cx: &mut Context<Self>,
15608    ) {
15609        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15610        let snapshot = self.snapshot(window, cx);
15611        let selection = self.selections.newest::<Point>(cx);
15612        self.go_to_hunk_before_or_after_position(
15613            &snapshot,
15614            selection.head(),
15615            Direction::Prev,
15616            window,
15617            cx,
15618        );
15619    }
15620
15621    fn hunk_before_position(
15622        &mut self,
15623        snapshot: &EditorSnapshot,
15624        position: Point,
15625    ) -> Option<MultiBufferRow> {
15626        snapshot
15627            .buffer_snapshot
15628            .diff_hunk_before(position)
15629            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15630    }
15631
15632    fn go_to_next_change(
15633        &mut self,
15634        _: &GoToNextChange,
15635        window: &mut Window,
15636        cx: &mut Context<Self>,
15637    ) {
15638        if let Some(selections) = self
15639            .change_list
15640            .next_change(1, Direction::Next)
15641            .map(|s| s.to_vec())
15642        {
15643            self.change_selections(Default::default(), window, cx, |s| {
15644                let map = s.display_map();
15645                s.select_display_ranges(selections.iter().map(|a| {
15646                    let point = a.to_display_point(&map);
15647                    point..point
15648                }))
15649            })
15650        }
15651    }
15652
15653    fn go_to_previous_change(
15654        &mut self,
15655        _: &GoToPreviousChange,
15656        window: &mut Window,
15657        cx: &mut Context<Self>,
15658    ) {
15659        if let Some(selections) = self
15660            .change_list
15661            .next_change(1, Direction::Prev)
15662            .map(|s| s.to_vec())
15663        {
15664            self.change_selections(Default::default(), window, cx, |s| {
15665                let map = s.display_map();
15666                s.select_display_ranges(selections.iter().map(|a| {
15667                    let point = a.to_display_point(&map);
15668                    point..point
15669                }))
15670            })
15671        }
15672    }
15673
15674    fn go_to_line<T: 'static>(
15675        &mut self,
15676        position: Anchor,
15677        highlight_color: Option<Hsla>,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) {
15681        let snapshot = self.snapshot(window, cx).display_snapshot;
15682        let position = position.to_point(&snapshot.buffer_snapshot);
15683        let start = snapshot
15684            .buffer_snapshot
15685            .clip_point(Point::new(position.row, 0), Bias::Left);
15686        let end = start + Point::new(1, 0);
15687        let start = snapshot.buffer_snapshot.anchor_before(start);
15688        let end = snapshot.buffer_snapshot.anchor_before(end);
15689
15690        self.highlight_rows::<T>(
15691            start..end,
15692            highlight_color
15693                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15694            Default::default(),
15695            cx,
15696        );
15697
15698        if self.buffer.read(cx).is_singleton() {
15699            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15700        }
15701    }
15702
15703    pub fn go_to_definition(
15704        &mut self,
15705        _: &GoToDefinition,
15706        window: &mut Window,
15707        cx: &mut Context<Self>,
15708    ) -> Task<Result<Navigated>> {
15709        let definition =
15710            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15711        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15712        cx.spawn_in(window, async move |editor, cx| {
15713            if definition.await? == Navigated::Yes {
15714                return Ok(Navigated::Yes);
15715            }
15716            match fallback_strategy {
15717                GoToDefinitionFallback::None => Ok(Navigated::No),
15718                GoToDefinitionFallback::FindAllReferences => {
15719                    match editor.update_in(cx, |editor, window, cx| {
15720                        editor.find_all_references(&FindAllReferences, window, cx)
15721                    })? {
15722                        Some(references) => references.await,
15723                        None => Ok(Navigated::No),
15724                    }
15725                }
15726            }
15727        })
15728    }
15729
15730    pub fn go_to_declaration(
15731        &mut self,
15732        _: &GoToDeclaration,
15733        window: &mut Window,
15734        cx: &mut Context<Self>,
15735    ) -> Task<Result<Navigated>> {
15736        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15737    }
15738
15739    pub fn go_to_declaration_split(
15740        &mut self,
15741        _: &GoToDeclaration,
15742        window: &mut Window,
15743        cx: &mut Context<Self>,
15744    ) -> Task<Result<Navigated>> {
15745        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15746    }
15747
15748    pub fn go_to_implementation(
15749        &mut self,
15750        _: &GoToImplementation,
15751        window: &mut Window,
15752        cx: &mut Context<Self>,
15753    ) -> Task<Result<Navigated>> {
15754        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15755    }
15756
15757    pub fn go_to_implementation_split(
15758        &mut self,
15759        _: &GoToImplementationSplit,
15760        window: &mut Window,
15761        cx: &mut Context<Self>,
15762    ) -> Task<Result<Navigated>> {
15763        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15764    }
15765
15766    pub fn go_to_type_definition(
15767        &mut self,
15768        _: &GoToTypeDefinition,
15769        window: &mut Window,
15770        cx: &mut Context<Self>,
15771    ) -> Task<Result<Navigated>> {
15772        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15773    }
15774
15775    pub fn go_to_definition_split(
15776        &mut self,
15777        _: &GoToDefinitionSplit,
15778        window: &mut Window,
15779        cx: &mut Context<Self>,
15780    ) -> Task<Result<Navigated>> {
15781        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15782    }
15783
15784    pub fn go_to_type_definition_split(
15785        &mut self,
15786        _: &GoToTypeDefinitionSplit,
15787        window: &mut Window,
15788        cx: &mut Context<Self>,
15789    ) -> Task<Result<Navigated>> {
15790        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15791    }
15792
15793    fn go_to_definition_of_kind(
15794        &mut self,
15795        kind: GotoDefinitionKind,
15796        split: bool,
15797        window: &mut Window,
15798        cx: &mut Context<Self>,
15799    ) -> Task<Result<Navigated>> {
15800        let Some(provider) = self.semantics_provider.clone() else {
15801            return Task::ready(Ok(Navigated::No));
15802        };
15803        let head = self.selections.newest::<usize>(cx).head();
15804        let buffer = self.buffer.read(cx);
15805        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15806            return Task::ready(Ok(Navigated::No));
15807        };
15808        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15809            return Task::ready(Ok(Navigated::No));
15810        };
15811
15812        cx.spawn_in(window, async move |editor, cx| {
15813            let Some(definitions) = definitions.await? else {
15814                return Ok(Navigated::No);
15815            };
15816            let navigated = editor
15817                .update_in(cx, |editor, window, cx| {
15818                    editor.navigate_to_hover_links(
15819                        Some(kind),
15820                        definitions
15821                            .into_iter()
15822                            .filter(|location| {
15823                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15824                            })
15825                            .map(HoverLink::Text)
15826                            .collect::<Vec<_>>(),
15827                        split,
15828                        window,
15829                        cx,
15830                    )
15831                })?
15832                .await?;
15833            anyhow::Ok(navigated)
15834        })
15835    }
15836
15837    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15838        let selection = self.selections.newest_anchor();
15839        let head = selection.head();
15840        let tail = selection.tail();
15841
15842        let Some((buffer, start_position)) =
15843            self.buffer.read(cx).text_anchor_for_position(head, cx)
15844        else {
15845            return;
15846        };
15847
15848        let end_position = if head != tail {
15849            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15850                return;
15851            };
15852            Some(pos)
15853        } else {
15854            None
15855        };
15856
15857        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15858            let url = if let Some(end_pos) = end_position {
15859                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15860            } else {
15861                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15862            };
15863
15864            if let Some(url) = url {
15865                editor.update(cx, |_, cx| {
15866                    cx.open_url(&url);
15867                })
15868            } else {
15869                Ok(())
15870            }
15871        });
15872
15873        url_finder.detach();
15874    }
15875
15876    pub fn open_selected_filename(
15877        &mut self,
15878        _: &OpenSelectedFilename,
15879        window: &mut Window,
15880        cx: &mut Context<Self>,
15881    ) {
15882        let Some(workspace) = self.workspace() else {
15883            return;
15884        };
15885
15886        let position = self.selections.newest_anchor().head();
15887
15888        let Some((buffer, buffer_position)) =
15889            self.buffer.read(cx).text_anchor_for_position(position, cx)
15890        else {
15891            return;
15892        };
15893
15894        let project = self.project.clone();
15895
15896        cx.spawn_in(window, async move |_, cx| {
15897            let result = find_file(&buffer, project, buffer_position, cx).await;
15898
15899            if let Some((_, path)) = result {
15900                workspace
15901                    .update_in(cx, |workspace, window, cx| {
15902                        workspace.open_resolved_path(path, window, cx)
15903                    })?
15904                    .await?;
15905            }
15906            anyhow::Ok(())
15907        })
15908        .detach();
15909    }
15910
15911    pub(crate) fn navigate_to_hover_links(
15912        &mut self,
15913        kind: Option<GotoDefinitionKind>,
15914        definitions: Vec<HoverLink>,
15915        split: bool,
15916        window: &mut Window,
15917        cx: &mut Context<Editor>,
15918    ) -> Task<Result<Navigated>> {
15919        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15920        let mut first_url_or_file = None;
15921        let definitions: Vec<_> = definitions
15922            .into_iter()
15923            .filter_map(|def| match def {
15924                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15925                HoverLink::InlayHint(lsp_location, server_id) => {
15926                    let computation =
15927                        self.compute_target_location(lsp_location, server_id, window, cx);
15928                    Some(cx.background_spawn(computation))
15929                }
15930                HoverLink::Url(url) => {
15931                    first_url_or_file = Some(Either::Left(url));
15932                    None
15933                }
15934                HoverLink::File(path) => {
15935                    first_url_or_file = Some(Either::Right(path));
15936                    None
15937                }
15938            })
15939            .collect();
15940
15941        let workspace = self.workspace();
15942
15943        cx.spawn_in(window, async move |editor, acx| {
15944            let mut locations: Vec<Location> = future::join_all(definitions)
15945                .await
15946                .into_iter()
15947                .filter_map(|location| location.transpose())
15948                .collect::<Result<_>>()
15949                .context("location tasks")?;
15950
15951            if locations.len() > 1 {
15952                let Some(workspace) = workspace else {
15953                    return Ok(Navigated::No);
15954                };
15955
15956                let tab_kind = match kind {
15957                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15958                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15959                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15960                    Some(GotoDefinitionKind::Type) => "Types",
15961                };
15962                let title = editor
15963                    .update_in(acx, |_, _, cx| {
15964                        let target = locations
15965                            .iter()
15966                            .map(|location| {
15967                                location
15968                                    .buffer
15969                                    .read(cx)
15970                                    .text_for_range(location.range.clone())
15971                                    .collect::<String>()
15972                            })
15973                            .filter(|text| !text.contains('\n'))
15974                            .unique()
15975                            .take(3)
15976                            .join(", ");
15977                        if target.is_empty() {
15978                            tab_kind.to_owned()
15979                        } else {
15980                            format!("{tab_kind} for {target}")
15981                        }
15982                    })
15983                    .context("buffer title")?;
15984
15985                let opened = workspace
15986                    .update_in(acx, |workspace, window, cx| {
15987                        Self::open_locations_in_multibuffer(
15988                            workspace,
15989                            locations,
15990                            title,
15991                            split,
15992                            MultibufferSelectionMode::First,
15993                            window,
15994                            cx,
15995                        )
15996                    })
15997                    .is_ok();
15998
15999                anyhow::Ok(Navigated::from_bool(opened))
16000            } else if locations.is_empty() {
16001                // If there is one definition, just open it directly
16002                match first_url_or_file {
16003                    Some(Either::Left(url)) => {
16004                        acx.update(|_, cx| cx.open_url(&url))?;
16005                        Ok(Navigated::Yes)
16006                    }
16007                    Some(Either::Right(path)) => {
16008                        let Some(workspace) = workspace else {
16009                            return Ok(Navigated::No);
16010                        };
16011
16012                        workspace
16013                            .update_in(acx, |workspace, window, cx| {
16014                                workspace.open_resolved_path(path, window, cx)
16015                            })?
16016                            .await?;
16017                        Ok(Navigated::Yes)
16018                    }
16019                    None => Ok(Navigated::No),
16020                }
16021            } else {
16022                let Some(workspace) = workspace else {
16023                    return Ok(Navigated::No);
16024                };
16025
16026                let target = locations.pop().unwrap();
16027                editor.update_in(acx, |editor, window, cx| {
16028                    let pane = workspace.read(cx).active_pane().clone();
16029
16030                    let range = target.range.to_point(target.buffer.read(cx));
16031                    let range = editor.range_for_match(&range);
16032                    let range = collapse_multiline_range(range);
16033
16034                    if !split
16035                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16036                    {
16037                        editor.go_to_singleton_buffer_range(range, window, cx);
16038                    } else {
16039                        window.defer(cx, move |window, cx| {
16040                            let target_editor: Entity<Self> =
16041                                workspace.update(cx, |workspace, cx| {
16042                                    let pane = if split {
16043                                        workspace.adjacent_pane(window, cx)
16044                                    } else {
16045                                        workspace.active_pane().clone()
16046                                    };
16047
16048                                    workspace.open_project_item(
16049                                        pane,
16050                                        target.buffer.clone(),
16051                                        true,
16052                                        true,
16053                                        window,
16054                                        cx,
16055                                    )
16056                                });
16057                            target_editor.update(cx, |target_editor, cx| {
16058                                // When selecting a definition in a different buffer, disable the nav history
16059                                // to avoid creating a history entry at the previous cursor location.
16060                                pane.update(cx, |pane, _| pane.disable_history());
16061                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16062                                pane.update(cx, |pane, _| pane.enable_history());
16063                            });
16064                        });
16065                    }
16066                    Navigated::Yes
16067                })
16068            }
16069        })
16070    }
16071
16072    fn compute_target_location(
16073        &self,
16074        lsp_location: lsp::Location,
16075        server_id: LanguageServerId,
16076        window: &mut Window,
16077        cx: &mut Context<Self>,
16078    ) -> Task<anyhow::Result<Option<Location>>> {
16079        let Some(project) = self.project.clone() else {
16080            return Task::ready(Ok(None));
16081        };
16082
16083        cx.spawn_in(window, async move |editor, cx| {
16084            let location_task = editor.update(cx, |_, cx| {
16085                project.update(cx, |project, cx| {
16086                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16087                })
16088            })?;
16089            let location = Some({
16090                let target_buffer_handle = location_task.await.context("open local buffer")?;
16091                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16092                    let target_start = target_buffer
16093                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16094                    let target_end = target_buffer
16095                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16096                    target_buffer.anchor_after(target_start)
16097                        ..target_buffer.anchor_before(target_end)
16098                })?;
16099                Location {
16100                    buffer: target_buffer_handle,
16101                    range,
16102                }
16103            });
16104            Ok(location)
16105        })
16106    }
16107
16108    pub fn find_all_references(
16109        &mut self,
16110        _: &FindAllReferences,
16111        window: &mut Window,
16112        cx: &mut Context<Self>,
16113    ) -> Option<Task<Result<Navigated>>> {
16114        let selection = self.selections.newest::<usize>(cx);
16115        let multi_buffer = self.buffer.read(cx);
16116        let head = selection.head();
16117
16118        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16119        let head_anchor = multi_buffer_snapshot.anchor_at(
16120            head,
16121            if head < selection.tail() {
16122                Bias::Right
16123            } else {
16124                Bias::Left
16125            },
16126        );
16127
16128        match self
16129            .find_all_references_task_sources
16130            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16131        {
16132            Ok(_) => {
16133                log::info!(
16134                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16135                );
16136                return None;
16137            }
16138            Err(i) => {
16139                self.find_all_references_task_sources.insert(i, head_anchor);
16140            }
16141        }
16142
16143        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16144        let workspace = self.workspace()?;
16145        let project = workspace.read(cx).project().clone();
16146        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16147        Some(cx.spawn_in(window, async move |editor, cx| {
16148            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16149                if let Ok(i) = editor
16150                    .find_all_references_task_sources
16151                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16152                {
16153                    editor.find_all_references_task_sources.remove(i);
16154                }
16155            });
16156
16157            let Some(locations) = references.await? else {
16158                return anyhow::Ok(Navigated::No);
16159            };
16160            if locations.is_empty() {
16161                return anyhow::Ok(Navigated::No);
16162            }
16163
16164            workspace.update_in(cx, |workspace, window, cx| {
16165                let target = locations
16166                    .iter()
16167                    .map(|location| {
16168                        location
16169                            .buffer
16170                            .read(cx)
16171                            .text_for_range(location.range.clone())
16172                            .collect::<String>()
16173                    })
16174                    .filter(|text| !text.contains('\n'))
16175                    .unique()
16176                    .take(3)
16177                    .join(", ");
16178                let title = if target.is_empty() {
16179                    "References".to_owned()
16180                } else {
16181                    format!("References to {target}")
16182                };
16183                Self::open_locations_in_multibuffer(
16184                    workspace,
16185                    locations,
16186                    title,
16187                    false,
16188                    MultibufferSelectionMode::First,
16189                    window,
16190                    cx,
16191                );
16192                Navigated::Yes
16193            })
16194        }))
16195    }
16196
16197    /// Opens a multibuffer with the given project locations in it
16198    pub fn open_locations_in_multibuffer(
16199        workspace: &mut Workspace,
16200        mut locations: Vec<Location>,
16201        title: String,
16202        split: bool,
16203        multibuffer_selection_mode: MultibufferSelectionMode,
16204        window: &mut Window,
16205        cx: &mut Context<Workspace>,
16206    ) {
16207        if locations.is_empty() {
16208            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16209            return;
16210        }
16211
16212        // If there are multiple definitions, open them in a multibuffer
16213        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16214        let mut locations = locations.into_iter().peekable();
16215        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16216        let capability = workspace.project().read(cx).capability();
16217
16218        let excerpt_buffer = cx.new(|cx| {
16219            let mut multibuffer = MultiBuffer::new(capability);
16220            while let Some(location) = locations.next() {
16221                let buffer = location.buffer.read(cx);
16222                let mut ranges_for_buffer = Vec::new();
16223                let range = location.range.to_point(buffer);
16224                ranges_for_buffer.push(range.clone());
16225
16226                while let Some(next_location) = locations.peek() {
16227                    if next_location.buffer == location.buffer {
16228                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16229                        locations.next();
16230                    } else {
16231                        break;
16232                    }
16233                }
16234
16235                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16236                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16237                    PathKey::for_buffer(&location.buffer, cx),
16238                    location.buffer.clone(),
16239                    ranges_for_buffer,
16240                    DEFAULT_MULTIBUFFER_CONTEXT,
16241                    cx,
16242                );
16243                ranges.extend(new_ranges)
16244            }
16245
16246            multibuffer.with_title(title)
16247        });
16248
16249        let editor = cx.new(|cx| {
16250            Editor::for_multibuffer(
16251                excerpt_buffer,
16252                Some(workspace.project().clone()),
16253                window,
16254                cx,
16255            )
16256        });
16257        editor.update(cx, |editor, cx| {
16258            match multibuffer_selection_mode {
16259                MultibufferSelectionMode::First => {
16260                    if let Some(first_range) = ranges.first() {
16261                        editor.change_selections(
16262                            SelectionEffects::no_scroll(),
16263                            window,
16264                            cx,
16265                            |selections| {
16266                                selections.clear_disjoint();
16267                                selections
16268                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16269                            },
16270                        );
16271                    }
16272                    editor.highlight_background::<Self>(
16273                        &ranges,
16274                        |theme| theme.colors().editor_highlighted_line_background,
16275                        cx,
16276                    );
16277                }
16278                MultibufferSelectionMode::All => {
16279                    editor.change_selections(
16280                        SelectionEffects::no_scroll(),
16281                        window,
16282                        cx,
16283                        |selections| {
16284                            selections.clear_disjoint();
16285                            selections.select_anchor_ranges(ranges);
16286                        },
16287                    );
16288                }
16289            }
16290            editor.register_buffers_with_language_servers(cx);
16291        });
16292
16293        let item = Box::new(editor);
16294        let item_id = item.item_id();
16295
16296        if split {
16297            workspace.split_item(SplitDirection::Right, item, window, cx);
16298        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16299            let (preview_item_id, preview_item_idx) =
16300                workspace.active_pane().read_with(cx, |pane, _| {
16301                    (pane.preview_item_id(), pane.preview_item_idx())
16302                });
16303
16304            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16305
16306            if let Some(preview_item_id) = preview_item_id {
16307                workspace.active_pane().update(cx, |pane, cx| {
16308                    pane.remove_item(preview_item_id, false, false, window, cx);
16309                });
16310            }
16311        } else {
16312            workspace.add_item_to_active_pane(item, None, true, window, cx);
16313        }
16314        workspace.active_pane().update(cx, |pane, cx| {
16315            pane.set_preview_item_id(Some(item_id), cx);
16316        });
16317    }
16318
16319    pub fn rename(
16320        &mut self,
16321        _: &Rename,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) -> Option<Task<Result<()>>> {
16325        use language::ToOffset as _;
16326
16327        let provider = self.semantics_provider.clone()?;
16328        let selection = self.selections.newest_anchor().clone();
16329        let (cursor_buffer, cursor_buffer_position) = self
16330            .buffer
16331            .read(cx)
16332            .text_anchor_for_position(selection.head(), cx)?;
16333        let (tail_buffer, cursor_buffer_position_end) = self
16334            .buffer
16335            .read(cx)
16336            .text_anchor_for_position(selection.tail(), cx)?;
16337        if tail_buffer != cursor_buffer {
16338            return None;
16339        }
16340
16341        let snapshot = cursor_buffer.read(cx).snapshot();
16342        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16343        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16344        let prepare_rename = provider
16345            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16346            .unwrap_or_else(|| Task::ready(Ok(None)));
16347        drop(snapshot);
16348
16349        Some(cx.spawn_in(window, async move |this, cx| {
16350            let rename_range = if let Some(range) = prepare_rename.await? {
16351                Some(range)
16352            } else {
16353                this.update(cx, |this, cx| {
16354                    let buffer = this.buffer.read(cx).snapshot(cx);
16355                    let mut buffer_highlights = this
16356                        .document_highlights_for_position(selection.head(), &buffer)
16357                        .filter(|highlight| {
16358                            highlight.start.excerpt_id == selection.head().excerpt_id
16359                                && highlight.end.excerpt_id == selection.head().excerpt_id
16360                        });
16361                    buffer_highlights
16362                        .next()
16363                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16364                })?
16365            };
16366            if let Some(rename_range) = rename_range {
16367                this.update_in(cx, |this, window, cx| {
16368                    let snapshot = cursor_buffer.read(cx).snapshot();
16369                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16370                    let cursor_offset_in_rename_range =
16371                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16372                    let cursor_offset_in_rename_range_end =
16373                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16374
16375                    this.take_rename(false, window, cx);
16376                    let buffer = this.buffer.read(cx).read(cx);
16377                    let cursor_offset = selection.head().to_offset(&buffer);
16378                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16379                    let rename_end = rename_start + rename_buffer_range.len();
16380                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16381                    let mut old_highlight_id = None;
16382                    let old_name: Arc<str> = buffer
16383                        .chunks(rename_start..rename_end, true)
16384                        .map(|chunk| {
16385                            if old_highlight_id.is_none() {
16386                                old_highlight_id = chunk.syntax_highlight_id;
16387                            }
16388                            chunk.text
16389                        })
16390                        .collect::<String>()
16391                        .into();
16392
16393                    drop(buffer);
16394
16395                    // Position the selection in the rename editor so that it matches the current selection.
16396                    this.show_local_selections = false;
16397                    let rename_editor = cx.new(|cx| {
16398                        let mut editor = Editor::single_line(window, cx);
16399                        editor.buffer.update(cx, |buffer, cx| {
16400                            buffer.edit([(0..0, old_name.clone())], None, cx)
16401                        });
16402                        let rename_selection_range = match cursor_offset_in_rename_range
16403                            .cmp(&cursor_offset_in_rename_range_end)
16404                        {
16405                            Ordering::Equal => {
16406                                editor.select_all(&SelectAll, window, cx);
16407                                return editor;
16408                            }
16409                            Ordering::Less => {
16410                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16411                            }
16412                            Ordering::Greater => {
16413                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16414                            }
16415                        };
16416                        if rename_selection_range.end > old_name.len() {
16417                            editor.select_all(&SelectAll, window, cx);
16418                        } else {
16419                            editor.change_selections(Default::default(), window, cx, |s| {
16420                                s.select_ranges([rename_selection_range]);
16421                            });
16422                        }
16423                        editor
16424                    });
16425                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16426                        if e == &EditorEvent::Focused {
16427                            cx.emit(EditorEvent::FocusedIn)
16428                        }
16429                    })
16430                    .detach();
16431
16432                    let write_highlights =
16433                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16434                    let read_highlights =
16435                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16436                    let ranges = write_highlights
16437                        .iter()
16438                        .flat_map(|(_, ranges)| ranges.iter())
16439                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16440                        .cloned()
16441                        .collect();
16442
16443                    this.highlight_text::<Rename>(
16444                        ranges,
16445                        HighlightStyle {
16446                            fade_out: Some(0.6),
16447                            ..Default::default()
16448                        },
16449                        cx,
16450                    );
16451                    let rename_focus_handle = rename_editor.focus_handle(cx);
16452                    window.focus(&rename_focus_handle);
16453                    let block_id = this.insert_blocks(
16454                        [BlockProperties {
16455                            style: BlockStyle::Flex,
16456                            placement: BlockPlacement::Below(range.start),
16457                            height: Some(1),
16458                            render: Arc::new({
16459                                let rename_editor = rename_editor.clone();
16460                                move |cx: &mut BlockContext| {
16461                                    let mut text_style = cx.editor_style.text.clone();
16462                                    if let Some(highlight_style) = old_highlight_id
16463                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16464                                    {
16465                                        text_style = text_style.highlight(highlight_style);
16466                                    }
16467                                    div()
16468                                        .block_mouse_except_scroll()
16469                                        .pl(cx.anchor_x)
16470                                        .child(EditorElement::new(
16471                                            &rename_editor,
16472                                            EditorStyle {
16473                                                background: cx.theme().system().transparent,
16474                                                local_player: cx.editor_style.local_player,
16475                                                text: text_style,
16476                                                scrollbar_width: cx.editor_style.scrollbar_width,
16477                                                syntax: cx.editor_style.syntax.clone(),
16478                                                status: cx.editor_style.status.clone(),
16479                                                inlay_hints_style: HighlightStyle {
16480                                                    font_weight: Some(FontWeight::BOLD),
16481                                                    ..make_inlay_hints_style(cx.app)
16482                                                },
16483                                                edit_prediction_styles: make_suggestion_styles(
16484                                                    cx.app,
16485                                                ),
16486                                                ..EditorStyle::default()
16487                                            },
16488                                        ))
16489                                        .into_any_element()
16490                                }
16491                            }),
16492                            priority: 0,
16493                        }],
16494                        Some(Autoscroll::fit()),
16495                        cx,
16496                    )[0];
16497                    this.pending_rename = Some(RenameState {
16498                        range,
16499                        old_name,
16500                        editor: rename_editor,
16501                        block_id,
16502                    });
16503                })?;
16504            }
16505
16506            Ok(())
16507        }))
16508    }
16509
16510    pub fn confirm_rename(
16511        &mut self,
16512        _: &ConfirmRename,
16513        window: &mut Window,
16514        cx: &mut Context<Self>,
16515    ) -> Option<Task<Result<()>>> {
16516        let rename = self.take_rename(false, window, cx)?;
16517        let workspace = self.workspace()?.downgrade();
16518        let (buffer, start) = self
16519            .buffer
16520            .read(cx)
16521            .text_anchor_for_position(rename.range.start, cx)?;
16522        let (end_buffer, _) = self
16523            .buffer
16524            .read(cx)
16525            .text_anchor_for_position(rename.range.end, cx)?;
16526        if buffer != end_buffer {
16527            return None;
16528        }
16529
16530        let old_name = rename.old_name;
16531        let new_name = rename.editor.read(cx).text(cx);
16532
16533        let rename = self.semantics_provider.as_ref()?.perform_rename(
16534            &buffer,
16535            start,
16536            new_name.clone(),
16537            cx,
16538        )?;
16539
16540        Some(cx.spawn_in(window, async move |editor, cx| {
16541            let project_transaction = rename.await?;
16542            Self::open_project_transaction(
16543                &editor,
16544                workspace,
16545                project_transaction,
16546                format!("Rename: {}{}", old_name, new_name),
16547                cx,
16548            )
16549            .await?;
16550
16551            editor.update(cx, |editor, cx| {
16552                editor.refresh_document_highlights(cx);
16553            })?;
16554            Ok(())
16555        }))
16556    }
16557
16558    fn take_rename(
16559        &mut self,
16560        moving_cursor: bool,
16561        window: &mut Window,
16562        cx: &mut Context<Self>,
16563    ) -> Option<RenameState> {
16564        let rename = self.pending_rename.take()?;
16565        if rename.editor.focus_handle(cx).is_focused(window) {
16566            window.focus(&self.focus_handle);
16567        }
16568
16569        self.remove_blocks(
16570            [rename.block_id].into_iter().collect(),
16571            Some(Autoscroll::fit()),
16572            cx,
16573        );
16574        self.clear_highlights::<Rename>(cx);
16575        self.show_local_selections = true;
16576
16577        if moving_cursor {
16578            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16579                editor.selections.newest::<usize>(cx).head()
16580            });
16581
16582            // Update the selection to match the position of the selection inside
16583            // the rename editor.
16584            let snapshot = self.buffer.read(cx).read(cx);
16585            let rename_range = rename.range.to_offset(&snapshot);
16586            let cursor_in_editor = snapshot
16587                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16588                .min(rename_range.end);
16589            drop(snapshot);
16590
16591            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16592                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16593            });
16594        } else {
16595            self.refresh_document_highlights(cx);
16596        }
16597
16598        Some(rename)
16599    }
16600
16601    pub fn pending_rename(&self) -> Option<&RenameState> {
16602        self.pending_rename.as_ref()
16603    }
16604
16605    fn format(
16606        &mut self,
16607        _: &Format,
16608        window: &mut Window,
16609        cx: &mut Context<Self>,
16610    ) -> Option<Task<Result<()>>> {
16611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16612
16613        let project = match &self.project {
16614            Some(project) => project.clone(),
16615            None => return None,
16616        };
16617
16618        Some(self.perform_format(
16619            project,
16620            FormatTrigger::Manual,
16621            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16622            window,
16623            cx,
16624        ))
16625    }
16626
16627    fn format_selections(
16628        &mut self,
16629        _: &FormatSelections,
16630        window: &mut Window,
16631        cx: &mut Context<Self>,
16632    ) -> Option<Task<Result<()>>> {
16633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16634
16635        let project = match &self.project {
16636            Some(project) => project.clone(),
16637            None => return None,
16638        };
16639
16640        let ranges = self
16641            .selections
16642            .all_adjusted(cx)
16643            .into_iter()
16644            .map(|selection| selection.range())
16645            .collect_vec();
16646
16647        Some(self.perform_format(
16648            project,
16649            FormatTrigger::Manual,
16650            FormatTarget::Ranges(ranges),
16651            window,
16652            cx,
16653        ))
16654    }
16655
16656    fn perform_format(
16657        &mut self,
16658        project: Entity<Project>,
16659        trigger: FormatTrigger,
16660        target: FormatTarget,
16661        window: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) -> Task<Result<()>> {
16664        let buffer = self.buffer.clone();
16665        let (buffers, target) = match target {
16666            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16667            FormatTarget::Ranges(selection_ranges) => {
16668                let multi_buffer = buffer.read(cx);
16669                let snapshot = multi_buffer.read(cx);
16670                let mut buffers = HashSet::default();
16671                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16672                    BTreeMap::new();
16673                for selection_range in selection_ranges {
16674                    for (buffer, buffer_range, _) in
16675                        snapshot.range_to_buffer_ranges(selection_range)
16676                    {
16677                        let buffer_id = buffer.remote_id();
16678                        let start = buffer.anchor_before(buffer_range.start);
16679                        let end = buffer.anchor_after(buffer_range.end);
16680                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16681                        buffer_id_to_ranges
16682                            .entry(buffer_id)
16683                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16684                            .or_insert_with(|| vec![start..end]);
16685                    }
16686                }
16687                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16688            }
16689        };
16690
16691        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16692        let selections_prev = transaction_id_prev
16693            .and_then(|transaction_id_prev| {
16694                // default to selections as they were after the last edit, if we have them,
16695                // instead of how they are now.
16696                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16697                // will take you back to where you made the last edit, instead of staying where you scrolled
16698                self.selection_history
16699                    .transaction(transaction_id_prev)
16700                    .map(|t| t.0.clone())
16701            })
16702            .unwrap_or_else(|| self.selections.disjoint_anchors());
16703
16704        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16705        let format = project.update(cx, |project, cx| {
16706            project.format(buffers, target, true, trigger, cx)
16707        });
16708
16709        cx.spawn_in(window, async move |editor, cx| {
16710            let transaction = futures::select_biased! {
16711                transaction = format.log_err().fuse() => transaction,
16712                () = timeout => {
16713                    log::warn!("timed out waiting for formatting");
16714                    None
16715                }
16716            };
16717
16718            buffer
16719                .update(cx, |buffer, cx| {
16720                    if let Some(transaction) = transaction
16721                        && !buffer.is_singleton()
16722                    {
16723                        buffer.push_transaction(&transaction.0, cx);
16724                    }
16725                    cx.notify();
16726                })
16727                .ok();
16728
16729            if let Some(transaction_id_now) =
16730                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16731            {
16732                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16733                if has_new_transaction {
16734                    _ = editor.update(cx, |editor, _| {
16735                        editor
16736                            .selection_history
16737                            .insert_transaction(transaction_id_now, selections_prev);
16738                    });
16739                }
16740            }
16741
16742            Ok(())
16743        })
16744    }
16745
16746    fn organize_imports(
16747        &mut self,
16748        _: &OrganizeImports,
16749        window: &mut Window,
16750        cx: &mut Context<Self>,
16751    ) -> Option<Task<Result<()>>> {
16752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16753        let project = match &self.project {
16754            Some(project) => project.clone(),
16755            None => return None,
16756        };
16757        Some(self.perform_code_action_kind(
16758            project,
16759            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16760            window,
16761            cx,
16762        ))
16763    }
16764
16765    fn perform_code_action_kind(
16766        &mut self,
16767        project: Entity<Project>,
16768        kind: CodeActionKind,
16769        window: &mut Window,
16770        cx: &mut Context<Self>,
16771    ) -> Task<Result<()>> {
16772        let buffer = self.buffer.clone();
16773        let buffers = buffer.read(cx).all_buffers();
16774        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16775        let apply_action = project.update(cx, |project, cx| {
16776            project.apply_code_action_kind(buffers, kind, true, cx)
16777        });
16778        cx.spawn_in(window, async move |_, cx| {
16779            let transaction = futures::select_biased! {
16780                () = timeout => {
16781                    log::warn!("timed out waiting for executing code action");
16782                    None
16783                }
16784                transaction = apply_action.log_err().fuse() => transaction,
16785            };
16786            buffer
16787                .update(cx, |buffer, cx| {
16788                    // check if we need this
16789                    if let Some(transaction) = transaction
16790                        && !buffer.is_singleton()
16791                    {
16792                        buffer.push_transaction(&transaction.0, cx);
16793                    }
16794                    cx.notify();
16795                })
16796                .ok();
16797            Ok(())
16798        })
16799    }
16800
16801    pub fn restart_language_server(
16802        &mut self,
16803        _: &RestartLanguageServer,
16804        _: &mut Window,
16805        cx: &mut Context<Self>,
16806    ) {
16807        if let Some(project) = self.project.clone() {
16808            self.buffer.update(cx, |multi_buffer, cx| {
16809                project.update(cx, |project, cx| {
16810                    project.restart_language_servers_for_buffers(
16811                        multi_buffer.all_buffers().into_iter().collect(),
16812                        HashSet::default(),
16813                        cx,
16814                    );
16815                });
16816            })
16817        }
16818    }
16819
16820    pub fn stop_language_server(
16821        &mut self,
16822        _: &StopLanguageServer,
16823        _: &mut Window,
16824        cx: &mut Context<Self>,
16825    ) {
16826        if let Some(project) = self.project.clone() {
16827            self.buffer.update(cx, |multi_buffer, cx| {
16828                project.update(cx, |project, cx| {
16829                    project.stop_language_servers_for_buffers(
16830                        multi_buffer.all_buffers().into_iter().collect(),
16831                        HashSet::default(),
16832                        cx,
16833                    );
16834                    cx.emit(project::Event::RefreshInlayHints);
16835                });
16836            });
16837        }
16838    }
16839
16840    fn cancel_language_server_work(
16841        workspace: &mut Workspace,
16842        _: &actions::CancelLanguageServerWork,
16843        _: &mut Window,
16844        cx: &mut Context<Workspace>,
16845    ) {
16846        let project = workspace.project();
16847        let buffers = workspace
16848            .active_item(cx)
16849            .and_then(|item| item.act_as::<Editor>(cx))
16850            .map_or(HashSet::default(), |editor| {
16851                editor.read(cx).buffer.read(cx).all_buffers()
16852            });
16853        project.update(cx, |project, cx| {
16854            project.cancel_language_server_work_for_buffers(buffers, cx);
16855        });
16856    }
16857
16858    fn show_character_palette(
16859        &mut self,
16860        _: &ShowCharacterPalette,
16861        window: &mut Window,
16862        _: &mut Context<Self>,
16863    ) {
16864        window.show_character_palette();
16865    }
16866
16867    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16868        if !self.diagnostics_enabled() {
16869            return;
16870        }
16871
16872        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16873            let buffer = self.buffer.read(cx).snapshot(cx);
16874            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16875            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16876            let is_valid = buffer
16877                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16878                .any(|entry| {
16879                    entry.diagnostic.is_primary
16880                        && !entry.range.is_empty()
16881                        && entry.range.start == primary_range_start
16882                        && entry.diagnostic.message == active_diagnostics.active_message
16883                });
16884
16885            if !is_valid {
16886                self.dismiss_diagnostics(cx);
16887            }
16888        }
16889    }
16890
16891    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16892        match &self.active_diagnostics {
16893            ActiveDiagnostic::Group(group) => Some(group),
16894            _ => None,
16895        }
16896    }
16897
16898    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16899        if !self.diagnostics_enabled() {
16900            return;
16901        }
16902        self.dismiss_diagnostics(cx);
16903        self.active_diagnostics = ActiveDiagnostic::All;
16904    }
16905
16906    fn activate_diagnostics(
16907        &mut self,
16908        buffer_id: BufferId,
16909        diagnostic: DiagnosticEntry<usize>,
16910        window: &mut Window,
16911        cx: &mut Context<Self>,
16912    ) {
16913        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16914            return;
16915        }
16916        self.dismiss_diagnostics(cx);
16917        let snapshot = self.snapshot(window, cx);
16918        let buffer = self.buffer.read(cx).snapshot(cx);
16919        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16920            return;
16921        };
16922
16923        let diagnostic_group = buffer
16924            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16925            .collect::<Vec<_>>();
16926
16927        let blocks =
16928            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16929
16930        let blocks = self.display_map.update(cx, |display_map, cx| {
16931            display_map.insert_blocks(blocks, cx).into_iter().collect()
16932        });
16933        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16934            active_range: buffer.anchor_before(diagnostic.range.start)
16935                ..buffer.anchor_after(diagnostic.range.end),
16936            active_message: diagnostic.diagnostic.message.clone(),
16937            group_id: diagnostic.diagnostic.group_id,
16938            blocks,
16939        });
16940        cx.notify();
16941    }
16942
16943    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16944        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16945            return;
16946        };
16947
16948        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16949        if let ActiveDiagnostic::Group(group) = prev {
16950            self.display_map.update(cx, |display_map, cx| {
16951                display_map.remove_blocks(group.blocks, cx);
16952            });
16953            cx.notify();
16954        }
16955    }
16956
16957    /// Disable inline diagnostics rendering for this editor.
16958    pub fn disable_inline_diagnostics(&mut self) {
16959        self.inline_diagnostics_enabled = false;
16960        self.inline_diagnostics_update = Task::ready(());
16961        self.inline_diagnostics.clear();
16962    }
16963
16964    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16965        self.diagnostics_enabled = false;
16966        self.dismiss_diagnostics(cx);
16967        self.inline_diagnostics_update = Task::ready(());
16968        self.inline_diagnostics.clear();
16969    }
16970
16971    pub fn diagnostics_enabled(&self) -> bool {
16972        self.diagnostics_enabled && self.mode.is_full()
16973    }
16974
16975    pub fn inline_diagnostics_enabled(&self) -> bool {
16976        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16977    }
16978
16979    pub fn show_inline_diagnostics(&self) -> bool {
16980        self.show_inline_diagnostics
16981    }
16982
16983    pub fn toggle_inline_diagnostics(
16984        &mut self,
16985        _: &ToggleInlineDiagnostics,
16986        window: &mut Window,
16987        cx: &mut Context<Editor>,
16988    ) {
16989        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16990        self.refresh_inline_diagnostics(false, window, cx);
16991    }
16992
16993    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16994        self.diagnostics_max_severity = severity;
16995        self.display_map.update(cx, |display_map, _| {
16996            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16997        });
16998    }
16999
17000    pub fn toggle_diagnostics(
17001        &mut self,
17002        _: &ToggleDiagnostics,
17003        window: &mut Window,
17004        cx: &mut Context<Editor>,
17005    ) {
17006        if !self.diagnostics_enabled() {
17007            return;
17008        }
17009
17010        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17011            EditorSettings::get_global(cx)
17012                .diagnostics_max_severity
17013                .filter(|severity| severity != &DiagnosticSeverity::Off)
17014                .unwrap_or(DiagnosticSeverity::Hint)
17015        } else {
17016            DiagnosticSeverity::Off
17017        };
17018        self.set_max_diagnostics_severity(new_severity, cx);
17019        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17020            self.active_diagnostics = ActiveDiagnostic::None;
17021            self.inline_diagnostics_update = Task::ready(());
17022            self.inline_diagnostics.clear();
17023        } else {
17024            self.refresh_inline_diagnostics(false, window, cx);
17025        }
17026
17027        cx.notify();
17028    }
17029
17030    pub fn toggle_minimap(
17031        &mut self,
17032        _: &ToggleMinimap,
17033        window: &mut Window,
17034        cx: &mut Context<Editor>,
17035    ) {
17036        if self.supports_minimap(cx) {
17037            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17038        }
17039    }
17040
17041    fn refresh_inline_diagnostics(
17042        &mut self,
17043        debounce: bool,
17044        window: &mut Window,
17045        cx: &mut Context<Self>,
17046    ) {
17047        let max_severity = ProjectSettings::get_global(cx)
17048            .diagnostics
17049            .inline
17050            .max_severity
17051            .unwrap_or(self.diagnostics_max_severity);
17052
17053        if !self.inline_diagnostics_enabled()
17054            || !self.show_inline_diagnostics
17055            || max_severity == DiagnosticSeverity::Off
17056        {
17057            self.inline_diagnostics_update = Task::ready(());
17058            self.inline_diagnostics.clear();
17059            return;
17060        }
17061
17062        let debounce_ms = ProjectSettings::get_global(cx)
17063            .diagnostics
17064            .inline
17065            .update_debounce_ms;
17066        let debounce = if debounce && debounce_ms > 0 {
17067            Some(Duration::from_millis(debounce_ms))
17068        } else {
17069            None
17070        };
17071        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17072            if let Some(debounce) = debounce {
17073                cx.background_executor().timer(debounce).await;
17074            }
17075            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17076                editor
17077                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17078                    .ok()
17079            }) else {
17080                return;
17081            };
17082
17083            let new_inline_diagnostics = cx
17084                .background_spawn(async move {
17085                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17086                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17087                        let message = diagnostic_entry
17088                            .diagnostic
17089                            .message
17090                            .split_once('\n')
17091                            .map(|(line, _)| line)
17092                            .map(SharedString::new)
17093                            .unwrap_or_else(|| {
17094                                SharedString::from(diagnostic_entry.diagnostic.message)
17095                            });
17096                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17097                        let (Ok(i) | Err(i)) = inline_diagnostics
17098                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17099                        inline_diagnostics.insert(
17100                            i,
17101                            (
17102                                start_anchor,
17103                                InlineDiagnostic {
17104                                    message,
17105                                    group_id: diagnostic_entry.diagnostic.group_id,
17106                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17107                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17108                                    severity: diagnostic_entry.diagnostic.severity,
17109                                },
17110                            ),
17111                        );
17112                    }
17113                    inline_diagnostics
17114                })
17115                .await;
17116
17117            editor
17118                .update(cx, |editor, cx| {
17119                    editor.inline_diagnostics = new_inline_diagnostics;
17120                    cx.notify();
17121                })
17122                .ok();
17123        });
17124    }
17125
17126    fn pull_diagnostics(
17127        &mut self,
17128        buffer_id: Option<BufferId>,
17129        window: &Window,
17130        cx: &mut Context<Self>,
17131    ) -> Option<()> {
17132        if !self.mode().is_full() {
17133            return None;
17134        }
17135        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17136            .diagnostics
17137            .lsp_pull_diagnostics;
17138        if !pull_diagnostics_settings.enabled {
17139            return None;
17140        }
17141        let project = self.project()?.downgrade();
17142        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17143        let mut buffers = self.buffer.read(cx).all_buffers();
17144        if let Some(buffer_id) = buffer_id {
17145            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17146        }
17147
17148        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17149            cx.background_executor().timer(debounce).await;
17150
17151            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17152                buffers
17153                    .into_iter()
17154                    .filter_map(|buffer| {
17155                        project
17156                            .update(cx, |project, cx| {
17157                                project.lsp_store().update(cx, |lsp_store, cx| {
17158                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17159                                })
17160                            })
17161                            .ok()
17162                    })
17163                    .collect::<FuturesUnordered<_>>()
17164            }) else {
17165                return;
17166            };
17167
17168            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17169                match pull_task {
17170                    Ok(()) => {
17171                        if editor
17172                            .update_in(cx, |editor, window, cx| {
17173                                editor.update_diagnostics_state(window, cx);
17174                            })
17175                            .is_err()
17176                        {
17177                            return;
17178                        }
17179                    }
17180                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17181                }
17182            }
17183        });
17184
17185        Some(())
17186    }
17187
17188    pub fn set_selections_from_remote(
17189        &mut self,
17190        selections: Vec<Selection<Anchor>>,
17191        pending_selection: Option<Selection<Anchor>>,
17192        window: &mut Window,
17193        cx: &mut Context<Self>,
17194    ) {
17195        let old_cursor_position = self.selections.newest_anchor().head();
17196        self.selections.change_with(cx, |s| {
17197            s.select_anchors(selections);
17198            if let Some(pending_selection) = pending_selection {
17199                s.set_pending(pending_selection, SelectMode::Character);
17200            } else {
17201                s.clear_pending();
17202            }
17203        });
17204        self.selections_did_change(
17205            false,
17206            &old_cursor_position,
17207            SelectionEffects::default(),
17208            window,
17209            cx,
17210        );
17211    }
17212
17213    pub fn transact(
17214        &mut self,
17215        window: &mut Window,
17216        cx: &mut Context<Self>,
17217        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17218    ) -> Option<TransactionId> {
17219        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17220            this.start_transaction_at(Instant::now(), window, cx);
17221            update(this, window, cx);
17222            this.end_transaction_at(Instant::now(), cx)
17223        })
17224    }
17225
17226    pub fn start_transaction_at(
17227        &mut self,
17228        now: Instant,
17229        window: &mut Window,
17230        cx: &mut Context<Self>,
17231    ) -> Option<TransactionId> {
17232        self.end_selection(window, cx);
17233        if let Some(tx_id) = self
17234            .buffer
17235            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17236        {
17237            self.selection_history
17238                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17239            cx.emit(EditorEvent::TransactionBegun {
17240                transaction_id: tx_id,
17241            });
17242            Some(tx_id)
17243        } else {
17244            None
17245        }
17246    }
17247
17248    pub fn end_transaction_at(
17249        &mut self,
17250        now: Instant,
17251        cx: &mut Context<Self>,
17252    ) -> Option<TransactionId> {
17253        if let Some(transaction_id) = self
17254            .buffer
17255            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17256        {
17257            if let Some((_, end_selections)) =
17258                self.selection_history.transaction_mut(transaction_id)
17259            {
17260                *end_selections = Some(self.selections.disjoint_anchors());
17261            } else {
17262                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17263            }
17264
17265            cx.emit(EditorEvent::Edited { transaction_id });
17266            Some(transaction_id)
17267        } else {
17268            None
17269        }
17270    }
17271
17272    pub fn modify_transaction_selection_history(
17273        &mut self,
17274        transaction_id: TransactionId,
17275        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17276    ) -> bool {
17277        self.selection_history
17278            .transaction_mut(transaction_id)
17279            .map(modify)
17280            .is_some()
17281    }
17282
17283    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17284        if self.selection_mark_mode {
17285            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17286                s.move_with(|_, sel| {
17287                    sel.collapse_to(sel.head(), SelectionGoal::None);
17288                });
17289            })
17290        }
17291        self.selection_mark_mode = true;
17292        cx.notify();
17293    }
17294
17295    pub fn swap_selection_ends(
17296        &mut self,
17297        _: &actions::SwapSelectionEnds,
17298        window: &mut Window,
17299        cx: &mut Context<Self>,
17300    ) {
17301        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17302            s.move_with(|_, sel| {
17303                if sel.start != sel.end {
17304                    sel.reversed = !sel.reversed
17305                }
17306            });
17307        });
17308        self.request_autoscroll(Autoscroll::newest(), cx);
17309        cx.notify();
17310    }
17311
17312    pub fn toggle_focus(
17313        workspace: &mut Workspace,
17314        _: &actions::ToggleFocus,
17315        window: &mut Window,
17316        cx: &mut Context<Workspace>,
17317    ) {
17318        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17319            return;
17320        };
17321        workspace.activate_item(&item, true, true, window, cx);
17322    }
17323
17324    pub fn toggle_fold(
17325        &mut self,
17326        _: &actions::ToggleFold,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) {
17330        if self.is_singleton(cx) {
17331            let selection = self.selections.newest::<Point>(cx);
17332
17333            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17334            let range = if selection.is_empty() {
17335                let point = selection.head().to_display_point(&display_map);
17336                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17337                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17338                    .to_point(&display_map);
17339                start..end
17340            } else {
17341                selection.range()
17342            };
17343            if display_map.folds_in_range(range).next().is_some() {
17344                self.unfold_lines(&Default::default(), window, cx)
17345            } else {
17346                self.fold(&Default::default(), window, cx)
17347            }
17348        } else {
17349            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17350            let buffer_ids: HashSet<_> = self
17351                .selections
17352                .disjoint_anchor_ranges()
17353                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17354                .collect();
17355
17356            let should_unfold = buffer_ids
17357                .iter()
17358                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17359
17360            for buffer_id in buffer_ids {
17361                if should_unfold {
17362                    self.unfold_buffer(buffer_id, cx);
17363                } else {
17364                    self.fold_buffer(buffer_id, cx);
17365                }
17366            }
17367        }
17368    }
17369
17370    pub fn toggle_fold_recursive(
17371        &mut self,
17372        _: &actions::ToggleFoldRecursive,
17373        window: &mut Window,
17374        cx: &mut Context<Self>,
17375    ) {
17376        let selection = self.selections.newest::<Point>(cx);
17377
17378        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17379        let range = if selection.is_empty() {
17380            let point = selection.head().to_display_point(&display_map);
17381            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17382            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17383                .to_point(&display_map);
17384            start..end
17385        } else {
17386            selection.range()
17387        };
17388        if display_map.folds_in_range(range).next().is_some() {
17389            self.unfold_recursive(&Default::default(), window, cx)
17390        } else {
17391            self.fold_recursive(&Default::default(), window, cx)
17392        }
17393    }
17394
17395    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17396        if self.is_singleton(cx) {
17397            let mut to_fold = Vec::new();
17398            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17399            let selections = self.selections.all_adjusted(cx);
17400
17401            for selection in selections {
17402                let range = selection.range().sorted();
17403                let buffer_start_row = range.start.row;
17404
17405                if range.start.row != range.end.row {
17406                    let mut found = false;
17407                    let mut row = range.start.row;
17408                    while row <= range.end.row {
17409                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17410                        {
17411                            found = true;
17412                            row = crease.range().end.row + 1;
17413                            to_fold.push(crease);
17414                        } else {
17415                            row += 1
17416                        }
17417                    }
17418                    if found {
17419                        continue;
17420                    }
17421                }
17422
17423                for row in (0..=range.start.row).rev() {
17424                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17425                        && crease.range().end.row >= buffer_start_row
17426                    {
17427                        to_fold.push(crease);
17428                        if row <= range.start.row {
17429                            break;
17430                        }
17431                    }
17432                }
17433            }
17434
17435            self.fold_creases(to_fold, true, window, cx);
17436        } else {
17437            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17438            let buffer_ids = self
17439                .selections
17440                .disjoint_anchor_ranges()
17441                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17442                .collect::<HashSet<_>>();
17443            for buffer_id in buffer_ids {
17444                self.fold_buffer(buffer_id, cx);
17445            }
17446        }
17447    }
17448
17449    pub fn toggle_fold_all(
17450        &mut self,
17451        _: &actions::ToggleFoldAll,
17452        window: &mut Window,
17453        cx: &mut Context<Self>,
17454    ) {
17455        if self.buffer.read(cx).is_singleton() {
17456            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17457            let has_folds = display_map
17458                .folds_in_range(0..display_map.buffer_snapshot.len())
17459                .next()
17460                .is_some();
17461
17462            if has_folds {
17463                self.unfold_all(&actions::UnfoldAll, window, cx);
17464            } else {
17465                self.fold_all(&actions::FoldAll, window, cx);
17466            }
17467        } else {
17468            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17469            let should_unfold = buffer_ids
17470                .iter()
17471                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17472
17473            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17474                editor
17475                    .update_in(cx, |editor, _, cx| {
17476                        for buffer_id in buffer_ids {
17477                            if should_unfold {
17478                                editor.unfold_buffer(buffer_id, cx);
17479                            } else {
17480                                editor.fold_buffer(buffer_id, cx);
17481                            }
17482                        }
17483                    })
17484                    .ok();
17485            });
17486        }
17487    }
17488
17489    fn fold_at_level(
17490        &mut self,
17491        fold_at: &FoldAtLevel,
17492        window: &mut Window,
17493        cx: &mut Context<Self>,
17494    ) {
17495        if !self.buffer.read(cx).is_singleton() {
17496            return;
17497        }
17498
17499        let fold_at_level = fold_at.0;
17500        let snapshot = self.buffer.read(cx).snapshot(cx);
17501        let mut to_fold = Vec::new();
17502        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17503
17504        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17505            while start_row < end_row {
17506                match self
17507                    .snapshot(window, cx)
17508                    .crease_for_buffer_row(MultiBufferRow(start_row))
17509                {
17510                    Some(crease) => {
17511                        let nested_start_row = crease.range().start.row + 1;
17512                        let nested_end_row = crease.range().end.row;
17513
17514                        if current_level < fold_at_level {
17515                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17516                        } else if current_level == fold_at_level {
17517                            to_fold.push(crease);
17518                        }
17519
17520                        start_row = nested_end_row + 1;
17521                    }
17522                    None => start_row += 1,
17523                }
17524            }
17525        }
17526
17527        self.fold_creases(to_fold, true, window, cx);
17528    }
17529
17530    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17531        if self.buffer.read(cx).is_singleton() {
17532            let mut fold_ranges = Vec::new();
17533            let snapshot = self.buffer.read(cx).snapshot(cx);
17534
17535            for row in 0..snapshot.max_row().0 {
17536                if let Some(foldable_range) = self
17537                    .snapshot(window, cx)
17538                    .crease_for_buffer_row(MultiBufferRow(row))
17539                {
17540                    fold_ranges.push(foldable_range);
17541                }
17542            }
17543
17544            self.fold_creases(fold_ranges, true, window, cx);
17545        } else {
17546            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17547                editor
17548                    .update_in(cx, |editor, _, cx| {
17549                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17550                            editor.fold_buffer(buffer_id, cx);
17551                        }
17552                    })
17553                    .ok();
17554            });
17555        }
17556    }
17557
17558    pub fn fold_function_bodies(
17559        &mut self,
17560        _: &actions::FoldFunctionBodies,
17561        window: &mut Window,
17562        cx: &mut Context<Self>,
17563    ) {
17564        let snapshot = self.buffer.read(cx).snapshot(cx);
17565
17566        let ranges = snapshot
17567            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17568            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17569            .collect::<Vec<_>>();
17570
17571        let creases = ranges
17572            .into_iter()
17573            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17574            .collect();
17575
17576        self.fold_creases(creases, true, window, cx);
17577    }
17578
17579    pub fn fold_recursive(
17580        &mut self,
17581        _: &actions::FoldRecursive,
17582        window: &mut Window,
17583        cx: &mut Context<Self>,
17584    ) {
17585        let mut to_fold = Vec::new();
17586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17587        let selections = self.selections.all_adjusted(cx);
17588
17589        for selection in selections {
17590            let range = selection.range().sorted();
17591            let buffer_start_row = range.start.row;
17592
17593            if range.start.row != range.end.row {
17594                let mut found = false;
17595                for row in range.start.row..=range.end.row {
17596                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17597                        found = true;
17598                        to_fold.push(crease);
17599                    }
17600                }
17601                if found {
17602                    continue;
17603                }
17604            }
17605
17606            for row in (0..=range.start.row).rev() {
17607                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17608                    if crease.range().end.row >= buffer_start_row {
17609                        to_fold.push(crease);
17610                    } else {
17611                        break;
17612                    }
17613                }
17614            }
17615        }
17616
17617        self.fold_creases(to_fold, true, window, cx);
17618    }
17619
17620    pub fn fold_at(
17621        &mut self,
17622        buffer_row: MultiBufferRow,
17623        window: &mut Window,
17624        cx: &mut Context<Self>,
17625    ) {
17626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17627
17628        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17629            let autoscroll = self
17630                .selections
17631                .all::<Point>(cx)
17632                .iter()
17633                .any(|selection| crease.range().overlaps(&selection.range()));
17634
17635            self.fold_creases(vec![crease], autoscroll, window, cx);
17636        }
17637    }
17638
17639    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17640        if self.is_singleton(cx) {
17641            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17642            let buffer = &display_map.buffer_snapshot;
17643            let selections = self.selections.all::<Point>(cx);
17644            let ranges = selections
17645                .iter()
17646                .map(|s| {
17647                    let range = s.display_range(&display_map).sorted();
17648                    let mut start = range.start.to_point(&display_map);
17649                    let mut end = range.end.to_point(&display_map);
17650                    start.column = 0;
17651                    end.column = buffer.line_len(MultiBufferRow(end.row));
17652                    start..end
17653                })
17654                .collect::<Vec<_>>();
17655
17656            self.unfold_ranges(&ranges, true, true, cx);
17657        } else {
17658            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17659            let buffer_ids = self
17660                .selections
17661                .disjoint_anchor_ranges()
17662                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17663                .collect::<HashSet<_>>();
17664            for buffer_id in buffer_ids {
17665                self.unfold_buffer(buffer_id, cx);
17666            }
17667        }
17668    }
17669
17670    pub fn unfold_recursive(
17671        &mut self,
17672        _: &UnfoldRecursive,
17673        _window: &mut Window,
17674        cx: &mut Context<Self>,
17675    ) {
17676        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17677        let selections = self.selections.all::<Point>(cx);
17678        let ranges = selections
17679            .iter()
17680            .map(|s| {
17681                let mut range = s.display_range(&display_map).sorted();
17682                *range.start.column_mut() = 0;
17683                *range.end.column_mut() = display_map.line_len(range.end.row());
17684                let start = range.start.to_point(&display_map);
17685                let end = range.end.to_point(&display_map);
17686                start..end
17687            })
17688            .collect::<Vec<_>>();
17689
17690        self.unfold_ranges(&ranges, true, true, cx);
17691    }
17692
17693    pub fn unfold_at(
17694        &mut self,
17695        buffer_row: MultiBufferRow,
17696        _window: &mut Window,
17697        cx: &mut Context<Self>,
17698    ) {
17699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17700
17701        let intersection_range = Point::new(buffer_row.0, 0)
17702            ..Point::new(
17703                buffer_row.0,
17704                display_map.buffer_snapshot.line_len(buffer_row),
17705            );
17706
17707        let autoscroll = self
17708            .selections
17709            .all::<Point>(cx)
17710            .iter()
17711            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17712
17713        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17714    }
17715
17716    pub fn unfold_all(
17717        &mut self,
17718        _: &actions::UnfoldAll,
17719        _window: &mut Window,
17720        cx: &mut Context<Self>,
17721    ) {
17722        if self.buffer.read(cx).is_singleton() {
17723            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17724            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17725        } else {
17726            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17727                editor
17728                    .update(cx, |editor, cx| {
17729                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17730                            editor.unfold_buffer(buffer_id, cx);
17731                        }
17732                    })
17733                    .ok();
17734            });
17735        }
17736    }
17737
17738    pub fn fold_selected_ranges(
17739        &mut self,
17740        _: &FoldSelectedRanges,
17741        window: &mut Window,
17742        cx: &mut Context<Self>,
17743    ) {
17744        let selections = self.selections.all_adjusted(cx);
17745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17746        let ranges = selections
17747            .into_iter()
17748            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17749            .collect::<Vec<_>>();
17750        self.fold_creases(ranges, true, window, cx);
17751    }
17752
17753    pub fn fold_ranges<T: ToOffset + Clone>(
17754        &mut self,
17755        ranges: Vec<Range<T>>,
17756        auto_scroll: bool,
17757        window: &mut Window,
17758        cx: &mut Context<Self>,
17759    ) {
17760        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17761        let ranges = ranges
17762            .into_iter()
17763            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17764            .collect::<Vec<_>>();
17765        self.fold_creases(ranges, auto_scroll, window, cx);
17766    }
17767
17768    pub fn fold_creases<T: ToOffset + Clone>(
17769        &mut self,
17770        creases: Vec<Crease<T>>,
17771        auto_scroll: bool,
17772        _window: &mut Window,
17773        cx: &mut Context<Self>,
17774    ) {
17775        if creases.is_empty() {
17776            return;
17777        }
17778
17779        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17780
17781        if auto_scroll {
17782            self.request_autoscroll(Autoscroll::fit(), cx);
17783        }
17784
17785        cx.notify();
17786
17787        self.scrollbar_marker_state.dirty = true;
17788        self.folds_did_change(cx);
17789    }
17790
17791    /// Removes any folds whose ranges intersect any of the given ranges.
17792    pub fn unfold_ranges<T: ToOffset + Clone>(
17793        &mut self,
17794        ranges: &[Range<T>],
17795        inclusive: bool,
17796        auto_scroll: bool,
17797        cx: &mut Context<Self>,
17798    ) {
17799        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17800            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17801        });
17802        self.folds_did_change(cx);
17803    }
17804
17805    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17806        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17807            return;
17808        }
17809        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17810        self.display_map.update(cx, |display_map, cx| {
17811            display_map.fold_buffers([buffer_id], cx)
17812        });
17813        cx.emit(EditorEvent::BufferFoldToggled {
17814            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17815            folded: true,
17816        });
17817        cx.notify();
17818    }
17819
17820    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17821        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17822            return;
17823        }
17824        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17825        self.display_map.update(cx, |display_map, cx| {
17826            display_map.unfold_buffers([buffer_id], cx);
17827        });
17828        cx.emit(EditorEvent::BufferFoldToggled {
17829            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17830            folded: false,
17831        });
17832        cx.notify();
17833    }
17834
17835    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17836        self.display_map.read(cx).is_buffer_folded(buffer)
17837    }
17838
17839    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17840        self.display_map.read(cx).folded_buffers()
17841    }
17842
17843    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17844        self.display_map.update(cx, |display_map, cx| {
17845            display_map.disable_header_for_buffer(buffer_id, cx);
17846        });
17847        cx.notify();
17848    }
17849
17850    /// Removes any folds with the given ranges.
17851    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17852        &mut self,
17853        ranges: &[Range<T>],
17854        type_id: TypeId,
17855        auto_scroll: bool,
17856        cx: &mut Context<Self>,
17857    ) {
17858        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17859            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17860        });
17861        self.folds_did_change(cx);
17862    }
17863
17864    fn remove_folds_with<T: ToOffset + Clone>(
17865        &mut self,
17866        ranges: &[Range<T>],
17867        auto_scroll: bool,
17868        cx: &mut Context<Self>,
17869        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17870    ) {
17871        if ranges.is_empty() {
17872            return;
17873        }
17874
17875        let mut buffers_affected = HashSet::default();
17876        let multi_buffer = self.buffer().read(cx);
17877        for range in ranges {
17878            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17879                buffers_affected.insert(buffer.read(cx).remote_id());
17880            };
17881        }
17882
17883        self.display_map.update(cx, update);
17884
17885        if auto_scroll {
17886            self.request_autoscroll(Autoscroll::fit(), cx);
17887        }
17888
17889        cx.notify();
17890        self.scrollbar_marker_state.dirty = true;
17891        self.active_indent_guides_state.dirty = true;
17892    }
17893
17894    pub fn update_renderer_widths(
17895        &mut self,
17896        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17897        cx: &mut Context<Self>,
17898    ) -> bool {
17899        self.display_map
17900            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17901    }
17902
17903    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17904        self.display_map.read(cx).fold_placeholder.clone()
17905    }
17906
17907    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17908        self.buffer.update(cx, |buffer, cx| {
17909            buffer.set_all_diff_hunks_expanded(cx);
17910        });
17911    }
17912
17913    pub fn expand_all_diff_hunks(
17914        &mut self,
17915        _: &ExpandAllDiffHunks,
17916        _window: &mut Window,
17917        cx: &mut Context<Self>,
17918    ) {
17919        self.buffer.update(cx, |buffer, cx| {
17920            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17921        });
17922    }
17923
17924    pub fn toggle_selected_diff_hunks(
17925        &mut self,
17926        _: &ToggleSelectedDiffHunks,
17927        _window: &mut Window,
17928        cx: &mut Context<Self>,
17929    ) {
17930        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17931        self.toggle_diff_hunks_in_ranges(ranges, cx);
17932    }
17933
17934    pub fn diff_hunks_in_ranges<'a>(
17935        &'a self,
17936        ranges: &'a [Range<Anchor>],
17937        buffer: &'a MultiBufferSnapshot,
17938    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17939        ranges.iter().flat_map(move |range| {
17940            let end_excerpt_id = range.end.excerpt_id;
17941            let range = range.to_point(buffer);
17942            let mut peek_end = range.end;
17943            if range.end.row < buffer.max_row().0 {
17944                peek_end = Point::new(range.end.row + 1, 0);
17945            }
17946            buffer
17947                .diff_hunks_in_range(range.start..peek_end)
17948                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17949        })
17950    }
17951
17952    pub fn has_stageable_diff_hunks_in_ranges(
17953        &self,
17954        ranges: &[Range<Anchor>],
17955        snapshot: &MultiBufferSnapshot,
17956    ) -> bool {
17957        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17958        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17959    }
17960
17961    pub fn toggle_staged_selected_diff_hunks(
17962        &mut self,
17963        _: &::git::ToggleStaged,
17964        _: &mut Window,
17965        cx: &mut Context<Self>,
17966    ) {
17967        let snapshot = self.buffer.read(cx).snapshot(cx);
17968        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17969        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17970        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17971    }
17972
17973    pub fn set_render_diff_hunk_controls(
17974        &mut self,
17975        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17976        cx: &mut Context<Self>,
17977    ) {
17978        self.render_diff_hunk_controls = render_diff_hunk_controls;
17979        cx.notify();
17980    }
17981
17982    pub fn stage_and_next(
17983        &mut self,
17984        _: &::git::StageAndNext,
17985        window: &mut Window,
17986        cx: &mut Context<Self>,
17987    ) {
17988        self.do_stage_or_unstage_and_next(true, window, cx);
17989    }
17990
17991    pub fn unstage_and_next(
17992        &mut self,
17993        _: &::git::UnstageAndNext,
17994        window: &mut Window,
17995        cx: &mut Context<Self>,
17996    ) {
17997        self.do_stage_or_unstage_and_next(false, window, cx);
17998    }
17999
18000    pub fn stage_or_unstage_diff_hunks(
18001        &mut self,
18002        stage: bool,
18003        ranges: Vec<Range<Anchor>>,
18004        cx: &mut Context<Self>,
18005    ) {
18006        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18007        cx.spawn(async move |this, cx| {
18008            task.await?;
18009            this.update(cx, |this, cx| {
18010                let snapshot = this.buffer.read(cx).snapshot(cx);
18011                let chunk_by = this
18012                    .diff_hunks_in_ranges(&ranges, &snapshot)
18013                    .chunk_by(|hunk| hunk.buffer_id);
18014                for (buffer_id, hunks) in &chunk_by {
18015                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18016                }
18017            })
18018        })
18019        .detach_and_log_err(cx);
18020    }
18021
18022    fn save_buffers_for_ranges_if_needed(
18023        &mut self,
18024        ranges: &[Range<Anchor>],
18025        cx: &mut Context<Editor>,
18026    ) -> Task<Result<()>> {
18027        let multibuffer = self.buffer.read(cx);
18028        let snapshot = multibuffer.read(cx);
18029        let buffer_ids: HashSet<_> = ranges
18030            .iter()
18031            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18032            .collect();
18033        drop(snapshot);
18034
18035        let mut buffers = HashSet::default();
18036        for buffer_id in buffer_ids {
18037            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18038                let buffer = buffer_entity.read(cx);
18039                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18040                {
18041                    buffers.insert(buffer_entity);
18042                }
18043            }
18044        }
18045
18046        if let Some(project) = &self.project {
18047            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18048        } else {
18049            Task::ready(Ok(()))
18050        }
18051    }
18052
18053    fn do_stage_or_unstage_and_next(
18054        &mut self,
18055        stage: bool,
18056        window: &mut Window,
18057        cx: &mut Context<Self>,
18058    ) {
18059        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18060
18061        if ranges.iter().any(|range| range.start != range.end) {
18062            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18063            return;
18064        }
18065
18066        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18067        let snapshot = self.snapshot(window, cx);
18068        let position = self.selections.newest::<Point>(cx).head();
18069        let mut row = snapshot
18070            .buffer_snapshot
18071            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18072            .find(|hunk| hunk.row_range.start.0 > position.row)
18073            .map(|hunk| hunk.row_range.start);
18074
18075        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18076        // Outside of the project diff editor, wrap around to the beginning.
18077        if !all_diff_hunks_expanded {
18078            row = row.or_else(|| {
18079                snapshot
18080                    .buffer_snapshot
18081                    .diff_hunks_in_range(Point::zero()..position)
18082                    .find(|hunk| hunk.row_range.end.0 < position.row)
18083                    .map(|hunk| hunk.row_range.start)
18084            });
18085        }
18086
18087        if let Some(row) = row {
18088            let destination = Point::new(row.0, 0);
18089            let autoscroll = Autoscroll::center();
18090
18091            self.unfold_ranges(&[destination..destination], false, false, cx);
18092            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18093                s.select_ranges([destination..destination]);
18094            });
18095        }
18096    }
18097
18098    fn do_stage_or_unstage(
18099        &self,
18100        stage: bool,
18101        buffer_id: BufferId,
18102        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18103        cx: &mut App,
18104    ) -> Option<()> {
18105        let project = self.project()?;
18106        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18107        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18108        let buffer_snapshot = buffer.read(cx).snapshot();
18109        let file_exists = buffer_snapshot
18110            .file()
18111            .is_some_and(|file| file.disk_state().exists());
18112        diff.update(cx, |diff, cx| {
18113            diff.stage_or_unstage_hunks(
18114                stage,
18115                &hunks
18116                    .map(|hunk| buffer_diff::DiffHunk {
18117                        buffer_range: hunk.buffer_range,
18118                        diff_base_byte_range: hunk.diff_base_byte_range,
18119                        secondary_status: hunk.secondary_status,
18120                        range: Point::zero()..Point::zero(), // unused
18121                    })
18122                    .collect::<Vec<_>>(),
18123                &buffer_snapshot,
18124                file_exists,
18125                cx,
18126            )
18127        });
18128        None
18129    }
18130
18131    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18132        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18133        self.buffer
18134            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18135    }
18136
18137    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18138        self.buffer.update(cx, |buffer, cx| {
18139            let ranges = vec![Anchor::min()..Anchor::max()];
18140            if !buffer.all_diff_hunks_expanded()
18141                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18142            {
18143                buffer.collapse_diff_hunks(ranges, cx);
18144                true
18145            } else {
18146                false
18147            }
18148        })
18149    }
18150
18151    fn toggle_diff_hunks_in_ranges(
18152        &mut self,
18153        ranges: Vec<Range<Anchor>>,
18154        cx: &mut Context<Editor>,
18155    ) {
18156        self.buffer.update(cx, |buffer, cx| {
18157            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18158            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18159        })
18160    }
18161
18162    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18163        self.buffer.update(cx, |buffer, cx| {
18164            let snapshot = buffer.snapshot(cx);
18165            let excerpt_id = range.end.excerpt_id;
18166            let point_range = range.to_point(&snapshot);
18167            let expand = !buffer.single_hunk_is_expanded(range, cx);
18168            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18169        })
18170    }
18171
18172    pub(crate) fn apply_all_diff_hunks(
18173        &mut self,
18174        _: &ApplyAllDiffHunks,
18175        window: &mut Window,
18176        cx: &mut Context<Self>,
18177    ) {
18178        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18179
18180        let buffers = self.buffer.read(cx).all_buffers();
18181        for branch_buffer in buffers {
18182            branch_buffer.update(cx, |branch_buffer, cx| {
18183                branch_buffer.merge_into_base(Vec::new(), cx);
18184            });
18185        }
18186
18187        if let Some(project) = self.project.clone() {
18188            self.save(
18189                SaveOptions {
18190                    format: true,
18191                    autosave: false,
18192                },
18193                project,
18194                window,
18195                cx,
18196            )
18197            .detach_and_log_err(cx);
18198        }
18199    }
18200
18201    pub(crate) fn apply_selected_diff_hunks(
18202        &mut self,
18203        _: &ApplyDiffHunk,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18208        let snapshot = self.snapshot(window, cx);
18209        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18210        let mut ranges_by_buffer = HashMap::default();
18211        self.transact(window, cx, |editor, _window, cx| {
18212            for hunk in hunks {
18213                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18214                    ranges_by_buffer
18215                        .entry(buffer.clone())
18216                        .or_insert_with(Vec::new)
18217                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18218                }
18219            }
18220
18221            for (buffer, ranges) in ranges_by_buffer {
18222                buffer.update(cx, |buffer, cx| {
18223                    buffer.merge_into_base(ranges, cx);
18224                });
18225            }
18226        });
18227
18228        if let Some(project) = self.project.clone() {
18229            self.save(
18230                SaveOptions {
18231                    format: true,
18232                    autosave: false,
18233                },
18234                project,
18235                window,
18236                cx,
18237            )
18238            .detach_and_log_err(cx);
18239        }
18240    }
18241
18242    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18243        if hovered != self.gutter_hovered {
18244            self.gutter_hovered = hovered;
18245            cx.notify();
18246        }
18247    }
18248
18249    pub fn insert_blocks(
18250        &mut self,
18251        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18252        autoscroll: Option<Autoscroll>,
18253        cx: &mut Context<Self>,
18254    ) -> Vec<CustomBlockId> {
18255        let blocks = self
18256            .display_map
18257            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18258        if let Some(autoscroll) = autoscroll {
18259            self.request_autoscroll(autoscroll, cx);
18260        }
18261        cx.notify();
18262        blocks
18263    }
18264
18265    pub fn resize_blocks(
18266        &mut self,
18267        heights: HashMap<CustomBlockId, u32>,
18268        autoscroll: Option<Autoscroll>,
18269        cx: &mut Context<Self>,
18270    ) {
18271        self.display_map
18272            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18273        if let Some(autoscroll) = autoscroll {
18274            self.request_autoscroll(autoscroll, cx);
18275        }
18276        cx.notify();
18277    }
18278
18279    pub fn replace_blocks(
18280        &mut self,
18281        renderers: HashMap<CustomBlockId, RenderBlock>,
18282        autoscroll: Option<Autoscroll>,
18283        cx: &mut Context<Self>,
18284    ) {
18285        self.display_map
18286            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18287        if let Some(autoscroll) = autoscroll {
18288            self.request_autoscroll(autoscroll, cx);
18289        }
18290        cx.notify();
18291    }
18292
18293    pub fn remove_blocks(
18294        &mut self,
18295        block_ids: HashSet<CustomBlockId>,
18296        autoscroll: Option<Autoscroll>,
18297        cx: &mut Context<Self>,
18298    ) {
18299        self.display_map.update(cx, |display_map, cx| {
18300            display_map.remove_blocks(block_ids, cx)
18301        });
18302        if let Some(autoscroll) = autoscroll {
18303            self.request_autoscroll(autoscroll, cx);
18304        }
18305        cx.notify();
18306    }
18307
18308    pub fn row_for_block(
18309        &self,
18310        block_id: CustomBlockId,
18311        cx: &mut Context<Self>,
18312    ) -> Option<DisplayRow> {
18313        self.display_map
18314            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18315    }
18316
18317    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18318        self.focused_block = Some(focused_block);
18319    }
18320
18321    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18322        self.focused_block.take()
18323    }
18324
18325    pub fn insert_creases(
18326        &mut self,
18327        creases: impl IntoIterator<Item = Crease<Anchor>>,
18328        cx: &mut Context<Self>,
18329    ) -> Vec<CreaseId> {
18330        self.display_map
18331            .update(cx, |map, cx| map.insert_creases(creases, cx))
18332    }
18333
18334    pub fn remove_creases(
18335        &mut self,
18336        ids: impl IntoIterator<Item = CreaseId>,
18337        cx: &mut Context<Self>,
18338    ) -> Vec<(CreaseId, Range<Anchor>)> {
18339        self.display_map
18340            .update(cx, |map, cx| map.remove_creases(ids, cx))
18341    }
18342
18343    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18344        self.display_map
18345            .update(cx, |map, cx| map.snapshot(cx))
18346            .longest_row()
18347    }
18348
18349    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18350        self.display_map
18351            .update(cx, |map, cx| map.snapshot(cx))
18352            .max_point()
18353    }
18354
18355    pub fn text(&self, cx: &App) -> String {
18356        self.buffer.read(cx).read(cx).text()
18357    }
18358
18359    pub fn is_empty(&self, cx: &App) -> bool {
18360        self.buffer.read(cx).read(cx).is_empty()
18361    }
18362
18363    pub fn text_option(&self, cx: &App) -> Option<String> {
18364        let text = self.text(cx);
18365        let text = text.trim();
18366
18367        if text.is_empty() {
18368            return None;
18369        }
18370
18371        Some(text.to_string())
18372    }
18373
18374    pub fn set_text(
18375        &mut self,
18376        text: impl Into<Arc<str>>,
18377        window: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        self.transact(window, cx, |this, _, cx| {
18381            this.buffer
18382                .read(cx)
18383                .as_singleton()
18384                .expect("you can only call set_text on editors for singleton buffers")
18385                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18386        });
18387    }
18388
18389    pub fn display_text(&self, cx: &mut App) -> String {
18390        self.display_map
18391            .update(cx, |map, cx| map.snapshot(cx))
18392            .text()
18393    }
18394
18395    fn create_minimap(
18396        &self,
18397        minimap_settings: MinimapSettings,
18398        window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) -> Option<Entity<Self>> {
18401        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18402            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18403    }
18404
18405    fn initialize_new_minimap(
18406        &self,
18407        minimap_settings: MinimapSettings,
18408        window: &mut Window,
18409        cx: &mut Context<Self>,
18410    ) -> Entity<Self> {
18411        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18412
18413        let mut minimap = Editor::new_internal(
18414            EditorMode::Minimap {
18415                parent: cx.weak_entity(),
18416            },
18417            self.buffer.clone(),
18418            None,
18419            Some(self.display_map.clone()),
18420            window,
18421            cx,
18422        );
18423        minimap.scroll_manager.clone_state(&self.scroll_manager);
18424        minimap.set_text_style_refinement(TextStyleRefinement {
18425            font_size: Some(MINIMAP_FONT_SIZE),
18426            font_weight: Some(MINIMAP_FONT_WEIGHT),
18427            ..Default::default()
18428        });
18429        minimap.update_minimap_configuration(minimap_settings, cx);
18430        cx.new(|_| minimap)
18431    }
18432
18433    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18434        let current_line_highlight = minimap_settings
18435            .current_line_highlight
18436            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18437        self.set_current_line_highlight(Some(current_line_highlight));
18438    }
18439
18440    pub fn minimap(&self) -> Option<&Entity<Self>> {
18441        self.minimap
18442            .as_ref()
18443            .filter(|_| self.minimap_visibility.visible())
18444    }
18445
18446    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18447        let mut wrap_guides = smallvec![];
18448
18449        if self.show_wrap_guides == Some(false) {
18450            return wrap_guides;
18451        }
18452
18453        let settings = self.buffer.read(cx).language_settings(cx);
18454        if settings.show_wrap_guides {
18455            match self.soft_wrap_mode(cx) {
18456                SoftWrap::Column(soft_wrap) => {
18457                    wrap_guides.push((soft_wrap as usize, true));
18458                }
18459                SoftWrap::Bounded(soft_wrap) => {
18460                    wrap_guides.push((soft_wrap as usize, true));
18461                }
18462                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18463            }
18464            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18465        }
18466
18467        wrap_guides
18468    }
18469
18470    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18471        let settings = self.buffer.read(cx).language_settings(cx);
18472        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18473        match mode {
18474            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18475                SoftWrap::None
18476            }
18477            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18478            language_settings::SoftWrap::PreferredLineLength => {
18479                SoftWrap::Column(settings.preferred_line_length)
18480            }
18481            language_settings::SoftWrap::Bounded => {
18482                SoftWrap::Bounded(settings.preferred_line_length)
18483            }
18484        }
18485    }
18486
18487    pub fn set_soft_wrap_mode(
18488        &mut self,
18489        mode: language_settings::SoftWrap,
18490
18491        cx: &mut Context<Self>,
18492    ) {
18493        self.soft_wrap_mode_override = Some(mode);
18494        cx.notify();
18495    }
18496
18497    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18498        self.hard_wrap = hard_wrap;
18499        cx.notify();
18500    }
18501
18502    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18503        self.text_style_refinement = Some(style);
18504    }
18505
18506    /// called by the Element so we know what style we were most recently rendered with.
18507    pub(crate) fn set_style(
18508        &mut self,
18509        style: EditorStyle,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        // We intentionally do not inform the display map about the minimap style
18514        // so that wrapping is not recalculated and stays consistent for the editor
18515        // and its linked minimap.
18516        if !self.mode.is_minimap() {
18517            let rem_size = window.rem_size();
18518            self.display_map.update(cx, |map, cx| {
18519                map.set_font(
18520                    style.text.font(),
18521                    style.text.font_size.to_pixels(rem_size),
18522                    cx,
18523                )
18524            });
18525        }
18526        self.style = Some(style);
18527    }
18528
18529    pub fn style(&self) -> Option<&EditorStyle> {
18530        self.style.as_ref()
18531    }
18532
18533    // Called by the element. This method is not designed to be called outside of the editor
18534    // element's layout code because it does not notify when rewrapping is computed synchronously.
18535    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18536        self.display_map
18537            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18538    }
18539
18540    pub fn set_soft_wrap(&mut self) {
18541        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18542    }
18543
18544    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18545        if self.soft_wrap_mode_override.is_some() {
18546            self.soft_wrap_mode_override.take();
18547        } else {
18548            let soft_wrap = match self.soft_wrap_mode(cx) {
18549                SoftWrap::GitDiff => return,
18550                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18551                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18552                    language_settings::SoftWrap::None
18553                }
18554            };
18555            self.soft_wrap_mode_override = Some(soft_wrap);
18556        }
18557        cx.notify();
18558    }
18559
18560    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18561        let Some(workspace) = self.workspace() else {
18562            return;
18563        };
18564        let fs = workspace.read(cx).app_state().fs.clone();
18565        let current_show = TabBarSettings::get_global(cx).show;
18566        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18567            setting.show = Some(!current_show);
18568        });
18569    }
18570
18571    pub fn toggle_indent_guides(
18572        &mut self,
18573        _: &ToggleIndentGuides,
18574        _: &mut Window,
18575        cx: &mut Context<Self>,
18576    ) {
18577        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18578            self.buffer
18579                .read(cx)
18580                .language_settings(cx)
18581                .indent_guides
18582                .enabled
18583        });
18584        self.show_indent_guides = Some(!currently_enabled);
18585        cx.notify();
18586    }
18587
18588    fn should_show_indent_guides(&self) -> Option<bool> {
18589        self.show_indent_guides
18590    }
18591
18592    pub fn toggle_line_numbers(
18593        &mut self,
18594        _: &ToggleLineNumbers,
18595        _: &mut Window,
18596        cx: &mut Context<Self>,
18597    ) {
18598        let mut editor_settings = EditorSettings::get_global(cx).clone();
18599        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18600        EditorSettings::override_global(editor_settings, cx);
18601    }
18602
18603    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18604        if let Some(show_line_numbers) = self.show_line_numbers {
18605            return show_line_numbers;
18606        }
18607        EditorSettings::get_global(cx).gutter.line_numbers
18608    }
18609
18610    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18611        self.use_relative_line_numbers
18612            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18613    }
18614
18615    pub fn toggle_relative_line_numbers(
18616        &mut self,
18617        _: &ToggleRelativeLineNumbers,
18618        _: &mut Window,
18619        cx: &mut Context<Self>,
18620    ) {
18621        let is_relative = self.should_use_relative_line_numbers(cx);
18622        self.set_relative_line_number(Some(!is_relative), cx)
18623    }
18624
18625    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18626        self.use_relative_line_numbers = is_relative;
18627        cx.notify();
18628    }
18629
18630    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18631        self.show_gutter = show_gutter;
18632        cx.notify();
18633    }
18634
18635    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18636        self.show_scrollbars = ScrollbarAxes {
18637            horizontal: show,
18638            vertical: show,
18639        };
18640        cx.notify();
18641    }
18642
18643    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18644        self.show_scrollbars.vertical = show;
18645        cx.notify();
18646    }
18647
18648    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18649        self.show_scrollbars.horizontal = show;
18650        cx.notify();
18651    }
18652
18653    pub fn set_minimap_visibility(
18654        &mut self,
18655        minimap_visibility: MinimapVisibility,
18656        window: &mut Window,
18657        cx: &mut Context<Self>,
18658    ) {
18659        if self.minimap_visibility != minimap_visibility {
18660            if minimap_visibility.visible() && self.minimap.is_none() {
18661                let minimap_settings = EditorSettings::get_global(cx).minimap;
18662                self.minimap =
18663                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18664            }
18665            self.minimap_visibility = minimap_visibility;
18666            cx.notify();
18667        }
18668    }
18669
18670    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18671        self.set_show_scrollbars(false, cx);
18672        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18673    }
18674
18675    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18676        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18677    }
18678
18679    /// Normally the text in full mode and auto height editors is padded on the
18680    /// left side by roughly half a character width for improved hit testing.
18681    ///
18682    /// Use this method to disable this for cases where this is not wanted (e.g.
18683    /// if you want to align the editor text with some other text above or below)
18684    /// or if you want to add this padding to single-line editors.
18685    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18686        self.offset_content = offset_content;
18687        cx.notify();
18688    }
18689
18690    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18691        self.show_line_numbers = Some(show_line_numbers);
18692        cx.notify();
18693    }
18694
18695    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18696        self.disable_expand_excerpt_buttons = true;
18697        cx.notify();
18698    }
18699
18700    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18701        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18702        cx.notify();
18703    }
18704
18705    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18706        self.show_code_actions = Some(show_code_actions);
18707        cx.notify();
18708    }
18709
18710    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18711        self.show_runnables = Some(show_runnables);
18712        cx.notify();
18713    }
18714
18715    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18716        self.show_breakpoints = Some(show_breakpoints);
18717        cx.notify();
18718    }
18719
18720    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18721        if self.display_map.read(cx).masked != masked {
18722            self.display_map.update(cx, |map, _| map.masked = masked);
18723        }
18724        cx.notify()
18725    }
18726
18727    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18728        self.show_wrap_guides = Some(show_wrap_guides);
18729        cx.notify();
18730    }
18731
18732    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18733        self.show_indent_guides = Some(show_indent_guides);
18734        cx.notify();
18735    }
18736
18737    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18738        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18739            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18740                && let Some(dir) = file.abs_path(cx).parent()
18741            {
18742                return Some(dir.to_owned());
18743            }
18744
18745            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18746                return Some(project_path.path.to_path_buf());
18747            }
18748        }
18749
18750        None
18751    }
18752
18753    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18754        self.active_excerpt(cx)?
18755            .1
18756            .read(cx)
18757            .file()
18758            .and_then(|f| f.as_local())
18759    }
18760
18761    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18762        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18763            let buffer = buffer.read(cx);
18764            if let Some(project_path) = buffer.project_path(cx) {
18765                let project = self.project()?.read(cx);
18766                project.absolute_path(&project_path, cx)
18767            } else {
18768                buffer
18769                    .file()
18770                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18771            }
18772        })
18773    }
18774
18775    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18776        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18777            let project_path = buffer.read(cx).project_path(cx)?;
18778            let project = self.project()?.read(cx);
18779            let entry = project.entry_for_path(&project_path, cx)?;
18780            let path = entry.path.to_path_buf();
18781            Some(path)
18782        })
18783    }
18784
18785    pub fn reveal_in_finder(
18786        &mut self,
18787        _: &RevealInFileManager,
18788        _window: &mut Window,
18789        cx: &mut Context<Self>,
18790    ) {
18791        if let Some(target) = self.target_file(cx) {
18792            cx.reveal_path(&target.abs_path(cx));
18793        }
18794    }
18795
18796    pub fn copy_path(
18797        &mut self,
18798        _: &zed_actions::workspace::CopyPath,
18799        _window: &mut Window,
18800        cx: &mut Context<Self>,
18801    ) {
18802        if let Some(path) = self.target_file_abs_path(cx)
18803            && let Some(path) = path.to_str()
18804        {
18805            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18806        }
18807    }
18808
18809    pub fn copy_relative_path(
18810        &mut self,
18811        _: &zed_actions::workspace::CopyRelativePath,
18812        _window: &mut Window,
18813        cx: &mut Context<Self>,
18814    ) {
18815        if let Some(path) = self.target_file_path(cx)
18816            && let Some(path) = path.to_str()
18817        {
18818            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18819        }
18820    }
18821
18822    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18823        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18824            buffer.read(cx).project_path(cx)
18825        } else {
18826            None
18827        }
18828    }
18829
18830    // Returns true if the editor handled a go-to-line request
18831    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18832        maybe!({
18833            let breakpoint_store = self.breakpoint_store.as_ref()?;
18834
18835            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18836            else {
18837                self.clear_row_highlights::<ActiveDebugLine>();
18838                return None;
18839            };
18840
18841            let position = active_stack_frame.position;
18842            let buffer_id = position.buffer_id?;
18843            let snapshot = self
18844                .project
18845                .as_ref()?
18846                .read(cx)
18847                .buffer_for_id(buffer_id, cx)?
18848                .read(cx)
18849                .snapshot();
18850
18851            let mut handled = false;
18852            for (id, ExcerptRange { context, .. }) in
18853                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18854            {
18855                if context.start.cmp(&position, &snapshot).is_ge()
18856                    || context.end.cmp(&position, &snapshot).is_lt()
18857                {
18858                    continue;
18859                }
18860                let snapshot = self.buffer.read(cx).snapshot(cx);
18861                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18862
18863                handled = true;
18864                self.clear_row_highlights::<ActiveDebugLine>();
18865
18866                self.go_to_line::<ActiveDebugLine>(
18867                    multibuffer_anchor,
18868                    Some(cx.theme().colors().editor_debugger_active_line_background),
18869                    window,
18870                    cx,
18871                );
18872
18873                cx.notify();
18874            }
18875
18876            handled.then_some(())
18877        })
18878        .is_some()
18879    }
18880
18881    pub fn copy_file_name_without_extension(
18882        &mut self,
18883        _: &CopyFileNameWithoutExtension,
18884        _: &mut Window,
18885        cx: &mut Context<Self>,
18886    ) {
18887        if let Some(file) = self.target_file(cx)
18888            && let Some(file_stem) = file.path().file_stem()
18889            && let Some(name) = file_stem.to_str()
18890        {
18891            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18892        }
18893    }
18894
18895    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18896        if let Some(file) = self.target_file(cx)
18897            && let Some(file_name) = file.path().file_name()
18898            && let Some(name) = file_name.to_str()
18899        {
18900            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18901        }
18902    }
18903
18904    pub fn toggle_git_blame(
18905        &mut self,
18906        _: &::git::Blame,
18907        window: &mut Window,
18908        cx: &mut Context<Self>,
18909    ) {
18910        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18911
18912        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18913            self.start_git_blame(true, window, cx);
18914        }
18915
18916        cx.notify();
18917    }
18918
18919    pub fn toggle_git_blame_inline(
18920        &mut self,
18921        _: &ToggleGitBlameInline,
18922        window: &mut Window,
18923        cx: &mut Context<Self>,
18924    ) {
18925        self.toggle_git_blame_inline_internal(true, window, cx);
18926        cx.notify();
18927    }
18928
18929    pub fn open_git_blame_commit(
18930        &mut self,
18931        _: &OpenGitBlameCommit,
18932        window: &mut Window,
18933        cx: &mut Context<Self>,
18934    ) {
18935        self.open_git_blame_commit_internal(window, cx);
18936    }
18937
18938    fn open_git_blame_commit_internal(
18939        &mut self,
18940        window: &mut Window,
18941        cx: &mut Context<Self>,
18942    ) -> Option<()> {
18943        let blame = self.blame.as_ref()?;
18944        let snapshot = self.snapshot(window, cx);
18945        let cursor = self.selections.newest::<Point>(cx).head();
18946        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18947        let blame_entry = blame
18948            .update(cx, |blame, cx| {
18949                blame
18950                    .blame_for_rows(
18951                        &[RowInfo {
18952                            buffer_id: Some(buffer.remote_id()),
18953                            buffer_row: Some(point.row),
18954                            ..Default::default()
18955                        }],
18956                        cx,
18957                    )
18958                    .next()
18959            })
18960            .flatten()?;
18961        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18962        let repo = blame.read(cx).repository(cx)?;
18963        let workspace = self.workspace()?.downgrade();
18964        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18965        None
18966    }
18967
18968    pub fn git_blame_inline_enabled(&self) -> bool {
18969        self.git_blame_inline_enabled
18970    }
18971
18972    pub fn toggle_selection_menu(
18973        &mut self,
18974        _: &ToggleSelectionMenu,
18975        _: &mut Window,
18976        cx: &mut Context<Self>,
18977    ) {
18978        self.show_selection_menu = self
18979            .show_selection_menu
18980            .map(|show_selections_menu| !show_selections_menu)
18981            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18982
18983        cx.notify();
18984    }
18985
18986    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18987        self.show_selection_menu
18988            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18989    }
18990
18991    fn start_git_blame(
18992        &mut self,
18993        user_triggered: bool,
18994        window: &mut Window,
18995        cx: &mut Context<Self>,
18996    ) {
18997        if let Some(project) = self.project() {
18998            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18999                return;
19000            };
19001
19002            if buffer.read(cx).file().is_none() {
19003                return;
19004            }
19005
19006            let focused = self.focus_handle(cx).contains_focused(window, cx);
19007
19008            let project = project.clone();
19009            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
19010            self.blame_subscription =
19011                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19012            self.blame = Some(blame);
19013        }
19014    }
19015
19016    fn toggle_git_blame_inline_internal(
19017        &mut self,
19018        user_triggered: bool,
19019        window: &mut Window,
19020        cx: &mut Context<Self>,
19021    ) {
19022        if self.git_blame_inline_enabled {
19023            self.git_blame_inline_enabled = false;
19024            self.show_git_blame_inline = false;
19025            self.show_git_blame_inline_delay_task.take();
19026        } else {
19027            self.git_blame_inline_enabled = true;
19028            self.start_git_blame_inline(user_triggered, window, cx);
19029        }
19030
19031        cx.notify();
19032    }
19033
19034    fn start_git_blame_inline(
19035        &mut self,
19036        user_triggered: bool,
19037        window: &mut Window,
19038        cx: &mut Context<Self>,
19039    ) {
19040        self.start_git_blame(user_triggered, window, cx);
19041
19042        if ProjectSettings::get_global(cx)
19043            .git
19044            .inline_blame_delay()
19045            .is_some()
19046        {
19047            self.start_inline_blame_timer(window, cx);
19048        } else {
19049            self.show_git_blame_inline = true
19050        }
19051    }
19052
19053    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19054        self.blame.as_ref()
19055    }
19056
19057    pub fn show_git_blame_gutter(&self) -> bool {
19058        self.show_git_blame_gutter
19059    }
19060
19061    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19062        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19063    }
19064
19065    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19066        self.show_git_blame_inline
19067            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19068            && !self.newest_selection_head_on_empty_line(cx)
19069            && self.has_blame_entries(cx)
19070    }
19071
19072    fn has_blame_entries(&self, cx: &App) -> bool {
19073        self.blame()
19074            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19075    }
19076
19077    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19078        let cursor_anchor = self.selections.newest_anchor().head();
19079
19080        let snapshot = self.buffer.read(cx).snapshot(cx);
19081        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19082
19083        snapshot.line_len(buffer_row) == 0
19084    }
19085
19086    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19087        let buffer_and_selection = maybe!({
19088            let selection = self.selections.newest::<Point>(cx);
19089            let selection_range = selection.range();
19090
19091            let multi_buffer = self.buffer().read(cx);
19092            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19093            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19094
19095            let (buffer, range, _) = if selection.reversed {
19096                buffer_ranges.first()
19097            } else {
19098                buffer_ranges.last()
19099            }?;
19100
19101            let selection = text::ToPoint::to_point(&range.start, buffer).row
19102                ..text::ToPoint::to_point(&range.end, buffer).row;
19103            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19104        });
19105
19106        let Some((buffer, selection)) = buffer_and_selection else {
19107            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19108        };
19109
19110        let Some(project) = self.project() else {
19111            return Task::ready(Err(anyhow!("editor does not have project")));
19112        };
19113
19114        project.update(cx, |project, cx| {
19115            project.get_permalink_to_line(&buffer, selection, cx)
19116        })
19117    }
19118
19119    pub fn copy_permalink_to_line(
19120        &mut self,
19121        _: &CopyPermalinkToLine,
19122        window: &mut Window,
19123        cx: &mut Context<Self>,
19124    ) {
19125        let permalink_task = self.get_permalink_to_line(cx);
19126        let workspace = self.workspace();
19127
19128        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19129            Ok(permalink) => {
19130                cx.update(|_, cx| {
19131                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19132                })
19133                .ok();
19134            }
19135            Err(err) => {
19136                let message = format!("Failed to copy permalink: {err}");
19137
19138                anyhow::Result::<()>::Err(err).log_err();
19139
19140                if let Some(workspace) = workspace {
19141                    workspace
19142                        .update_in(cx, |workspace, _, cx| {
19143                            struct CopyPermalinkToLine;
19144
19145                            workspace.show_toast(
19146                                Toast::new(
19147                                    NotificationId::unique::<CopyPermalinkToLine>(),
19148                                    message,
19149                                ),
19150                                cx,
19151                            )
19152                        })
19153                        .ok();
19154                }
19155            }
19156        })
19157        .detach();
19158    }
19159
19160    pub fn copy_file_location(
19161        &mut self,
19162        _: &CopyFileLocation,
19163        _: &mut Window,
19164        cx: &mut Context<Self>,
19165    ) {
19166        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19167        if let Some(file) = self.target_file(cx)
19168            && let Some(path) = file.path().to_str()
19169        {
19170            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19171        }
19172    }
19173
19174    pub fn open_permalink_to_line(
19175        &mut self,
19176        _: &OpenPermalinkToLine,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        let permalink_task = self.get_permalink_to_line(cx);
19181        let workspace = self.workspace();
19182
19183        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19184            Ok(permalink) => {
19185                cx.update(|_, cx| {
19186                    cx.open_url(permalink.as_ref());
19187                })
19188                .ok();
19189            }
19190            Err(err) => {
19191                let message = format!("Failed to open permalink: {err}");
19192
19193                anyhow::Result::<()>::Err(err).log_err();
19194
19195                if let Some(workspace) = workspace {
19196                    workspace
19197                        .update(cx, |workspace, cx| {
19198                            struct OpenPermalinkToLine;
19199
19200                            workspace.show_toast(
19201                                Toast::new(
19202                                    NotificationId::unique::<OpenPermalinkToLine>(),
19203                                    message,
19204                                ),
19205                                cx,
19206                            )
19207                        })
19208                        .ok();
19209                }
19210            }
19211        })
19212        .detach();
19213    }
19214
19215    pub fn insert_uuid_v4(
19216        &mut self,
19217        _: &InsertUuidV4,
19218        window: &mut Window,
19219        cx: &mut Context<Self>,
19220    ) {
19221        self.insert_uuid(UuidVersion::V4, window, cx);
19222    }
19223
19224    pub fn insert_uuid_v7(
19225        &mut self,
19226        _: &InsertUuidV7,
19227        window: &mut Window,
19228        cx: &mut Context<Self>,
19229    ) {
19230        self.insert_uuid(UuidVersion::V7, window, cx);
19231    }
19232
19233    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19234        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19235        self.transact(window, cx, |this, window, cx| {
19236            let edits = this
19237                .selections
19238                .all::<Point>(cx)
19239                .into_iter()
19240                .map(|selection| {
19241                    let uuid = match version {
19242                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19243                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19244                    };
19245
19246                    (selection.range(), uuid.to_string())
19247                });
19248            this.edit(edits, cx);
19249            this.refresh_edit_prediction(true, false, window, cx);
19250        });
19251    }
19252
19253    pub fn open_selections_in_multibuffer(
19254        &mut self,
19255        _: &OpenSelectionsInMultibuffer,
19256        window: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        let multibuffer = self.buffer.read(cx);
19260
19261        let Some(buffer) = multibuffer.as_singleton() else {
19262            return;
19263        };
19264
19265        let Some(workspace) = self.workspace() else {
19266            return;
19267        };
19268
19269        let title = multibuffer.title(cx).to_string();
19270
19271        let locations = self
19272            .selections
19273            .all_anchors(cx)
19274            .iter()
19275            .map(|selection| Location {
19276                buffer: buffer.clone(),
19277                range: selection.start.text_anchor..selection.end.text_anchor,
19278            })
19279            .collect::<Vec<_>>();
19280
19281        cx.spawn_in(window, async move |_, cx| {
19282            workspace.update_in(cx, |workspace, window, cx| {
19283                Self::open_locations_in_multibuffer(
19284                    workspace,
19285                    locations,
19286                    format!("Selections for '{title}'"),
19287                    false,
19288                    MultibufferSelectionMode::All,
19289                    window,
19290                    cx,
19291                );
19292            })
19293        })
19294        .detach();
19295    }
19296
19297    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19298    /// last highlight added will be used.
19299    ///
19300    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19301    pub fn highlight_rows<T: 'static>(
19302        &mut self,
19303        range: Range<Anchor>,
19304        color: Hsla,
19305        options: RowHighlightOptions,
19306        cx: &mut Context<Self>,
19307    ) {
19308        let snapshot = self.buffer().read(cx).snapshot(cx);
19309        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19310        let ix = row_highlights.binary_search_by(|highlight| {
19311            Ordering::Equal
19312                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19313                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19314        });
19315
19316        if let Err(mut ix) = ix {
19317            let index = post_inc(&mut self.highlight_order);
19318
19319            // If this range intersects with the preceding highlight, then merge it with
19320            // the preceding highlight. Otherwise insert a new highlight.
19321            let mut merged = false;
19322            if ix > 0 {
19323                let prev_highlight = &mut row_highlights[ix - 1];
19324                if prev_highlight
19325                    .range
19326                    .end
19327                    .cmp(&range.start, &snapshot)
19328                    .is_ge()
19329                {
19330                    ix -= 1;
19331                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19332                        prev_highlight.range.end = range.end;
19333                    }
19334                    merged = true;
19335                    prev_highlight.index = index;
19336                    prev_highlight.color = color;
19337                    prev_highlight.options = options;
19338                }
19339            }
19340
19341            if !merged {
19342                row_highlights.insert(
19343                    ix,
19344                    RowHighlight {
19345                        range,
19346                        index,
19347                        color,
19348                        options,
19349                        type_id: TypeId::of::<T>(),
19350                    },
19351                );
19352            }
19353
19354            // If any of the following highlights intersect with this one, merge them.
19355            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19356                let highlight = &row_highlights[ix];
19357                if next_highlight
19358                    .range
19359                    .start
19360                    .cmp(&highlight.range.end, &snapshot)
19361                    .is_le()
19362                {
19363                    if next_highlight
19364                        .range
19365                        .end
19366                        .cmp(&highlight.range.end, &snapshot)
19367                        .is_gt()
19368                    {
19369                        row_highlights[ix].range.end = next_highlight.range.end;
19370                    }
19371                    row_highlights.remove(ix + 1);
19372                } else {
19373                    break;
19374                }
19375            }
19376        }
19377    }
19378
19379    /// Remove any highlighted row ranges of the given type that intersect the
19380    /// given ranges.
19381    pub fn remove_highlighted_rows<T: 'static>(
19382        &mut self,
19383        ranges_to_remove: Vec<Range<Anchor>>,
19384        cx: &mut Context<Self>,
19385    ) {
19386        let snapshot = self.buffer().read(cx).snapshot(cx);
19387        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19388        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19389        row_highlights.retain(|highlight| {
19390            while let Some(range_to_remove) = ranges_to_remove.peek() {
19391                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19392                    Ordering::Less | Ordering::Equal => {
19393                        ranges_to_remove.next();
19394                    }
19395                    Ordering::Greater => {
19396                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19397                            Ordering::Less | Ordering::Equal => {
19398                                return false;
19399                            }
19400                            Ordering::Greater => break,
19401                        }
19402                    }
19403                }
19404            }
19405
19406            true
19407        })
19408    }
19409
19410    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19411    pub fn clear_row_highlights<T: 'static>(&mut self) {
19412        self.highlighted_rows.remove(&TypeId::of::<T>());
19413    }
19414
19415    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19416    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19417        self.highlighted_rows
19418            .get(&TypeId::of::<T>())
19419            .map_or(&[] as &[_], |vec| vec.as_slice())
19420            .iter()
19421            .map(|highlight| (highlight.range.clone(), highlight.color))
19422    }
19423
19424    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19425    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19426    /// Allows to ignore certain kinds of highlights.
19427    pub fn highlighted_display_rows(
19428        &self,
19429        window: &mut Window,
19430        cx: &mut App,
19431    ) -> BTreeMap<DisplayRow, LineHighlight> {
19432        let snapshot = self.snapshot(window, cx);
19433        let mut used_highlight_orders = HashMap::default();
19434        self.highlighted_rows
19435            .iter()
19436            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19437            .fold(
19438                BTreeMap::<DisplayRow, LineHighlight>::new(),
19439                |mut unique_rows, highlight| {
19440                    let start = highlight.range.start.to_display_point(&snapshot);
19441                    let end = highlight.range.end.to_display_point(&snapshot);
19442                    let start_row = start.row().0;
19443                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19444                        && end.column() == 0
19445                    {
19446                        end.row().0.saturating_sub(1)
19447                    } else {
19448                        end.row().0
19449                    };
19450                    for row in start_row..=end_row {
19451                        let used_index =
19452                            used_highlight_orders.entry(row).or_insert(highlight.index);
19453                        if highlight.index >= *used_index {
19454                            *used_index = highlight.index;
19455                            unique_rows.insert(
19456                                DisplayRow(row),
19457                                LineHighlight {
19458                                    include_gutter: highlight.options.include_gutter,
19459                                    border: None,
19460                                    background: highlight.color.into(),
19461                                    type_id: Some(highlight.type_id),
19462                                },
19463                            );
19464                        }
19465                    }
19466                    unique_rows
19467                },
19468            )
19469    }
19470
19471    pub fn highlighted_display_row_for_autoscroll(
19472        &self,
19473        snapshot: &DisplaySnapshot,
19474    ) -> Option<DisplayRow> {
19475        self.highlighted_rows
19476            .values()
19477            .flat_map(|highlighted_rows| highlighted_rows.iter())
19478            .filter_map(|highlight| {
19479                if highlight.options.autoscroll {
19480                    Some(highlight.range.start.to_display_point(snapshot).row())
19481                } else {
19482                    None
19483                }
19484            })
19485            .min()
19486    }
19487
19488    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19489        self.highlight_background::<SearchWithinRange>(
19490            ranges,
19491            |colors| colors.colors().editor_document_highlight_read_background,
19492            cx,
19493        )
19494    }
19495
19496    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19497        self.breadcrumb_header = Some(new_header);
19498    }
19499
19500    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19501        self.clear_background_highlights::<SearchWithinRange>(cx);
19502    }
19503
19504    pub fn highlight_background<T: 'static>(
19505        &mut self,
19506        ranges: &[Range<Anchor>],
19507        color_fetcher: fn(&Theme) -> Hsla,
19508        cx: &mut Context<Self>,
19509    ) {
19510        self.background_highlights.insert(
19511            HighlightKey::Type(TypeId::of::<T>()),
19512            (color_fetcher, Arc::from(ranges)),
19513        );
19514        self.scrollbar_marker_state.dirty = true;
19515        cx.notify();
19516    }
19517
19518    pub fn highlight_background_key<T: 'static>(
19519        &mut self,
19520        key: usize,
19521        ranges: &[Range<Anchor>],
19522        color_fetcher: fn(&Theme) -> Hsla,
19523        cx: &mut Context<Self>,
19524    ) {
19525        self.background_highlights.insert(
19526            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19527            (color_fetcher, Arc::from(ranges)),
19528        );
19529        self.scrollbar_marker_state.dirty = true;
19530        cx.notify();
19531    }
19532
19533    pub fn clear_background_highlights<T: 'static>(
19534        &mut self,
19535        cx: &mut Context<Self>,
19536    ) -> Option<BackgroundHighlight> {
19537        let text_highlights = self
19538            .background_highlights
19539            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19540        if !text_highlights.1.is_empty() {
19541            self.scrollbar_marker_state.dirty = true;
19542            cx.notify();
19543        }
19544        Some(text_highlights)
19545    }
19546
19547    pub fn highlight_gutter<T: 'static>(
19548        &mut self,
19549        ranges: impl Into<Vec<Range<Anchor>>>,
19550        color_fetcher: fn(&App) -> Hsla,
19551        cx: &mut Context<Self>,
19552    ) {
19553        self.gutter_highlights
19554            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19555        cx.notify();
19556    }
19557
19558    pub fn clear_gutter_highlights<T: 'static>(
19559        &mut self,
19560        cx: &mut Context<Self>,
19561    ) -> Option<GutterHighlight> {
19562        cx.notify();
19563        self.gutter_highlights.remove(&TypeId::of::<T>())
19564    }
19565
19566    pub fn insert_gutter_highlight<T: 'static>(
19567        &mut self,
19568        range: Range<Anchor>,
19569        color_fetcher: fn(&App) -> Hsla,
19570        cx: &mut Context<Self>,
19571    ) {
19572        let snapshot = self.buffer().read(cx).snapshot(cx);
19573        let mut highlights = self
19574            .gutter_highlights
19575            .remove(&TypeId::of::<T>())
19576            .map(|(_, highlights)| highlights)
19577            .unwrap_or_default();
19578        let ix = highlights.binary_search_by(|highlight| {
19579            Ordering::Equal
19580                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19581                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19582        });
19583        if let Err(ix) = ix {
19584            highlights.insert(ix, range);
19585        }
19586        self.gutter_highlights
19587            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19588    }
19589
19590    pub fn remove_gutter_highlights<T: 'static>(
19591        &mut self,
19592        ranges_to_remove: Vec<Range<Anchor>>,
19593        cx: &mut Context<Self>,
19594    ) {
19595        let snapshot = self.buffer().read(cx).snapshot(cx);
19596        let Some((color_fetcher, mut gutter_highlights)) =
19597            self.gutter_highlights.remove(&TypeId::of::<T>())
19598        else {
19599            return;
19600        };
19601        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19602        gutter_highlights.retain(|highlight| {
19603            while let Some(range_to_remove) = ranges_to_remove.peek() {
19604                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19605                    Ordering::Less | Ordering::Equal => {
19606                        ranges_to_remove.next();
19607                    }
19608                    Ordering::Greater => {
19609                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19610                            Ordering::Less | Ordering::Equal => {
19611                                return false;
19612                            }
19613                            Ordering::Greater => break,
19614                        }
19615                    }
19616                }
19617            }
19618
19619            true
19620        });
19621        self.gutter_highlights
19622            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19623    }
19624
19625    #[cfg(feature = "test-support")]
19626    pub fn all_text_highlights(
19627        &self,
19628        window: &mut Window,
19629        cx: &mut Context<Self>,
19630    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19631        let snapshot = self.snapshot(window, cx);
19632        self.display_map.update(cx, |display_map, _| {
19633            display_map
19634                .all_text_highlights()
19635                .map(|highlight| {
19636                    let (style, ranges) = highlight.as_ref();
19637                    (
19638                        *style,
19639                        ranges
19640                            .iter()
19641                            .map(|range| range.clone().to_display_points(&snapshot))
19642                            .collect(),
19643                    )
19644                })
19645                .collect()
19646        })
19647    }
19648
19649    #[cfg(feature = "test-support")]
19650    pub fn all_text_background_highlights(
19651        &self,
19652        window: &mut Window,
19653        cx: &mut Context<Self>,
19654    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19655        let snapshot = self.snapshot(window, cx);
19656        let buffer = &snapshot.buffer_snapshot;
19657        let start = buffer.anchor_before(0);
19658        let end = buffer.anchor_after(buffer.len());
19659        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19660    }
19661
19662    #[cfg(feature = "test-support")]
19663    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19664        let snapshot = self.buffer().read(cx).snapshot(cx);
19665
19666        let highlights = self
19667            .background_highlights
19668            .get(&HighlightKey::Type(TypeId::of::<
19669                items::BufferSearchHighlights,
19670            >()));
19671
19672        if let Some((_color, ranges)) = highlights {
19673            ranges
19674                .iter()
19675                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19676                .collect_vec()
19677        } else {
19678            vec![]
19679        }
19680    }
19681
19682    fn document_highlights_for_position<'a>(
19683        &'a self,
19684        position: Anchor,
19685        buffer: &'a MultiBufferSnapshot,
19686    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19687        let read_highlights = self
19688            .background_highlights
19689            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19690            .map(|h| &h.1);
19691        let write_highlights = self
19692            .background_highlights
19693            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19694            .map(|h| &h.1);
19695        let left_position = position.bias_left(buffer);
19696        let right_position = position.bias_right(buffer);
19697        read_highlights
19698            .into_iter()
19699            .chain(write_highlights)
19700            .flat_map(move |ranges| {
19701                let start_ix = match ranges.binary_search_by(|probe| {
19702                    let cmp = probe.end.cmp(&left_position, buffer);
19703                    if cmp.is_ge() {
19704                        Ordering::Greater
19705                    } else {
19706                        Ordering::Less
19707                    }
19708                }) {
19709                    Ok(i) | Err(i) => i,
19710                };
19711
19712                ranges[start_ix..]
19713                    .iter()
19714                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19715            })
19716    }
19717
19718    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19719        self.background_highlights
19720            .get(&HighlightKey::Type(TypeId::of::<T>()))
19721            .is_some_and(|(_, highlights)| !highlights.is_empty())
19722    }
19723
19724    pub fn background_highlights_in_range(
19725        &self,
19726        search_range: Range<Anchor>,
19727        display_snapshot: &DisplaySnapshot,
19728        theme: &Theme,
19729    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19730        let mut results = Vec::new();
19731        for (color_fetcher, ranges) in self.background_highlights.values() {
19732            let color = color_fetcher(theme);
19733            let start_ix = match ranges.binary_search_by(|probe| {
19734                let cmp = probe
19735                    .end
19736                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19737                if cmp.is_gt() {
19738                    Ordering::Greater
19739                } else {
19740                    Ordering::Less
19741                }
19742            }) {
19743                Ok(i) | Err(i) => i,
19744            };
19745            for range in &ranges[start_ix..] {
19746                if range
19747                    .start
19748                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19749                    .is_ge()
19750                {
19751                    break;
19752                }
19753
19754                let start = range.start.to_display_point(display_snapshot);
19755                let end = range.end.to_display_point(display_snapshot);
19756                results.push((start..end, color))
19757            }
19758        }
19759        results
19760    }
19761
19762    pub fn background_highlight_row_ranges<T: 'static>(
19763        &self,
19764        search_range: Range<Anchor>,
19765        display_snapshot: &DisplaySnapshot,
19766        count: usize,
19767    ) -> Vec<RangeInclusive<DisplayPoint>> {
19768        let mut results = Vec::new();
19769        let Some((_, ranges)) = self
19770            .background_highlights
19771            .get(&HighlightKey::Type(TypeId::of::<T>()))
19772        else {
19773            return vec![];
19774        };
19775
19776        let start_ix = match ranges.binary_search_by(|probe| {
19777            let cmp = probe
19778                .end
19779                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19780            if cmp.is_gt() {
19781                Ordering::Greater
19782            } else {
19783                Ordering::Less
19784            }
19785        }) {
19786            Ok(i) | Err(i) => i,
19787        };
19788        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19789            if let (Some(start_display), Some(end_display)) = (start, end) {
19790                results.push(
19791                    start_display.to_display_point(display_snapshot)
19792                        ..=end_display.to_display_point(display_snapshot),
19793                );
19794            }
19795        };
19796        let mut start_row: Option<Point> = None;
19797        let mut end_row: Option<Point> = None;
19798        if ranges.len() > count {
19799            return Vec::new();
19800        }
19801        for range in &ranges[start_ix..] {
19802            if range
19803                .start
19804                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19805                .is_ge()
19806            {
19807                break;
19808            }
19809            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19810            if let Some(current_row) = &end_row
19811                && end.row == current_row.row
19812            {
19813                continue;
19814            }
19815            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19816            if start_row.is_none() {
19817                assert_eq!(end_row, None);
19818                start_row = Some(start);
19819                end_row = Some(end);
19820                continue;
19821            }
19822            if let Some(current_end) = end_row.as_mut() {
19823                if start.row > current_end.row + 1 {
19824                    push_region(start_row, end_row);
19825                    start_row = Some(start);
19826                    end_row = Some(end);
19827                } else {
19828                    // Merge two hunks.
19829                    *current_end = end;
19830                }
19831            } else {
19832                unreachable!();
19833            }
19834        }
19835        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19836        push_region(start_row, end_row);
19837        results
19838    }
19839
19840    pub fn gutter_highlights_in_range(
19841        &self,
19842        search_range: Range<Anchor>,
19843        display_snapshot: &DisplaySnapshot,
19844        cx: &App,
19845    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19846        let mut results = Vec::new();
19847        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19848            let color = color_fetcher(cx);
19849            let start_ix = match ranges.binary_search_by(|probe| {
19850                let cmp = probe
19851                    .end
19852                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19853                if cmp.is_gt() {
19854                    Ordering::Greater
19855                } else {
19856                    Ordering::Less
19857                }
19858            }) {
19859                Ok(i) | Err(i) => i,
19860            };
19861            for range in &ranges[start_ix..] {
19862                if range
19863                    .start
19864                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19865                    .is_ge()
19866                {
19867                    break;
19868                }
19869
19870                let start = range.start.to_display_point(display_snapshot);
19871                let end = range.end.to_display_point(display_snapshot);
19872                results.push((start..end, color))
19873            }
19874        }
19875        results
19876    }
19877
19878    /// Get the text ranges corresponding to the redaction query
19879    pub fn redacted_ranges(
19880        &self,
19881        search_range: Range<Anchor>,
19882        display_snapshot: &DisplaySnapshot,
19883        cx: &App,
19884    ) -> Vec<Range<DisplayPoint>> {
19885        display_snapshot
19886            .buffer_snapshot
19887            .redacted_ranges(search_range, |file| {
19888                if let Some(file) = file {
19889                    file.is_private()
19890                        && EditorSettings::get(
19891                            Some(SettingsLocation {
19892                                worktree_id: file.worktree_id(cx),
19893                                path: file.path().as_ref(),
19894                            }),
19895                            cx,
19896                        )
19897                        .redact_private_values
19898                } else {
19899                    false
19900                }
19901            })
19902            .map(|range| {
19903                range.start.to_display_point(display_snapshot)
19904                    ..range.end.to_display_point(display_snapshot)
19905            })
19906            .collect()
19907    }
19908
19909    pub fn highlight_text_key<T: 'static>(
19910        &mut self,
19911        key: usize,
19912        ranges: Vec<Range<Anchor>>,
19913        style: HighlightStyle,
19914        cx: &mut Context<Self>,
19915    ) {
19916        self.display_map.update(cx, |map, _| {
19917            map.highlight_text(
19918                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19919                ranges,
19920                style,
19921            );
19922        });
19923        cx.notify();
19924    }
19925
19926    pub fn highlight_text<T: 'static>(
19927        &mut self,
19928        ranges: Vec<Range<Anchor>>,
19929        style: HighlightStyle,
19930        cx: &mut Context<Self>,
19931    ) {
19932        self.display_map.update(cx, |map, _| {
19933            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19934        });
19935        cx.notify();
19936    }
19937
19938    pub(crate) fn highlight_inlays<T: 'static>(
19939        &mut self,
19940        highlights: Vec<InlayHighlight>,
19941        style: HighlightStyle,
19942        cx: &mut Context<Self>,
19943    ) {
19944        self.display_map.update(cx, |map, _| {
19945            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19946        });
19947        cx.notify();
19948    }
19949
19950    pub fn text_highlights<'a, T: 'static>(
19951        &'a self,
19952        cx: &'a App,
19953    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19954        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19955    }
19956
19957    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19958        let cleared = self
19959            .display_map
19960            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19961        if cleared {
19962            cx.notify();
19963        }
19964    }
19965
19966    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19967        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19968            && self.focus_handle.is_focused(window)
19969    }
19970
19971    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19972        self.show_cursor_when_unfocused = is_enabled;
19973        cx.notify();
19974    }
19975
19976    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19977        cx.notify();
19978    }
19979
19980    fn on_debug_session_event(
19981        &mut self,
19982        _session: Entity<Session>,
19983        event: &SessionEvent,
19984        cx: &mut Context<Self>,
19985    ) {
19986        if let SessionEvent::InvalidateInlineValue = event {
19987            self.refresh_inline_values(cx);
19988        }
19989    }
19990
19991    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19992        let Some(project) = self.project.clone() else {
19993            return;
19994        };
19995
19996        if !self.inline_value_cache.enabled {
19997            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19998            self.splice_inlays(&inlays, Vec::new(), cx);
19999            return;
20000        }
20001
20002        let current_execution_position = self
20003            .highlighted_rows
20004            .get(&TypeId::of::<ActiveDebugLine>())
20005            .and_then(|lines| lines.last().map(|line| line.range.end));
20006
20007        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20008            let inline_values = editor
20009                .update(cx, |editor, cx| {
20010                    let Some(current_execution_position) = current_execution_position else {
20011                        return Some(Task::ready(Ok(Vec::new())));
20012                    };
20013
20014                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20015                        let snapshot = buffer.snapshot(cx);
20016
20017                        let excerpt = snapshot.excerpt_containing(
20018                            current_execution_position..current_execution_position,
20019                        )?;
20020
20021                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20022                    })?;
20023
20024                    let range =
20025                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20026
20027                    project.inline_values(buffer, range, cx)
20028                })
20029                .ok()
20030                .flatten()?
20031                .await
20032                .context("refreshing debugger inlays")
20033                .log_err()?;
20034
20035            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20036
20037            for (buffer_id, inline_value) in inline_values
20038                .into_iter()
20039                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20040            {
20041                buffer_inline_values
20042                    .entry(buffer_id)
20043                    .or_default()
20044                    .push(inline_value);
20045            }
20046
20047            editor
20048                .update(cx, |editor, cx| {
20049                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20050                    let mut new_inlays = Vec::default();
20051
20052                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20053                        let buffer_id = buffer_snapshot.remote_id();
20054                        buffer_inline_values
20055                            .get(&buffer_id)
20056                            .into_iter()
20057                            .flatten()
20058                            .for_each(|hint| {
20059                                let inlay = Inlay::debugger(
20060                                    post_inc(&mut editor.next_inlay_id),
20061                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20062                                    hint.text(),
20063                                );
20064                                if !inlay.text.chars().contains(&'\n') {
20065                                    new_inlays.push(inlay);
20066                                }
20067                            });
20068                    }
20069
20070                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20071                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20072
20073                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20074                })
20075                .ok()?;
20076            Some(())
20077        });
20078    }
20079
20080    fn on_buffer_event(
20081        &mut self,
20082        multibuffer: &Entity<MultiBuffer>,
20083        event: &multi_buffer::Event,
20084        window: &mut Window,
20085        cx: &mut Context<Self>,
20086    ) {
20087        match event {
20088            multi_buffer::Event::Edited {
20089                singleton_buffer_edited,
20090                edited_buffer,
20091            } => {
20092                self.scrollbar_marker_state.dirty = true;
20093                self.active_indent_guides_state.dirty = true;
20094                self.refresh_active_diagnostics(cx);
20095                self.refresh_code_actions(window, cx);
20096                self.refresh_selected_text_highlights(true, window, cx);
20097                self.refresh_single_line_folds(window, cx);
20098                refresh_matching_bracket_highlights(self, window, cx);
20099                if self.has_active_edit_prediction() {
20100                    self.update_visible_edit_prediction(window, cx);
20101                }
20102                if let Some(project) = self.project.as_ref()
20103                    && let Some(edited_buffer) = edited_buffer
20104                {
20105                    project.update(cx, |project, cx| {
20106                        self.registered_buffers
20107                            .entry(edited_buffer.read(cx).remote_id())
20108                            .or_insert_with(|| {
20109                                project.register_buffer_with_language_servers(edited_buffer, cx)
20110                            });
20111                    });
20112                }
20113                cx.emit(EditorEvent::BufferEdited);
20114                cx.emit(SearchEvent::MatchesInvalidated);
20115
20116                if let Some(buffer) = edited_buffer {
20117                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20118                }
20119
20120                if *singleton_buffer_edited {
20121                    if let Some(buffer) = edited_buffer
20122                        && buffer.read(cx).file().is_none()
20123                    {
20124                        cx.emit(EditorEvent::TitleChanged);
20125                    }
20126                    if let Some(project) = &self.project {
20127                        #[allow(clippy::mutable_key_type)]
20128                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20129                            multibuffer
20130                                .all_buffers()
20131                                .into_iter()
20132                                .filter_map(|buffer| {
20133                                    buffer.update(cx, |buffer, cx| {
20134                                        let language = buffer.language()?;
20135                                        let should_discard = project.update(cx, |project, cx| {
20136                                            project.is_local()
20137                                                && !project.has_language_servers_for(buffer, cx)
20138                                        });
20139                                        should_discard.not().then_some(language.clone())
20140                                    })
20141                                })
20142                                .collect::<HashSet<_>>()
20143                        });
20144                        if !languages_affected.is_empty() {
20145                            self.refresh_inlay_hints(
20146                                InlayHintRefreshReason::BufferEdited(languages_affected),
20147                                cx,
20148                            );
20149                        }
20150                    }
20151                }
20152
20153                let Some(project) = &self.project else { return };
20154                let (telemetry, is_via_ssh) = {
20155                    let project = project.read(cx);
20156                    let telemetry = project.client().telemetry().clone();
20157                    let is_via_ssh = project.is_via_remote_server();
20158                    (telemetry, is_via_ssh)
20159                };
20160                refresh_linked_ranges(self, window, cx);
20161                telemetry.log_edit_event("editor", is_via_ssh);
20162            }
20163            multi_buffer::Event::ExcerptsAdded {
20164                buffer,
20165                predecessor,
20166                excerpts,
20167            } => {
20168                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20169                let buffer_id = buffer.read(cx).remote_id();
20170                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20171                    && let Some(project) = &self.project
20172                {
20173                    update_uncommitted_diff_for_buffer(
20174                        cx.entity(),
20175                        project,
20176                        [buffer.clone()],
20177                        self.buffer.clone(),
20178                        cx,
20179                    )
20180                    .detach();
20181                }
20182                self.update_lsp_data(false, Some(buffer_id), window, cx);
20183                cx.emit(EditorEvent::ExcerptsAdded {
20184                    buffer: buffer.clone(),
20185                    predecessor: *predecessor,
20186                    excerpts: excerpts.clone(),
20187                });
20188                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20189            }
20190            multi_buffer::Event::ExcerptsRemoved {
20191                ids,
20192                removed_buffer_ids,
20193            } => {
20194                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20195                let buffer = self.buffer.read(cx);
20196                self.registered_buffers
20197                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20198                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20199                cx.emit(EditorEvent::ExcerptsRemoved {
20200                    ids: ids.clone(),
20201                    removed_buffer_ids: removed_buffer_ids.clone(),
20202                });
20203            }
20204            multi_buffer::Event::ExcerptsEdited {
20205                excerpt_ids,
20206                buffer_ids,
20207            } => {
20208                self.display_map.update(cx, |map, cx| {
20209                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20210                });
20211                cx.emit(EditorEvent::ExcerptsEdited {
20212                    ids: excerpt_ids.clone(),
20213                });
20214            }
20215            multi_buffer::Event::ExcerptsExpanded { ids } => {
20216                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20217                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20218            }
20219            multi_buffer::Event::Reparsed(buffer_id) => {
20220                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20221                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20222
20223                cx.emit(EditorEvent::Reparsed(*buffer_id));
20224            }
20225            multi_buffer::Event::DiffHunksToggled => {
20226                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20227            }
20228            multi_buffer::Event::LanguageChanged(buffer_id) => {
20229                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20230                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20231                cx.emit(EditorEvent::Reparsed(*buffer_id));
20232                cx.notify();
20233            }
20234            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20235            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20236            multi_buffer::Event::FileHandleChanged
20237            | multi_buffer::Event::Reloaded
20238            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20239            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20240            multi_buffer::Event::DiagnosticsUpdated => {
20241                self.update_diagnostics_state(window, cx);
20242            }
20243            _ => {}
20244        };
20245    }
20246
20247    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20248        if !self.diagnostics_enabled() {
20249            return;
20250        }
20251        self.refresh_active_diagnostics(cx);
20252        self.refresh_inline_diagnostics(true, window, cx);
20253        self.scrollbar_marker_state.dirty = true;
20254        cx.notify();
20255    }
20256
20257    pub fn start_temporary_diff_override(&mut self) {
20258        self.load_diff_task.take();
20259        self.temporary_diff_override = true;
20260    }
20261
20262    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20263        self.temporary_diff_override = false;
20264        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20265        self.buffer.update(cx, |buffer, cx| {
20266            buffer.set_all_diff_hunks_collapsed(cx);
20267        });
20268
20269        if let Some(project) = self.project.clone() {
20270            self.load_diff_task = Some(
20271                update_uncommitted_diff_for_buffer(
20272                    cx.entity(),
20273                    &project,
20274                    self.buffer.read(cx).all_buffers(),
20275                    self.buffer.clone(),
20276                    cx,
20277                )
20278                .shared(),
20279            );
20280        }
20281    }
20282
20283    fn on_display_map_changed(
20284        &mut self,
20285        _: Entity<DisplayMap>,
20286        _: &mut Window,
20287        cx: &mut Context<Self>,
20288    ) {
20289        cx.notify();
20290    }
20291
20292    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20293        if self.diagnostics_enabled() {
20294            let new_severity = EditorSettings::get_global(cx)
20295                .diagnostics_max_severity
20296                .unwrap_or(DiagnosticSeverity::Hint);
20297            self.set_max_diagnostics_severity(new_severity, cx);
20298        }
20299        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20300        self.update_edit_prediction_settings(cx);
20301        self.refresh_edit_prediction(true, false, window, cx);
20302        self.refresh_inline_values(cx);
20303        self.refresh_inlay_hints(
20304            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20305                self.selections.newest_anchor().head(),
20306                &self.buffer.read(cx).snapshot(cx),
20307                cx,
20308            )),
20309            cx,
20310        );
20311
20312        let old_cursor_shape = self.cursor_shape;
20313        let old_show_breadcrumbs = self.show_breadcrumbs;
20314
20315        {
20316            let editor_settings = EditorSettings::get_global(cx);
20317            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20318            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20319            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20320            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20321        }
20322
20323        if old_cursor_shape != self.cursor_shape {
20324            cx.emit(EditorEvent::CursorShapeChanged);
20325        }
20326
20327        if old_show_breadcrumbs != self.show_breadcrumbs {
20328            cx.emit(EditorEvent::BreadcrumbsChanged);
20329        }
20330
20331        let project_settings = ProjectSettings::get_global(cx);
20332        self.serialize_dirty_buffers =
20333            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20334
20335        if self.mode.is_full() {
20336            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20337            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20338            if self.show_inline_diagnostics != show_inline_diagnostics {
20339                self.show_inline_diagnostics = show_inline_diagnostics;
20340                self.refresh_inline_diagnostics(false, window, cx);
20341            }
20342
20343            if self.git_blame_inline_enabled != inline_blame_enabled {
20344                self.toggle_git_blame_inline_internal(false, window, cx);
20345            }
20346
20347            let minimap_settings = EditorSettings::get_global(cx).minimap;
20348            if self.minimap_visibility != MinimapVisibility::Disabled {
20349                if self.minimap_visibility.settings_visibility()
20350                    != minimap_settings.minimap_enabled()
20351                {
20352                    self.set_minimap_visibility(
20353                        MinimapVisibility::for_mode(self.mode(), cx),
20354                        window,
20355                        cx,
20356                    );
20357                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20358                    minimap_entity.update(cx, |minimap_editor, cx| {
20359                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20360                    })
20361                }
20362            }
20363        }
20364
20365        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20366            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20367        }) {
20368            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20369                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20370            }
20371            self.refresh_colors(false, None, window, cx);
20372        }
20373
20374        cx.notify();
20375    }
20376
20377    pub fn set_searchable(&mut self, searchable: bool) {
20378        self.searchable = searchable;
20379    }
20380
20381    pub fn searchable(&self) -> bool {
20382        self.searchable
20383    }
20384
20385    fn open_proposed_changes_editor(
20386        &mut self,
20387        _: &OpenProposedChangesEditor,
20388        window: &mut Window,
20389        cx: &mut Context<Self>,
20390    ) {
20391        let Some(workspace) = self.workspace() else {
20392            cx.propagate();
20393            return;
20394        };
20395
20396        let selections = self.selections.all::<usize>(cx);
20397        let multi_buffer = self.buffer.read(cx);
20398        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20399        let mut new_selections_by_buffer = HashMap::default();
20400        for selection in selections {
20401            for (buffer, range, _) in
20402                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20403            {
20404                let mut range = range.to_point(buffer);
20405                range.start.column = 0;
20406                range.end.column = buffer.line_len(range.end.row);
20407                new_selections_by_buffer
20408                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20409                    .or_insert(Vec::new())
20410                    .push(range)
20411            }
20412        }
20413
20414        let proposed_changes_buffers = new_selections_by_buffer
20415            .into_iter()
20416            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20417            .collect::<Vec<_>>();
20418        let proposed_changes_editor = cx.new(|cx| {
20419            ProposedChangesEditor::new(
20420                "Proposed changes",
20421                proposed_changes_buffers,
20422                self.project.clone(),
20423                window,
20424                cx,
20425            )
20426        });
20427
20428        window.defer(cx, move |window, cx| {
20429            workspace.update(cx, |workspace, cx| {
20430                workspace.active_pane().update(cx, |pane, cx| {
20431                    pane.add_item(
20432                        Box::new(proposed_changes_editor),
20433                        true,
20434                        true,
20435                        None,
20436                        window,
20437                        cx,
20438                    );
20439                });
20440            });
20441        });
20442    }
20443
20444    pub fn open_excerpts_in_split(
20445        &mut self,
20446        _: &OpenExcerptsSplit,
20447        window: &mut Window,
20448        cx: &mut Context<Self>,
20449    ) {
20450        self.open_excerpts_common(None, true, window, cx)
20451    }
20452
20453    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20454        self.open_excerpts_common(None, false, window, cx)
20455    }
20456
20457    fn open_excerpts_common(
20458        &mut self,
20459        jump_data: Option<JumpData>,
20460        split: bool,
20461        window: &mut Window,
20462        cx: &mut Context<Self>,
20463    ) {
20464        let Some(workspace) = self.workspace() else {
20465            cx.propagate();
20466            return;
20467        };
20468
20469        if self.buffer.read(cx).is_singleton() {
20470            cx.propagate();
20471            return;
20472        }
20473
20474        let mut new_selections_by_buffer = HashMap::default();
20475        match &jump_data {
20476            Some(JumpData::MultiBufferPoint {
20477                excerpt_id,
20478                position,
20479                anchor,
20480                line_offset_from_top,
20481            }) => {
20482                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20483                if let Some(buffer) = multi_buffer_snapshot
20484                    .buffer_id_for_excerpt(*excerpt_id)
20485                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20486                {
20487                    let buffer_snapshot = buffer.read(cx).snapshot();
20488                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20489                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20490                    } else {
20491                        buffer_snapshot.clip_point(*position, Bias::Left)
20492                    };
20493                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20494                    new_selections_by_buffer.insert(
20495                        buffer,
20496                        (
20497                            vec![jump_to_offset..jump_to_offset],
20498                            Some(*line_offset_from_top),
20499                        ),
20500                    );
20501                }
20502            }
20503            Some(JumpData::MultiBufferRow {
20504                row,
20505                line_offset_from_top,
20506            }) => {
20507                let point = MultiBufferPoint::new(row.0, 0);
20508                if let Some((buffer, buffer_point, _)) =
20509                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20510                {
20511                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20512                    new_selections_by_buffer
20513                        .entry(buffer)
20514                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20515                        .0
20516                        .push(buffer_offset..buffer_offset)
20517                }
20518            }
20519            None => {
20520                let selections = self.selections.all::<usize>(cx);
20521                let multi_buffer = self.buffer.read(cx);
20522                for selection in selections {
20523                    for (snapshot, range, _, anchor) in multi_buffer
20524                        .snapshot(cx)
20525                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20526                    {
20527                        if let Some(anchor) = anchor {
20528                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20529                            else {
20530                                continue;
20531                            };
20532                            let offset = text::ToOffset::to_offset(
20533                                &anchor.text_anchor,
20534                                &buffer_handle.read(cx).snapshot(),
20535                            );
20536                            let range = offset..offset;
20537                            new_selections_by_buffer
20538                                .entry(buffer_handle)
20539                                .or_insert((Vec::new(), None))
20540                                .0
20541                                .push(range)
20542                        } else {
20543                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20544                            else {
20545                                continue;
20546                            };
20547                            new_selections_by_buffer
20548                                .entry(buffer_handle)
20549                                .or_insert((Vec::new(), None))
20550                                .0
20551                                .push(range)
20552                        }
20553                    }
20554                }
20555            }
20556        }
20557
20558        new_selections_by_buffer
20559            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20560
20561        if new_selections_by_buffer.is_empty() {
20562            return;
20563        }
20564
20565        // We defer the pane interaction because we ourselves are a workspace item
20566        // and activating a new item causes the pane to call a method on us reentrantly,
20567        // which panics if we're on the stack.
20568        window.defer(cx, move |window, cx| {
20569            workspace.update(cx, |workspace, cx| {
20570                let pane = if split {
20571                    workspace.adjacent_pane(window, cx)
20572                } else {
20573                    workspace.active_pane().clone()
20574                };
20575
20576                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20577                    let editor = buffer
20578                        .read(cx)
20579                        .file()
20580                        .is_none()
20581                        .then(|| {
20582                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20583                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20584                            // Instead, we try to activate the existing editor in the pane first.
20585                            let (editor, pane_item_index) =
20586                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20587                                    let editor = item.downcast::<Editor>()?;
20588                                    let singleton_buffer =
20589                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20590                                    if singleton_buffer == buffer {
20591                                        Some((editor, i))
20592                                    } else {
20593                                        None
20594                                    }
20595                                })?;
20596                            pane.update(cx, |pane, cx| {
20597                                pane.activate_item(pane_item_index, true, true, window, cx)
20598                            });
20599                            Some(editor)
20600                        })
20601                        .flatten()
20602                        .unwrap_or_else(|| {
20603                            workspace.open_project_item::<Self>(
20604                                pane.clone(),
20605                                buffer,
20606                                true,
20607                                true,
20608                                window,
20609                                cx,
20610                            )
20611                        });
20612
20613                    editor.update(cx, |editor, cx| {
20614                        let autoscroll = match scroll_offset {
20615                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20616                            None => Autoscroll::newest(),
20617                        };
20618                        let nav_history = editor.nav_history.take();
20619                        editor.change_selections(
20620                            SelectionEffects::scroll(autoscroll),
20621                            window,
20622                            cx,
20623                            |s| {
20624                                s.select_ranges(ranges);
20625                            },
20626                        );
20627                        editor.nav_history = nav_history;
20628                    });
20629                }
20630            })
20631        });
20632    }
20633
20634    // For now, don't allow opening excerpts in buffers that aren't backed by
20635    // regular project files.
20636    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20637        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20638    }
20639
20640    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20641        let snapshot = self.buffer.read(cx).read(cx);
20642        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20643        Some(
20644            ranges
20645                .iter()
20646                .map(move |range| {
20647                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20648                })
20649                .collect(),
20650        )
20651    }
20652
20653    fn selection_replacement_ranges(
20654        &self,
20655        range: Range<OffsetUtf16>,
20656        cx: &mut App,
20657    ) -> Vec<Range<OffsetUtf16>> {
20658        let selections = self.selections.all::<OffsetUtf16>(cx);
20659        let newest_selection = selections
20660            .iter()
20661            .max_by_key(|selection| selection.id)
20662            .unwrap();
20663        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20664        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20665        let snapshot = self.buffer.read(cx).read(cx);
20666        selections
20667            .into_iter()
20668            .map(|mut selection| {
20669                selection.start.0 =
20670                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20671                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20672                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20673                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20674            })
20675            .collect()
20676    }
20677
20678    fn report_editor_event(
20679        &self,
20680        reported_event: ReportEditorEvent,
20681        file_extension: Option<String>,
20682        cx: &App,
20683    ) {
20684        if cfg!(any(test, feature = "test-support")) {
20685            return;
20686        }
20687
20688        let Some(project) = &self.project else { return };
20689
20690        // If None, we are in a file without an extension
20691        let file = self
20692            .buffer
20693            .read(cx)
20694            .as_singleton()
20695            .and_then(|b| b.read(cx).file());
20696        let file_extension = file_extension.or(file
20697            .as_ref()
20698            .and_then(|file| Path::new(file.file_name(cx)).extension())
20699            .and_then(|e| e.to_str())
20700            .map(|a| a.to_string()));
20701
20702        let vim_mode = vim_enabled(cx);
20703
20704        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20705        let copilot_enabled = edit_predictions_provider
20706            == language::language_settings::EditPredictionProvider::Copilot;
20707        let copilot_enabled_for_language = self
20708            .buffer
20709            .read(cx)
20710            .language_settings(cx)
20711            .show_edit_predictions;
20712
20713        let project = project.read(cx);
20714        let event_type = reported_event.event_type();
20715
20716        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20717            telemetry::event!(
20718                event_type,
20719                type = if auto_saved {"autosave"} else {"manual"},
20720                file_extension,
20721                vim_mode,
20722                copilot_enabled,
20723                copilot_enabled_for_language,
20724                edit_predictions_provider,
20725                is_via_ssh = project.is_via_remote_server(),
20726            );
20727        } else {
20728            telemetry::event!(
20729                event_type,
20730                file_extension,
20731                vim_mode,
20732                copilot_enabled,
20733                copilot_enabled_for_language,
20734                edit_predictions_provider,
20735                is_via_ssh = project.is_via_remote_server(),
20736            );
20737        };
20738    }
20739
20740    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20741    /// with each line being an array of {text, highlight} objects.
20742    fn copy_highlight_json(
20743        &mut self,
20744        _: &CopyHighlightJson,
20745        window: &mut Window,
20746        cx: &mut Context<Self>,
20747    ) {
20748        #[derive(Serialize)]
20749        struct Chunk<'a> {
20750            text: String,
20751            highlight: Option<&'a str>,
20752        }
20753
20754        let snapshot = self.buffer.read(cx).snapshot(cx);
20755        let range = self
20756            .selected_text_range(false, window, cx)
20757            .and_then(|selection| {
20758                if selection.range.is_empty() {
20759                    None
20760                } else {
20761                    Some(selection.range)
20762                }
20763            })
20764            .unwrap_or_else(|| 0..snapshot.len());
20765
20766        let chunks = snapshot.chunks(range, true);
20767        let mut lines = Vec::new();
20768        let mut line: VecDeque<Chunk> = VecDeque::new();
20769
20770        let Some(style) = self.style.as_ref() else {
20771            return;
20772        };
20773
20774        for chunk in chunks {
20775            let highlight = chunk
20776                .syntax_highlight_id
20777                .and_then(|id| id.name(&style.syntax));
20778            let mut chunk_lines = chunk.text.split('\n').peekable();
20779            while let Some(text) = chunk_lines.next() {
20780                let mut merged_with_last_token = false;
20781                if let Some(last_token) = line.back_mut()
20782                    && last_token.highlight == highlight
20783                {
20784                    last_token.text.push_str(text);
20785                    merged_with_last_token = true;
20786                }
20787
20788                if !merged_with_last_token {
20789                    line.push_back(Chunk {
20790                        text: text.into(),
20791                        highlight,
20792                    });
20793                }
20794
20795                if chunk_lines.peek().is_some() {
20796                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20797                        line.pop_front();
20798                    }
20799                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20800                        line.pop_back();
20801                    }
20802
20803                    lines.push(mem::take(&mut line));
20804                }
20805            }
20806        }
20807
20808        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20809            return;
20810        };
20811        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20812    }
20813
20814    pub fn open_context_menu(
20815        &mut self,
20816        _: &OpenContextMenu,
20817        window: &mut Window,
20818        cx: &mut Context<Self>,
20819    ) {
20820        self.request_autoscroll(Autoscroll::newest(), cx);
20821        let position = self.selections.newest_display(cx).start;
20822        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20823    }
20824
20825    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20826        &self.inlay_hint_cache
20827    }
20828
20829    pub fn replay_insert_event(
20830        &mut self,
20831        text: &str,
20832        relative_utf16_range: Option<Range<isize>>,
20833        window: &mut Window,
20834        cx: &mut Context<Self>,
20835    ) {
20836        if !self.input_enabled {
20837            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20838            return;
20839        }
20840        if let Some(relative_utf16_range) = relative_utf16_range {
20841            let selections = self.selections.all::<OffsetUtf16>(cx);
20842            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20843                let new_ranges = selections.into_iter().map(|range| {
20844                    let start = OffsetUtf16(
20845                        range
20846                            .head()
20847                            .0
20848                            .saturating_add_signed(relative_utf16_range.start),
20849                    );
20850                    let end = OffsetUtf16(
20851                        range
20852                            .head()
20853                            .0
20854                            .saturating_add_signed(relative_utf16_range.end),
20855                    );
20856                    start..end
20857                });
20858                s.select_ranges(new_ranges);
20859            });
20860        }
20861
20862        self.handle_input(text, window, cx);
20863    }
20864
20865    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20866        let Some(provider) = self.semantics_provider.as_ref() else {
20867            return false;
20868        };
20869
20870        let mut supports = false;
20871        self.buffer().update(cx, |this, cx| {
20872            this.for_each_buffer(|buffer| {
20873                supports |= provider.supports_inlay_hints(buffer, cx);
20874            });
20875        });
20876
20877        supports
20878    }
20879
20880    pub fn is_focused(&self, window: &Window) -> bool {
20881        self.focus_handle.is_focused(window)
20882    }
20883
20884    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20885        cx.emit(EditorEvent::Focused);
20886
20887        if let Some(descendant) = self
20888            .last_focused_descendant
20889            .take()
20890            .and_then(|descendant| descendant.upgrade())
20891        {
20892            window.focus(&descendant);
20893        } else {
20894            if let Some(blame) = self.blame.as_ref() {
20895                blame.update(cx, GitBlame::focus)
20896            }
20897
20898            self.blink_manager.update(cx, BlinkManager::enable);
20899            self.show_cursor_names(window, cx);
20900            self.buffer.update(cx, |buffer, cx| {
20901                buffer.finalize_last_transaction(cx);
20902                if self.leader_id.is_none() {
20903                    buffer.set_active_selections(
20904                        &self.selections.disjoint_anchors(),
20905                        self.selections.line_mode,
20906                        self.cursor_shape,
20907                        cx,
20908                    );
20909                }
20910            });
20911        }
20912    }
20913
20914    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20915        cx.emit(EditorEvent::FocusedIn)
20916    }
20917
20918    fn handle_focus_out(
20919        &mut self,
20920        event: FocusOutEvent,
20921        _window: &mut Window,
20922        cx: &mut Context<Self>,
20923    ) {
20924        if event.blurred != self.focus_handle {
20925            self.last_focused_descendant = Some(event.blurred);
20926        }
20927        self.selection_drag_state = SelectionDragState::None;
20928        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20929    }
20930
20931    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20932        self.blink_manager.update(cx, BlinkManager::disable);
20933        self.buffer
20934            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20935
20936        if let Some(blame) = self.blame.as_ref() {
20937            blame.update(cx, GitBlame::blur)
20938        }
20939        if !self.hover_state.focused(window, cx) {
20940            hide_hover(self, cx);
20941        }
20942        if !self
20943            .context_menu
20944            .borrow()
20945            .as_ref()
20946            .is_some_and(|context_menu| context_menu.focused(window, cx))
20947        {
20948            self.hide_context_menu(window, cx);
20949        }
20950        self.discard_edit_prediction(false, cx);
20951        cx.emit(EditorEvent::Blurred);
20952        cx.notify();
20953    }
20954
20955    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20956        let mut pending: String = window
20957            .pending_input_keystrokes()
20958            .into_iter()
20959            .flatten()
20960            .filter_map(|keystroke| {
20961                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20962                    keystroke.key_char.clone()
20963                } else {
20964                    None
20965                }
20966            })
20967            .collect();
20968
20969        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20970            pending = "".to_string();
20971        }
20972
20973        let existing_pending = self
20974            .text_highlights::<PendingInput>(cx)
20975            .map(|(_, ranges)| ranges.to_vec());
20976        if existing_pending.is_none() && pending.is_empty() {
20977            return;
20978        }
20979        let transaction =
20980            self.transact(window, cx, |this, window, cx| {
20981                let selections = this.selections.all::<usize>(cx);
20982                let edits = selections
20983                    .iter()
20984                    .map(|selection| (selection.end..selection.end, pending.clone()));
20985                this.edit(edits, cx);
20986                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20987                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20988                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20989                    }));
20990                });
20991                if let Some(existing_ranges) = existing_pending {
20992                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20993                    this.edit(edits, cx);
20994                }
20995            });
20996
20997        let snapshot = self.snapshot(window, cx);
20998        let ranges = self
20999            .selections
21000            .all::<usize>(cx)
21001            .into_iter()
21002            .map(|selection| {
21003                snapshot.buffer_snapshot.anchor_after(selection.end)
21004                    ..snapshot
21005                        .buffer_snapshot
21006                        .anchor_before(selection.end + pending.len())
21007            })
21008            .collect();
21009
21010        if pending.is_empty() {
21011            self.clear_highlights::<PendingInput>(cx);
21012        } else {
21013            self.highlight_text::<PendingInput>(
21014                ranges,
21015                HighlightStyle {
21016                    underline: Some(UnderlineStyle {
21017                        thickness: px(1.),
21018                        color: None,
21019                        wavy: false,
21020                    }),
21021                    ..Default::default()
21022                },
21023                cx,
21024            );
21025        }
21026
21027        self.ime_transaction = self.ime_transaction.or(transaction);
21028        if let Some(transaction) = self.ime_transaction {
21029            self.buffer.update(cx, |buffer, cx| {
21030                buffer.group_until_transaction(transaction, cx);
21031            });
21032        }
21033
21034        if self.text_highlights::<PendingInput>(cx).is_none() {
21035            self.ime_transaction.take();
21036        }
21037    }
21038
21039    pub fn register_action_renderer(
21040        &mut self,
21041        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21042    ) -> Subscription {
21043        let id = self.next_editor_action_id.post_inc();
21044        self.editor_actions
21045            .borrow_mut()
21046            .insert(id, Box::new(listener));
21047
21048        let editor_actions = self.editor_actions.clone();
21049        Subscription::new(move || {
21050            editor_actions.borrow_mut().remove(&id);
21051        })
21052    }
21053
21054    pub fn register_action<A: Action>(
21055        &mut self,
21056        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21057    ) -> Subscription {
21058        let id = self.next_editor_action_id.post_inc();
21059        let listener = Arc::new(listener);
21060        self.editor_actions.borrow_mut().insert(
21061            id,
21062            Box::new(move |_, window, _| {
21063                let listener = listener.clone();
21064                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21065                    let action = action.downcast_ref().unwrap();
21066                    if phase == DispatchPhase::Bubble {
21067                        listener(action, window, cx)
21068                    }
21069                })
21070            }),
21071        );
21072
21073        let editor_actions = self.editor_actions.clone();
21074        Subscription::new(move || {
21075            editor_actions.borrow_mut().remove(&id);
21076        })
21077    }
21078
21079    pub fn file_header_size(&self) -> u32 {
21080        FILE_HEADER_HEIGHT
21081    }
21082
21083    pub fn restore(
21084        &mut self,
21085        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21086        window: &mut Window,
21087        cx: &mut Context<Self>,
21088    ) {
21089        let workspace = self.workspace();
21090        let project = self.project();
21091        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21092            let mut tasks = Vec::new();
21093            for (buffer_id, changes) in revert_changes {
21094                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21095                    buffer.update(cx, |buffer, cx| {
21096                        buffer.edit(
21097                            changes
21098                                .into_iter()
21099                                .map(|(range, text)| (range, text.to_string())),
21100                            None,
21101                            cx,
21102                        );
21103                    });
21104
21105                    if let Some(project) =
21106                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21107                    {
21108                        project.update(cx, |project, cx| {
21109                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21110                        })
21111                    }
21112                }
21113            }
21114            tasks
21115        });
21116        cx.spawn_in(window, async move |_, cx| {
21117            for (buffer, task) in save_tasks {
21118                let result = task.await;
21119                if result.is_err() {
21120                    let Some(path) = buffer
21121                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21122                        .ok()
21123                    else {
21124                        continue;
21125                    };
21126                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21127                        let Some(task) = cx
21128                            .update_window_entity(workspace, |workspace, window, cx| {
21129                                workspace
21130                                    .open_path_preview(path, None, false, false, false, window, cx)
21131                            })
21132                            .ok()
21133                        else {
21134                            continue;
21135                        };
21136                        task.await.log_err();
21137                    }
21138                }
21139            }
21140        })
21141        .detach();
21142        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21143            selections.refresh()
21144        });
21145    }
21146
21147    pub fn to_pixel_point(
21148        &self,
21149        source: multi_buffer::Anchor,
21150        editor_snapshot: &EditorSnapshot,
21151        window: &mut Window,
21152    ) -> Option<gpui::Point<Pixels>> {
21153        let source_point = source.to_display_point(editor_snapshot);
21154        self.display_to_pixel_point(source_point, editor_snapshot, window)
21155    }
21156
21157    pub fn display_to_pixel_point(
21158        &self,
21159        source: DisplayPoint,
21160        editor_snapshot: &EditorSnapshot,
21161        window: &mut Window,
21162    ) -> Option<gpui::Point<Pixels>> {
21163        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21164        let text_layout_details = self.text_layout_details(window);
21165        let scroll_top = text_layout_details
21166            .scroll_anchor
21167            .scroll_position(editor_snapshot)
21168            .y;
21169
21170        if source.row().as_f32() < scroll_top.floor() {
21171            return None;
21172        }
21173        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21174        let source_y = line_height * (source.row().as_f32() - scroll_top);
21175        Some(gpui::Point::new(source_x, source_y))
21176    }
21177
21178    pub fn has_visible_completions_menu(&self) -> bool {
21179        !self.edit_prediction_preview_is_active()
21180            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21181                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21182            })
21183    }
21184
21185    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21186        if self.mode.is_minimap() {
21187            return;
21188        }
21189        self.addons
21190            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21191    }
21192
21193    pub fn unregister_addon<T: Addon>(&mut self) {
21194        self.addons.remove(&std::any::TypeId::of::<T>());
21195    }
21196
21197    pub fn addon<T: Addon>(&self) -> Option<&T> {
21198        let type_id = std::any::TypeId::of::<T>();
21199        self.addons
21200            .get(&type_id)
21201            .and_then(|item| item.to_any().downcast_ref::<T>())
21202    }
21203
21204    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21205        let type_id = std::any::TypeId::of::<T>();
21206        self.addons
21207            .get_mut(&type_id)
21208            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21209    }
21210
21211    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21212        let text_layout_details = self.text_layout_details(window);
21213        let style = &text_layout_details.editor_style;
21214        let font_id = window.text_system().resolve_font(&style.text.font());
21215        let font_size = style.text.font_size.to_pixels(window.rem_size());
21216        let line_height = style.text.line_height_in_pixels(window.rem_size());
21217        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21218        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21219
21220        CharacterDimensions {
21221            em_width,
21222            em_advance,
21223            line_height,
21224        }
21225    }
21226
21227    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21228        self.load_diff_task.clone()
21229    }
21230
21231    fn read_metadata_from_db(
21232        &mut self,
21233        item_id: u64,
21234        workspace_id: WorkspaceId,
21235        window: &mut Window,
21236        cx: &mut Context<Editor>,
21237    ) {
21238        if self.is_singleton(cx)
21239            && !self.mode.is_minimap()
21240            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21241        {
21242            let buffer_snapshot = OnceCell::new();
21243
21244            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21245                && !folds.is_empty()
21246            {
21247                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21248                self.fold_ranges(
21249                    folds
21250                        .into_iter()
21251                        .map(|(start, end)| {
21252                            snapshot.clip_offset(start, Bias::Left)
21253                                ..snapshot.clip_offset(end, Bias::Right)
21254                        })
21255                        .collect(),
21256                    false,
21257                    window,
21258                    cx,
21259                );
21260            }
21261
21262            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21263                && !selections.is_empty()
21264            {
21265                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21266                // skip adding the initial selection to selection history
21267                self.selection_history.mode = SelectionHistoryMode::Skipping;
21268                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21269                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21270                        snapshot.clip_offset(start, Bias::Left)
21271                            ..snapshot.clip_offset(end, Bias::Right)
21272                    }));
21273                });
21274                self.selection_history.mode = SelectionHistoryMode::Normal;
21275            };
21276        }
21277
21278        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21279    }
21280
21281    fn update_lsp_data(
21282        &mut self,
21283        ignore_cache: bool,
21284        for_buffer: Option<BufferId>,
21285        window: &mut Window,
21286        cx: &mut Context<'_, Self>,
21287    ) {
21288        self.pull_diagnostics(for_buffer, window, cx);
21289        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21290    }
21291}
21292
21293fn vim_enabled(cx: &App) -> bool {
21294    cx.global::<SettingsStore>()
21295        .raw_user_settings()
21296        .get("vim_mode")
21297        == Some(&serde_json::Value::Bool(true))
21298}
21299
21300fn process_completion_for_edit(
21301    completion: &Completion,
21302    intent: CompletionIntent,
21303    buffer: &Entity<Buffer>,
21304    cursor_position: &text::Anchor,
21305    cx: &mut Context<Editor>,
21306) -> CompletionEdit {
21307    let buffer = buffer.read(cx);
21308    let buffer_snapshot = buffer.snapshot();
21309    let (snippet, new_text) = if completion.is_snippet() {
21310        // Workaround for typescript language server issues so that methods don't expand within
21311        // strings and functions with type expressions. The previous point is used because the query
21312        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21313        let mut snippet_source = completion.new_text.clone();
21314        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21315        previous_point.column = previous_point.column.saturating_sub(1);
21316        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21317            && scope.prefers_label_for_snippet_in_completion()
21318            && let Some(label) = completion.label()
21319            && matches!(
21320                completion.kind(),
21321                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21322            )
21323        {
21324            snippet_source = label;
21325        }
21326        match Snippet::parse(&snippet_source).log_err() {
21327            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21328            None => (None, completion.new_text.clone()),
21329        }
21330    } else {
21331        (None, completion.new_text.clone())
21332    };
21333
21334    let mut range_to_replace = {
21335        let replace_range = &completion.replace_range;
21336        if let CompletionSource::Lsp {
21337            insert_range: Some(insert_range),
21338            ..
21339        } = &completion.source
21340        {
21341            debug_assert_eq!(
21342                insert_range.start, replace_range.start,
21343                "insert_range and replace_range should start at the same position"
21344            );
21345            debug_assert!(
21346                insert_range
21347                    .start
21348                    .cmp(cursor_position, &buffer_snapshot)
21349                    .is_le(),
21350                "insert_range should start before or at cursor position"
21351            );
21352            debug_assert!(
21353                replace_range
21354                    .start
21355                    .cmp(cursor_position, &buffer_snapshot)
21356                    .is_le(),
21357                "replace_range should start before or at cursor position"
21358            );
21359
21360            let should_replace = match intent {
21361                CompletionIntent::CompleteWithInsert => false,
21362                CompletionIntent::CompleteWithReplace => true,
21363                CompletionIntent::Complete | CompletionIntent::Compose => {
21364                    let insert_mode =
21365                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21366                            .completions
21367                            .lsp_insert_mode;
21368                    match insert_mode {
21369                        LspInsertMode::Insert => false,
21370                        LspInsertMode::Replace => true,
21371                        LspInsertMode::ReplaceSubsequence => {
21372                            let mut text_to_replace = buffer.chars_for_range(
21373                                buffer.anchor_before(replace_range.start)
21374                                    ..buffer.anchor_after(replace_range.end),
21375                            );
21376                            let mut current_needle = text_to_replace.next();
21377                            for haystack_ch in completion.label.text.chars() {
21378                                if let Some(needle_ch) = current_needle
21379                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21380                                {
21381                                    current_needle = text_to_replace.next();
21382                                }
21383                            }
21384                            current_needle.is_none()
21385                        }
21386                        LspInsertMode::ReplaceSuffix => {
21387                            if replace_range
21388                                .end
21389                                .cmp(cursor_position, &buffer_snapshot)
21390                                .is_gt()
21391                            {
21392                                let range_after_cursor = *cursor_position..replace_range.end;
21393                                let text_after_cursor = buffer
21394                                    .text_for_range(
21395                                        buffer.anchor_before(range_after_cursor.start)
21396                                            ..buffer.anchor_after(range_after_cursor.end),
21397                                    )
21398                                    .collect::<String>()
21399                                    .to_ascii_lowercase();
21400                                completion
21401                                    .label
21402                                    .text
21403                                    .to_ascii_lowercase()
21404                                    .ends_with(&text_after_cursor)
21405                            } else {
21406                                true
21407                            }
21408                        }
21409                    }
21410                }
21411            };
21412
21413            if should_replace {
21414                replace_range.clone()
21415            } else {
21416                insert_range.clone()
21417            }
21418        } else {
21419            replace_range.clone()
21420        }
21421    };
21422
21423    if range_to_replace
21424        .end
21425        .cmp(cursor_position, &buffer_snapshot)
21426        .is_lt()
21427    {
21428        range_to_replace.end = *cursor_position;
21429    }
21430
21431    CompletionEdit {
21432        new_text,
21433        replace_range: range_to_replace.to_offset(buffer),
21434        snippet,
21435    }
21436}
21437
21438struct CompletionEdit {
21439    new_text: String,
21440    replace_range: Range<usize>,
21441    snippet: Option<Snippet>,
21442}
21443
21444fn insert_extra_newline_brackets(
21445    buffer: &MultiBufferSnapshot,
21446    range: Range<usize>,
21447    language: &language::LanguageScope,
21448) -> bool {
21449    let leading_whitespace_len = buffer
21450        .reversed_chars_at(range.start)
21451        .take_while(|c| c.is_whitespace() && *c != '\n')
21452        .map(|c| c.len_utf8())
21453        .sum::<usize>();
21454    let trailing_whitespace_len = buffer
21455        .chars_at(range.end)
21456        .take_while(|c| c.is_whitespace() && *c != '\n')
21457        .map(|c| c.len_utf8())
21458        .sum::<usize>();
21459    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21460
21461    language.brackets().any(|(pair, enabled)| {
21462        let pair_start = pair.start.trim_end();
21463        let pair_end = pair.end.trim_start();
21464
21465        enabled
21466            && pair.newline
21467            && buffer.contains_str_at(range.end, pair_end)
21468            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21469    })
21470}
21471
21472fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21473    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21474        [(buffer, range, _)] => (*buffer, range.clone()),
21475        _ => return false,
21476    };
21477    let pair = {
21478        let mut result: Option<BracketMatch> = None;
21479
21480        for pair in buffer
21481            .all_bracket_ranges(range.clone())
21482            .filter(move |pair| {
21483                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21484            })
21485        {
21486            let len = pair.close_range.end - pair.open_range.start;
21487
21488            if let Some(existing) = &result {
21489                let existing_len = existing.close_range.end - existing.open_range.start;
21490                if len > existing_len {
21491                    continue;
21492                }
21493            }
21494
21495            result = Some(pair);
21496        }
21497
21498        result
21499    };
21500    let Some(pair) = pair else {
21501        return false;
21502    };
21503    pair.newline_only
21504        && buffer
21505            .chars_for_range(pair.open_range.end..range.start)
21506            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21507            .all(|c| c.is_whitespace() && c != '\n')
21508}
21509
21510fn update_uncommitted_diff_for_buffer(
21511    editor: Entity<Editor>,
21512    project: &Entity<Project>,
21513    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21514    buffer: Entity<MultiBuffer>,
21515    cx: &mut App,
21516) -> Task<()> {
21517    let mut tasks = Vec::new();
21518    project.update(cx, |project, cx| {
21519        for buffer in buffers {
21520            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21521                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21522            }
21523        }
21524    });
21525    cx.spawn(async move |cx| {
21526        let diffs = future::join_all(tasks).await;
21527        if editor
21528            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21529            .unwrap_or(false)
21530        {
21531            return;
21532        }
21533
21534        buffer
21535            .update(cx, |buffer, cx| {
21536                for diff in diffs.into_iter().flatten() {
21537                    buffer.add_diff(diff, cx);
21538                }
21539            })
21540            .ok();
21541    })
21542}
21543
21544fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21545    let tab_size = tab_size.get() as usize;
21546    let mut width = offset;
21547
21548    for ch in text.chars() {
21549        width += if ch == '\t' {
21550            tab_size - (width % tab_size)
21551        } else {
21552            1
21553        };
21554    }
21555
21556    width - offset
21557}
21558
21559#[cfg(test)]
21560mod tests {
21561    use super::*;
21562
21563    #[test]
21564    fn test_string_size_with_expanded_tabs() {
21565        let nz = |val| NonZeroU32::new(val).unwrap();
21566        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21567        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21568        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21569        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21570        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21571        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21572        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21573        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21574    }
21575}
21576
21577/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21578struct WordBreakingTokenizer<'a> {
21579    input: &'a str,
21580}
21581
21582impl<'a> WordBreakingTokenizer<'a> {
21583    fn new(input: &'a str) -> Self {
21584        Self { input }
21585    }
21586}
21587
21588fn is_char_ideographic(ch: char) -> bool {
21589    use unicode_script::Script::*;
21590    use unicode_script::UnicodeScript;
21591    matches!(ch.script(), Han | Tangut | Yi)
21592}
21593
21594fn is_grapheme_ideographic(text: &str) -> bool {
21595    text.chars().any(is_char_ideographic)
21596}
21597
21598fn is_grapheme_whitespace(text: &str) -> bool {
21599    text.chars().any(|x| x.is_whitespace())
21600}
21601
21602fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21603    text.chars()
21604        .next()
21605        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21606}
21607
21608#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21609enum WordBreakToken<'a> {
21610    Word { token: &'a str, grapheme_len: usize },
21611    InlineWhitespace { token: &'a str, grapheme_len: usize },
21612    Newline,
21613}
21614
21615impl<'a> Iterator for WordBreakingTokenizer<'a> {
21616    /// Yields a span, the count of graphemes in the token, and whether it was
21617    /// whitespace. Note that it also breaks at word boundaries.
21618    type Item = WordBreakToken<'a>;
21619
21620    fn next(&mut self) -> Option<Self::Item> {
21621        use unicode_segmentation::UnicodeSegmentation;
21622        if self.input.is_empty() {
21623            return None;
21624        }
21625
21626        let mut iter = self.input.graphemes(true).peekable();
21627        let mut offset = 0;
21628        let mut grapheme_len = 0;
21629        if let Some(first_grapheme) = iter.next() {
21630            let is_newline = first_grapheme == "\n";
21631            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21632            offset += first_grapheme.len();
21633            grapheme_len += 1;
21634            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21635                if let Some(grapheme) = iter.peek().copied()
21636                    && should_stay_with_preceding_ideograph(grapheme)
21637                {
21638                    offset += grapheme.len();
21639                    grapheme_len += 1;
21640                }
21641            } else {
21642                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21643                let mut next_word_bound = words.peek().copied();
21644                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21645                    next_word_bound = words.next();
21646                }
21647                while let Some(grapheme) = iter.peek().copied() {
21648                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21649                        break;
21650                    };
21651                    if is_grapheme_whitespace(grapheme) != is_whitespace
21652                        || (grapheme == "\n") != is_newline
21653                    {
21654                        break;
21655                    };
21656                    offset += grapheme.len();
21657                    grapheme_len += 1;
21658                    iter.next();
21659                }
21660            }
21661            let token = &self.input[..offset];
21662            self.input = &self.input[offset..];
21663            if token == "\n" {
21664                Some(WordBreakToken::Newline)
21665            } else if is_whitespace {
21666                Some(WordBreakToken::InlineWhitespace {
21667                    token,
21668                    grapheme_len,
21669                })
21670            } else {
21671                Some(WordBreakToken::Word {
21672                    token,
21673                    grapheme_len,
21674                })
21675            }
21676        } else {
21677            None
21678        }
21679    }
21680}
21681
21682#[test]
21683fn test_word_breaking_tokenizer() {
21684    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21685        ("", &[]),
21686        ("  ", &[whitespace("  ", 2)]),
21687        ("Ʒ", &[word("Ʒ", 1)]),
21688        ("Ǽ", &[word("Ǽ", 1)]),
21689        ("", &[word("", 1)]),
21690        ("⋑⋑", &[word("⋑⋑", 2)]),
21691        (
21692            "原理,进而",
21693            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21694        ),
21695        (
21696            "hello world",
21697            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21698        ),
21699        (
21700            "hello, world",
21701            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21702        ),
21703        (
21704            "  hello world",
21705            &[
21706                whitespace("  ", 2),
21707                word("hello", 5),
21708                whitespace(" ", 1),
21709                word("world", 5),
21710            ],
21711        ),
21712        (
21713            "这是什么 \n 钢笔",
21714            &[
21715                word("", 1),
21716                word("", 1),
21717                word("", 1),
21718                word("", 1),
21719                whitespace(" ", 1),
21720                newline(),
21721                whitespace(" ", 1),
21722                word("", 1),
21723                word("", 1),
21724            ],
21725        ),
21726        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21727    ];
21728
21729    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21730        WordBreakToken::Word {
21731            token,
21732            grapheme_len,
21733        }
21734    }
21735
21736    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21737        WordBreakToken::InlineWhitespace {
21738            token,
21739            grapheme_len,
21740        }
21741    }
21742
21743    fn newline() -> WordBreakToken<'static> {
21744        WordBreakToken::Newline
21745    }
21746
21747    for (input, result) in tests {
21748        assert_eq!(
21749            WordBreakingTokenizer::new(input)
21750                .collect::<Vec<_>>()
21751                .as_slice(),
21752            *result,
21753        );
21754    }
21755}
21756
21757fn wrap_with_prefix(
21758    first_line_prefix: String,
21759    subsequent_lines_prefix: String,
21760    unwrapped_text: String,
21761    wrap_column: usize,
21762    tab_size: NonZeroU32,
21763    preserve_existing_whitespace: bool,
21764) -> String {
21765    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21766    let subsequent_lines_prefix_len =
21767        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21768    let mut wrapped_text = String::new();
21769    let mut current_line = first_line_prefix;
21770    let mut is_first_line = true;
21771
21772    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21773    let mut current_line_len = first_line_prefix_len;
21774    let mut in_whitespace = false;
21775    for token in tokenizer {
21776        let have_preceding_whitespace = in_whitespace;
21777        match token {
21778            WordBreakToken::Word {
21779                token,
21780                grapheme_len,
21781            } => {
21782                in_whitespace = false;
21783                let current_prefix_len = if is_first_line {
21784                    first_line_prefix_len
21785                } else {
21786                    subsequent_lines_prefix_len
21787                };
21788                if current_line_len + grapheme_len > wrap_column
21789                    && current_line_len != current_prefix_len
21790                {
21791                    wrapped_text.push_str(current_line.trim_end());
21792                    wrapped_text.push('\n');
21793                    is_first_line = false;
21794                    current_line = subsequent_lines_prefix.clone();
21795                    current_line_len = subsequent_lines_prefix_len;
21796                }
21797                current_line.push_str(token);
21798                current_line_len += grapheme_len;
21799            }
21800            WordBreakToken::InlineWhitespace {
21801                mut token,
21802                mut grapheme_len,
21803            } => {
21804                in_whitespace = true;
21805                if have_preceding_whitespace && !preserve_existing_whitespace {
21806                    continue;
21807                }
21808                if !preserve_existing_whitespace {
21809                    token = " ";
21810                    grapheme_len = 1;
21811                }
21812                let current_prefix_len = if is_first_line {
21813                    first_line_prefix_len
21814                } else {
21815                    subsequent_lines_prefix_len
21816                };
21817                if current_line_len + grapheme_len > wrap_column {
21818                    wrapped_text.push_str(current_line.trim_end());
21819                    wrapped_text.push('\n');
21820                    is_first_line = false;
21821                    current_line = subsequent_lines_prefix.clone();
21822                    current_line_len = subsequent_lines_prefix_len;
21823                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21824                    current_line.push_str(token);
21825                    current_line_len += grapheme_len;
21826                }
21827            }
21828            WordBreakToken::Newline => {
21829                in_whitespace = true;
21830                let current_prefix_len = if is_first_line {
21831                    first_line_prefix_len
21832                } else {
21833                    subsequent_lines_prefix_len
21834                };
21835                if preserve_existing_whitespace {
21836                    wrapped_text.push_str(current_line.trim_end());
21837                    wrapped_text.push('\n');
21838                    is_first_line = false;
21839                    current_line = subsequent_lines_prefix.clone();
21840                    current_line_len = subsequent_lines_prefix_len;
21841                } else if have_preceding_whitespace {
21842                    continue;
21843                } else if current_line_len + 1 > wrap_column
21844                    && current_line_len != current_prefix_len
21845                {
21846                    wrapped_text.push_str(current_line.trim_end());
21847                    wrapped_text.push('\n');
21848                    is_first_line = false;
21849                    current_line = subsequent_lines_prefix.clone();
21850                    current_line_len = subsequent_lines_prefix_len;
21851                } else if current_line_len != current_prefix_len {
21852                    current_line.push(' ');
21853                    current_line_len += 1;
21854                }
21855            }
21856        }
21857    }
21858
21859    if !current_line.is_empty() {
21860        wrapped_text.push_str(&current_line);
21861    }
21862    wrapped_text
21863}
21864
21865#[test]
21866fn test_wrap_with_prefix() {
21867    assert_eq!(
21868        wrap_with_prefix(
21869            "# ".to_string(),
21870            "# ".to_string(),
21871            "abcdefg".to_string(),
21872            4,
21873            NonZeroU32::new(4).unwrap(),
21874            false,
21875        ),
21876        "# abcdefg"
21877    );
21878    assert_eq!(
21879        wrap_with_prefix(
21880            "".to_string(),
21881            "".to_string(),
21882            "\thello world".to_string(),
21883            8,
21884            NonZeroU32::new(4).unwrap(),
21885            false,
21886        ),
21887        "hello\nworld"
21888    );
21889    assert_eq!(
21890        wrap_with_prefix(
21891            "// ".to_string(),
21892            "// ".to_string(),
21893            "xx \nyy zz aa bb cc".to_string(),
21894            12,
21895            NonZeroU32::new(4).unwrap(),
21896            false,
21897        ),
21898        "// xx yy zz\n// aa bb cc"
21899    );
21900    assert_eq!(
21901        wrap_with_prefix(
21902            String::new(),
21903            String::new(),
21904            "这是什么 \n 钢笔".to_string(),
21905            3,
21906            NonZeroU32::new(4).unwrap(),
21907            false,
21908        ),
21909        "这是什\n么 钢\n"
21910    );
21911}
21912
21913pub trait CollaborationHub {
21914    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21915    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21916    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21917}
21918
21919impl CollaborationHub for Entity<Project> {
21920    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21921        self.read(cx).collaborators()
21922    }
21923
21924    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21925        self.read(cx).user_store().read(cx).participant_indices()
21926    }
21927
21928    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21929        let this = self.read(cx);
21930        let user_ids = this.collaborators().values().map(|c| c.user_id);
21931        this.user_store().read(cx).participant_names(user_ids, cx)
21932    }
21933}
21934
21935pub trait SemanticsProvider {
21936    fn hover(
21937        &self,
21938        buffer: &Entity<Buffer>,
21939        position: text::Anchor,
21940        cx: &mut App,
21941    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21942
21943    fn inline_values(
21944        &self,
21945        buffer_handle: Entity<Buffer>,
21946        range: Range<text::Anchor>,
21947        cx: &mut App,
21948    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21949
21950    fn inlay_hints(
21951        &self,
21952        buffer_handle: Entity<Buffer>,
21953        range: Range<text::Anchor>,
21954        cx: &mut App,
21955    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21956
21957    fn resolve_inlay_hint(
21958        &self,
21959        hint: InlayHint,
21960        buffer_handle: Entity<Buffer>,
21961        server_id: LanguageServerId,
21962        cx: &mut App,
21963    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21964
21965    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21966
21967    fn document_highlights(
21968        &self,
21969        buffer: &Entity<Buffer>,
21970        position: text::Anchor,
21971        cx: &mut App,
21972    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21973
21974    fn definitions(
21975        &self,
21976        buffer: &Entity<Buffer>,
21977        position: text::Anchor,
21978        kind: GotoDefinitionKind,
21979        cx: &mut App,
21980    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21981
21982    fn range_for_rename(
21983        &self,
21984        buffer: &Entity<Buffer>,
21985        position: text::Anchor,
21986        cx: &mut App,
21987    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21988
21989    fn perform_rename(
21990        &self,
21991        buffer: &Entity<Buffer>,
21992        position: text::Anchor,
21993        new_name: String,
21994        cx: &mut App,
21995    ) -> Option<Task<Result<ProjectTransaction>>>;
21996}
21997
21998pub trait CompletionProvider {
21999    fn completions(
22000        &self,
22001        excerpt_id: ExcerptId,
22002        buffer: &Entity<Buffer>,
22003        buffer_position: text::Anchor,
22004        trigger: CompletionContext,
22005        window: &mut Window,
22006        cx: &mut Context<Editor>,
22007    ) -> Task<Result<Vec<CompletionResponse>>>;
22008
22009    fn resolve_completions(
22010        &self,
22011        _buffer: Entity<Buffer>,
22012        _completion_indices: Vec<usize>,
22013        _completions: Rc<RefCell<Box<[Completion]>>>,
22014        _cx: &mut Context<Editor>,
22015    ) -> Task<Result<bool>> {
22016        Task::ready(Ok(false))
22017    }
22018
22019    fn apply_additional_edits_for_completion(
22020        &self,
22021        _buffer: Entity<Buffer>,
22022        _completions: Rc<RefCell<Box<[Completion]>>>,
22023        _completion_index: usize,
22024        _push_to_history: bool,
22025        _cx: &mut Context<Editor>,
22026    ) -> Task<Result<Option<language::Transaction>>> {
22027        Task::ready(Ok(None))
22028    }
22029
22030    fn is_completion_trigger(
22031        &self,
22032        buffer: &Entity<Buffer>,
22033        position: language::Anchor,
22034        text: &str,
22035        trigger_in_words: bool,
22036        menu_is_open: bool,
22037        cx: &mut Context<Editor>,
22038    ) -> bool;
22039
22040    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22041
22042    fn sort_completions(&self) -> bool {
22043        true
22044    }
22045
22046    fn filter_completions(&self) -> bool {
22047        true
22048    }
22049}
22050
22051pub trait CodeActionProvider {
22052    fn id(&self) -> Arc<str>;
22053
22054    fn code_actions(
22055        &self,
22056        buffer: &Entity<Buffer>,
22057        range: Range<text::Anchor>,
22058        window: &mut Window,
22059        cx: &mut App,
22060    ) -> Task<Result<Vec<CodeAction>>>;
22061
22062    fn apply_code_action(
22063        &self,
22064        buffer_handle: Entity<Buffer>,
22065        action: CodeAction,
22066        excerpt_id: ExcerptId,
22067        push_to_history: bool,
22068        window: &mut Window,
22069        cx: &mut App,
22070    ) -> Task<Result<ProjectTransaction>>;
22071}
22072
22073impl CodeActionProvider for Entity<Project> {
22074    fn id(&self) -> Arc<str> {
22075        "project".into()
22076    }
22077
22078    fn code_actions(
22079        &self,
22080        buffer: &Entity<Buffer>,
22081        range: Range<text::Anchor>,
22082        _window: &mut Window,
22083        cx: &mut App,
22084    ) -> Task<Result<Vec<CodeAction>>> {
22085        self.update(cx, |project, cx| {
22086            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22087            let code_actions = project.code_actions(buffer, range, None, cx);
22088            cx.background_spawn(async move {
22089                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22090                Ok(code_lens_actions
22091                    .context("code lens fetch")?
22092                    .into_iter()
22093                    .flatten()
22094                    .chain(
22095                        code_actions
22096                            .context("code action fetch")?
22097                            .into_iter()
22098                            .flatten(),
22099                    )
22100                    .collect())
22101            })
22102        })
22103    }
22104
22105    fn apply_code_action(
22106        &self,
22107        buffer_handle: Entity<Buffer>,
22108        action: CodeAction,
22109        _excerpt_id: ExcerptId,
22110        push_to_history: bool,
22111        _window: &mut Window,
22112        cx: &mut App,
22113    ) -> Task<Result<ProjectTransaction>> {
22114        self.update(cx, |project, cx| {
22115            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22116        })
22117    }
22118}
22119
22120fn snippet_completions(
22121    project: &Project,
22122    buffer: &Entity<Buffer>,
22123    buffer_position: text::Anchor,
22124    cx: &mut App,
22125) -> Task<Result<CompletionResponse>> {
22126    let languages = buffer.read(cx).languages_at(buffer_position);
22127    let snippet_store = project.snippets().read(cx);
22128
22129    let scopes: Vec<_> = languages
22130        .iter()
22131        .filter_map(|language| {
22132            let language_name = language.lsp_id();
22133            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22134
22135            if snippets.is_empty() {
22136                None
22137            } else {
22138                Some((language.default_scope(), snippets))
22139            }
22140        })
22141        .collect();
22142
22143    if scopes.is_empty() {
22144        return Task::ready(Ok(CompletionResponse {
22145            completions: vec![],
22146            is_incomplete: false,
22147        }));
22148    }
22149
22150    let snapshot = buffer.read(cx).text_snapshot();
22151    let chars: String = snapshot
22152        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22153        .collect();
22154    let executor = cx.background_executor().clone();
22155
22156    cx.background_spawn(async move {
22157        let mut is_incomplete = false;
22158        let mut completions: Vec<Completion> = Vec::new();
22159        for (scope, snippets) in scopes.into_iter() {
22160            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22161            let mut last_word = chars
22162                .chars()
22163                .take_while(|c| classifier.is_word(*c))
22164                .collect::<String>();
22165            last_word = last_word.chars().rev().collect();
22166
22167            if last_word.is_empty() {
22168                return Ok(CompletionResponse {
22169                    completions: vec![],
22170                    is_incomplete: true,
22171                });
22172            }
22173
22174            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22175            let to_lsp = |point: &text::Anchor| {
22176                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22177                point_to_lsp(end)
22178            };
22179            let lsp_end = to_lsp(&buffer_position);
22180
22181            let candidates = snippets
22182                .iter()
22183                .enumerate()
22184                .flat_map(|(ix, snippet)| {
22185                    snippet
22186                        .prefix
22187                        .iter()
22188                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22189                })
22190                .collect::<Vec<StringMatchCandidate>>();
22191
22192            const MAX_RESULTS: usize = 100;
22193            let mut matches = fuzzy::match_strings(
22194                &candidates,
22195                &last_word,
22196                last_word.chars().any(|c| c.is_uppercase()),
22197                true,
22198                MAX_RESULTS,
22199                &Default::default(),
22200                executor.clone(),
22201            )
22202            .await;
22203
22204            if matches.len() >= MAX_RESULTS {
22205                is_incomplete = true;
22206            }
22207
22208            // Remove all candidates where the query's start does not match the start of any word in the candidate
22209            if let Some(query_start) = last_word.chars().next() {
22210                matches.retain(|string_match| {
22211                    split_words(&string_match.string).any(|word| {
22212                        // Check that the first codepoint of the word as lowercase matches the first
22213                        // codepoint of the query as lowercase
22214                        word.chars()
22215                            .flat_map(|codepoint| codepoint.to_lowercase())
22216                            .zip(query_start.to_lowercase())
22217                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22218                    })
22219                });
22220            }
22221
22222            let matched_strings = matches
22223                .into_iter()
22224                .map(|m| m.string)
22225                .collect::<HashSet<_>>();
22226
22227            completions.extend(snippets.iter().filter_map(|snippet| {
22228                let matching_prefix = snippet
22229                    .prefix
22230                    .iter()
22231                    .find(|prefix| matched_strings.contains(*prefix))?;
22232                let start = as_offset - last_word.len();
22233                let start = snapshot.anchor_before(start);
22234                let range = start..buffer_position;
22235                let lsp_start = to_lsp(&start);
22236                let lsp_range = lsp::Range {
22237                    start: lsp_start,
22238                    end: lsp_end,
22239                };
22240                Some(Completion {
22241                    replace_range: range,
22242                    new_text: snippet.body.clone(),
22243                    source: CompletionSource::Lsp {
22244                        insert_range: None,
22245                        server_id: LanguageServerId(usize::MAX),
22246                        resolved: true,
22247                        lsp_completion: Box::new(lsp::CompletionItem {
22248                            label: snippet.prefix.first().unwrap().clone(),
22249                            kind: Some(CompletionItemKind::SNIPPET),
22250                            label_details: snippet.description.as_ref().map(|description| {
22251                                lsp::CompletionItemLabelDetails {
22252                                    detail: Some(description.clone()),
22253                                    description: None,
22254                                }
22255                            }),
22256                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22257                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22258                                lsp::InsertReplaceEdit {
22259                                    new_text: snippet.body.clone(),
22260                                    insert: lsp_range,
22261                                    replace: lsp_range,
22262                                },
22263                            )),
22264                            filter_text: Some(snippet.body.clone()),
22265                            sort_text: Some(char::MAX.to_string()),
22266                            ..lsp::CompletionItem::default()
22267                        }),
22268                        lsp_defaults: None,
22269                    },
22270                    label: CodeLabel {
22271                        text: matching_prefix.clone(),
22272                        runs: Vec::new(),
22273                        filter_range: 0..matching_prefix.len(),
22274                    },
22275                    icon_path: None,
22276                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22277                        single_line: snippet.name.clone().into(),
22278                        plain_text: snippet
22279                            .description
22280                            .clone()
22281                            .map(|description| description.into()),
22282                    }),
22283                    insert_text_mode: None,
22284                    confirm: None,
22285                })
22286            }))
22287        }
22288
22289        Ok(CompletionResponse {
22290            completions,
22291            is_incomplete,
22292        })
22293    })
22294}
22295
22296impl CompletionProvider for Entity<Project> {
22297    fn completions(
22298        &self,
22299        _excerpt_id: ExcerptId,
22300        buffer: &Entity<Buffer>,
22301        buffer_position: text::Anchor,
22302        options: CompletionContext,
22303        _window: &mut Window,
22304        cx: &mut Context<Editor>,
22305    ) -> Task<Result<Vec<CompletionResponse>>> {
22306        self.update(cx, |project, cx| {
22307            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22308            let project_completions = project.completions(buffer, buffer_position, options, cx);
22309            cx.background_spawn(async move {
22310                let mut responses = project_completions.await?;
22311                let snippets = snippets.await?;
22312                if !snippets.completions.is_empty() {
22313                    responses.push(snippets);
22314                }
22315                Ok(responses)
22316            })
22317        })
22318    }
22319
22320    fn resolve_completions(
22321        &self,
22322        buffer: Entity<Buffer>,
22323        completion_indices: Vec<usize>,
22324        completions: Rc<RefCell<Box<[Completion]>>>,
22325        cx: &mut Context<Editor>,
22326    ) -> Task<Result<bool>> {
22327        self.update(cx, |project, cx| {
22328            project.lsp_store().update(cx, |lsp_store, cx| {
22329                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22330            })
22331        })
22332    }
22333
22334    fn apply_additional_edits_for_completion(
22335        &self,
22336        buffer: Entity<Buffer>,
22337        completions: Rc<RefCell<Box<[Completion]>>>,
22338        completion_index: usize,
22339        push_to_history: bool,
22340        cx: &mut Context<Editor>,
22341    ) -> Task<Result<Option<language::Transaction>>> {
22342        self.update(cx, |project, cx| {
22343            project.lsp_store().update(cx, |lsp_store, cx| {
22344                lsp_store.apply_additional_edits_for_completion(
22345                    buffer,
22346                    completions,
22347                    completion_index,
22348                    push_to_history,
22349                    cx,
22350                )
22351            })
22352        })
22353    }
22354
22355    fn is_completion_trigger(
22356        &self,
22357        buffer: &Entity<Buffer>,
22358        position: language::Anchor,
22359        text: &str,
22360        trigger_in_words: bool,
22361        menu_is_open: bool,
22362        cx: &mut Context<Editor>,
22363    ) -> bool {
22364        let mut chars = text.chars();
22365        let char = if let Some(char) = chars.next() {
22366            char
22367        } else {
22368            return false;
22369        };
22370        if chars.next().is_some() {
22371            return false;
22372        }
22373
22374        let buffer = buffer.read(cx);
22375        let snapshot = buffer.snapshot();
22376        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22377            return false;
22378        }
22379        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22380        if trigger_in_words && classifier.is_word(char) {
22381            return true;
22382        }
22383
22384        buffer.completion_triggers().contains(text)
22385    }
22386}
22387
22388impl SemanticsProvider for Entity<Project> {
22389    fn hover(
22390        &self,
22391        buffer: &Entity<Buffer>,
22392        position: text::Anchor,
22393        cx: &mut App,
22394    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22395        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22396    }
22397
22398    fn document_highlights(
22399        &self,
22400        buffer: &Entity<Buffer>,
22401        position: text::Anchor,
22402        cx: &mut App,
22403    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22404        Some(self.update(cx, |project, cx| {
22405            project.document_highlights(buffer, position, cx)
22406        }))
22407    }
22408
22409    fn definitions(
22410        &self,
22411        buffer: &Entity<Buffer>,
22412        position: text::Anchor,
22413        kind: GotoDefinitionKind,
22414        cx: &mut App,
22415    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22416        Some(self.update(cx, |project, cx| match kind {
22417            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22418            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22419            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22420            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22421        }))
22422    }
22423
22424    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22425        self.update(cx, |project, cx| {
22426            if project
22427                .active_debug_session(cx)
22428                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22429            {
22430                return true;
22431            }
22432
22433            buffer.update(cx, |buffer, cx| {
22434                project.any_language_server_supports_inlay_hints(buffer, cx)
22435            })
22436        })
22437    }
22438
22439    fn inline_values(
22440        &self,
22441        buffer_handle: Entity<Buffer>,
22442        range: Range<text::Anchor>,
22443        cx: &mut App,
22444    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22445        self.update(cx, |project, cx| {
22446            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22447
22448            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22449        })
22450    }
22451
22452    fn inlay_hints(
22453        &self,
22454        buffer_handle: Entity<Buffer>,
22455        range: Range<text::Anchor>,
22456        cx: &mut App,
22457    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22458        Some(self.update(cx, |project, cx| {
22459            project.inlay_hints(buffer_handle, range, cx)
22460        }))
22461    }
22462
22463    fn resolve_inlay_hint(
22464        &self,
22465        hint: InlayHint,
22466        buffer_handle: Entity<Buffer>,
22467        server_id: LanguageServerId,
22468        cx: &mut App,
22469    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22470        Some(self.update(cx, |project, cx| {
22471            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22472        }))
22473    }
22474
22475    fn range_for_rename(
22476        &self,
22477        buffer: &Entity<Buffer>,
22478        position: text::Anchor,
22479        cx: &mut App,
22480    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22481        Some(self.update(cx, |project, cx| {
22482            let buffer = buffer.clone();
22483            let task = project.prepare_rename(buffer.clone(), position, cx);
22484            cx.spawn(async move |_, cx| {
22485                Ok(match task.await? {
22486                    PrepareRenameResponse::Success(range) => Some(range),
22487                    PrepareRenameResponse::InvalidPosition => None,
22488                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22489                        // Fallback on using TreeSitter info to determine identifier range
22490                        buffer.read_with(cx, |buffer, _| {
22491                            let snapshot = buffer.snapshot();
22492                            let (range, kind) = snapshot.surrounding_word(position, false);
22493                            if kind != Some(CharKind::Word) {
22494                                return None;
22495                            }
22496                            Some(
22497                                snapshot.anchor_before(range.start)
22498                                    ..snapshot.anchor_after(range.end),
22499                            )
22500                        })?
22501                    }
22502                })
22503            })
22504        }))
22505    }
22506
22507    fn perform_rename(
22508        &self,
22509        buffer: &Entity<Buffer>,
22510        position: text::Anchor,
22511        new_name: String,
22512        cx: &mut App,
22513    ) -> Option<Task<Result<ProjectTransaction>>> {
22514        Some(self.update(cx, |project, cx| {
22515            project.perform_rename(buffer.clone(), position, new_name, cx)
22516        }))
22517    }
22518}
22519
22520fn inlay_hint_settings(
22521    location: Anchor,
22522    snapshot: &MultiBufferSnapshot,
22523    cx: &mut Context<Editor>,
22524) -> InlayHintSettings {
22525    let file = snapshot.file_at(location);
22526    let language = snapshot.language_at(location).map(|l| l.name());
22527    language_settings(language, file, cx).inlay_hints
22528}
22529
22530fn consume_contiguous_rows(
22531    contiguous_row_selections: &mut Vec<Selection<Point>>,
22532    selection: &Selection<Point>,
22533    display_map: &DisplaySnapshot,
22534    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22535) -> (MultiBufferRow, MultiBufferRow) {
22536    contiguous_row_selections.push(selection.clone());
22537    let start_row = starting_row(selection, display_map);
22538    let mut end_row = ending_row(selection, display_map);
22539
22540    while let Some(next_selection) = selections.peek() {
22541        if next_selection.start.row <= end_row.0 {
22542            end_row = ending_row(next_selection, display_map);
22543            contiguous_row_selections.push(selections.next().unwrap().clone());
22544        } else {
22545            break;
22546        }
22547    }
22548    (start_row, end_row)
22549}
22550
22551fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22552    if selection.start.column > 0 {
22553        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22554    } else {
22555        MultiBufferRow(selection.start.row)
22556    }
22557}
22558
22559fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22560    if next_selection.end.column > 0 || next_selection.is_empty() {
22561        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22562    } else {
22563        MultiBufferRow(next_selection.end.row)
22564    }
22565}
22566
22567impl EditorSnapshot {
22568    pub fn remote_selections_in_range<'a>(
22569        &'a self,
22570        range: &'a Range<Anchor>,
22571        collaboration_hub: &dyn CollaborationHub,
22572        cx: &'a App,
22573    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22574        let participant_names = collaboration_hub.user_names(cx);
22575        let participant_indices = collaboration_hub.user_participant_indices(cx);
22576        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22577        let collaborators_by_replica_id = collaborators_by_peer_id
22578            .values()
22579            .map(|collaborator| (collaborator.replica_id, collaborator))
22580            .collect::<HashMap<_, _>>();
22581        self.buffer_snapshot
22582            .selections_in_range(range, false)
22583            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22584                if replica_id == AGENT_REPLICA_ID {
22585                    Some(RemoteSelection {
22586                        replica_id,
22587                        selection,
22588                        cursor_shape,
22589                        line_mode,
22590                        collaborator_id: CollaboratorId::Agent,
22591                        user_name: Some("Agent".into()),
22592                        color: cx.theme().players().agent(),
22593                    })
22594                } else {
22595                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22596                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22597                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22598                    Some(RemoteSelection {
22599                        replica_id,
22600                        selection,
22601                        cursor_shape,
22602                        line_mode,
22603                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22604                        user_name,
22605                        color: if let Some(index) = participant_index {
22606                            cx.theme().players().color_for_participant(index.0)
22607                        } else {
22608                            cx.theme().players().absent()
22609                        },
22610                    })
22611                }
22612            })
22613    }
22614
22615    pub fn hunks_for_ranges(
22616        &self,
22617        ranges: impl IntoIterator<Item = Range<Point>>,
22618    ) -> Vec<MultiBufferDiffHunk> {
22619        let mut hunks = Vec::new();
22620        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22621            HashMap::default();
22622        for query_range in ranges {
22623            let query_rows =
22624                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22625            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22626                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22627            ) {
22628                // Include deleted hunks that are adjacent to the query range, because
22629                // otherwise they would be missed.
22630                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22631                if hunk.status().is_deleted() {
22632                    intersects_range |= hunk.row_range.start == query_rows.end;
22633                    intersects_range |= hunk.row_range.end == query_rows.start;
22634                }
22635                if intersects_range {
22636                    if !processed_buffer_rows
22637                        .entry(hunk.buffer_id)
22638                        .or_default()
22639                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22640                    {
22641                        continue;
22642                    }
22643                    hunks.push(hunk);
22644                }
22645            }
22646        }
22647
22648        hunks
22649    }
22650
22651    fn display_diff_hunks_for_rows<'a>(
22652        &'a self,
22653        display_rows: Range<DisplayRow>,
22654        folded_buffers: &'a HashSet<BufferId>,
22655    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22656        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22657        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22658
22659        self.buffer_snapshot
22660            .diff_hunks_in_range(buffer_start..buffer_end)
22661            .filter_map(|hunk| {
22662                if folded_buffers.contains(&hunk.buffer_id) {
22663                    return None;
22664                }
22665
22666                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22667                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22668
22669                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22670                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22671
22672                let display_hunk = if hunk_display_start.column() != 0 {
22673                    DisplayDiffHunk::Folded {
22674                        display_row: hunk_display_start.row(),
22675                    }
22676                } else {
22677                    let mut end_row = hunk_display_end.row();
22678                    if hunk_display_end.column() > 0 {
22679                        end_row.0 += 1;
22680                    }
22681                    let is_created_file = hunk.is_created_file();
22682                    DisplayDiffHunk::Unfolded {
22683                        status: hunk.status(),
22684                        diff_base_byte_range: hunk.diff_base_byte_range,
22685                        display_row_range: hunk_display_start.row()..end_row,
22686                        multi_buffer_range: Anchor::range_in_buffer(
22687                            hunk.excerpt_id,
22688                            hunk.buffer_id,
22689                            hunk.buffer_range,
22690                        ),
22691                        is_created_file,
22692                    }
22693                };
22694
22695                Some(display_hunk)
22696            })
22697    }
22698
22699    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22700        self.display_snapshot.buffer_snapshot.language_at(position)
22701    }
22702
22703    pub fn is_focused(&self) -> bool {
22704        self.is_focused
22705    }
22706
22707    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22708        self.placeholder_text.as_ref()
22709    }
22710
22711    pub fn scroll_position(&self) -> gpui::Point<f32> {
22712        self.scroll_anchor.scroll_position(&self.display_snapshot)
22713    }
22714
22715    fn gutter_dimensions(
22716        &self,
22717        font_id: FontId,
22718        font_size: Pixels,
22719        max_line_number_width: Pixels,
22720        cx: &App,
22721    ) -> Option<GutterDimensions> {
22722        if !self.show_gutter {
22723            return None;
22724        }
22725
22726        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22727        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22728
22729        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22730            matches!(
22731                ProjectSettings::get_global(cx).git.git_gutter,
22732                Some(GitGutterSetting::TrackedFiles)
22733            )
22734        });
22735        let gutter_settings = EditorSettings::get_global(cx).gutter;
22736        let show_line_numbers = self
22737            .show_line_numbers
22738            .unwrap_or(gutter_settings.line_numbers);
22739        let line_gutter_width = if show_line_numbers {
22740            // Avoid flicker-like gutter resizes when the line number gains another digit by
22741            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22742            let min_width_for_number_on_gutter =
22743                ch_advance * gutter_settings.min_line_number_digits as f32;
22744            max_line_number_width.max(min_width_for_number_on_gutter)
22745        } else {
22746            0.0.into()
22747        };
22748
22749        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22750        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22751
22752        let git_blame_entries_width =
22753            self.git_blame_gutter_max_author_length
22754                .map(|max_author_length| {
22755                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22756                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22757
22758                    /// The number of characters to dedicate to gaps and margins.
22759                    const SPACING_WIDTH: usize = 4;
22760
22761                    let max_char_count = max_author_length.min(renderer.max_author_length())
22762                        + ::git::SHORT_SHA_LENGTH
22763                        + MAX_RELATIVE_TIMESTAMP.len()
22764                        + SPACING_WIDTH;
22765
22766                    ch_advance * max_char_count
22767                });
22768
22769        let is_singleton = self.buffer_snapshot.is_singleton();
22770
22771        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22772        left_padding += if !is_singleton {
22773            ch_width * 4.0
22774        } else if show_runnables || show_breakpoints {
22775            ch_width * 3.0
22776        } else if show_git_gutter && show_line_numbers {
22777            ch_width * 2.0
22778        } else if show_git_gutter || show_line_numbers {
22779            ch_width
22780        } else {
22781            px(0.)
22782        };
22783
22784        let shows_folds = is_singleton && gutter_settings.folds;
22785
22786        let right_padding = if shows_folds && show_line_numbers {
22787            ch_width * 4.0
22788        } else if shows_folds || (!is_singleton && show_line_numbers) {
22789            ch_width * 3.0
22790        } else if show_line_numbers {
22791            ch_width
22792        } else {
22793            px(0.)
22794        };
22795
22796        Some(GutterDimensions {
22797            left_padding,
22798            right_padding,
22799            width: line_gutter_width + left_padding + right_padding,
22800            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22801            git_blame_entries_width,
22802        })
22803    }
22804
22805    pub fn render_crease_toggle(
22806        &self,
22807        buffer_row: MultiBufferRow,
22808        row_contains_cursor: bool,
22809        editor: Entity<Editor>,
22810        window: &mut Window,
22811        cx: &mut App,
22812    ) -> Option<AnyElement> {
22813        let folded = self.is_line_folded(buffer_row);
22814        let mut is_foldable = false;
22815
22816        if let Some(crease) = self
22817            .crease_snapshot
22818            .query_row(buffer_row, &self.buffer_snapshot)
22819        {
22820            is_foldable = true;
22821            match crease {
22822                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22823                    if let Some(render_toggle) = render_toggle {
22824                        let toggle_callback =
22825                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22826                                if folded {
22827                                    editor.update(cx, |editor, cx| {
22828                                        editor.fold_at(buffer_row, window, cx)
22829                                    });
22830                                } else {
22831                                    editor.update(cx, |editor, cx| {
22832                                        editor.unfold_at(buffer_row, window, cx)
22833                                    });
22834                                }
22835                            });
22836                        return Some((render_toggle)(
22837                            buffer_row,
22838                            folded,
22839                            toggle_callback,
22840                            window,
22841                            cx,
22842                        ));
22843                    }
22844                }
22845            }
22846        }
22847
22848        is_foldable |= self.starts_indent(buffer_row);
22849
22850        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22851            Some(
22852                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22853                    .toggle_state(folded)
22854                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22855                        if folded {
22856                            this.unfold_at(buffer_row, window, cx);
22857                        } else {
22858                            this.fold_at(buffer_row, window, cx);
22859                        }
22860                    }))
22861                    .into_any_element(),
22862            )
22863        } else {
22864            None
22865        }
22866    }
22867
22868    pub fn render_crease_trailer(
22869        &self,
22870        buffer_row: MultiBufferRow,
22871        window: &mut Window,
22872        cx: &mut App,
22873    ) -> Option<AnyElement> {
22874        let folded = self.is_line_folded(buffer_row);
22875        if let Crease::Inline { render_trailer, .. } = self
22876            .crease_snapshot
22877            .query_row(buffer_row, &self.buffer_snapshot)?
22878        {
22879            let render_trailer = render_trailer.as_ref()?;
22880            Some(render_trailer(buffer_row, folded, window, cx))
22881        } else {
22882            None
22883        }
22884    }
22885}
22886
22887impl Deref for EditorSnapshot {
22888    type Target = DisplaySnapshot;
22889
22890    fn deref(&self) -> &Self::Target {
22891        &self.display_snapshot
22892    }
22893}
22894
22895#[derive(Clone, Debug, PartialEq, Eq)]
22896pub enum EditorEvent {
22897    InputIgnored {
22898        text: Arc<str>,
22899    },
22900    InputHandled {
22901        utf16_range_to_replace: Option<Range<isize>>,
22902        text: Arc<str>,
22903    },
22904    ExcerptsAdded {
22905        buffer: Entity<Buffer>,
22906        predecessor: ExcerptId,
22907        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22908    },
22909    ExcerptsRemoved {
22910        ids: Vec<ExcerptId>,
22911        removed_buffer_ids: Vec<BufferId>,
22912    },
22913    BufferFoldToggled {
22914        ids: Vec<ExcerptId>,
22915        folded: bool,
22916    },
22917    ExcerptsEdited {
22918        ids: Vec<ExcerptId>,
22919    },
22920    ExcerptsExpanded {
22921        ids: Vec<ExcerptId>,
22922    },
22923    BufferEdited,
22924    Edited {
22925        transaction_id: clock::Lamport,
22926    },
22927    Reparsed(BufferId),
22928    Focused,
22929    FocusedIn,
22930    Blurred,
22931    DirtyChanged,
22932    Saved,
22933    TitleChanged,
22934    DiffBaseChanged,
22935    SelectionsChanged {
22936        local: bool,
22937    },
22938    ScrollPositionChanged {
22939        local: bool,
22940        autoscroll: bool,
22941    },
22942    Closed,
22943    TransactionUndone {
22944        transaction_id: clock::Lamport,
22945    },
22946    TransactionBegun {
22947        transaction_id: clock::Lamport,
22948    },
22949    Reloaded,
22950    CursorShapeChanged,
22951    BreadcrumbsChanged,
22952    PushedToNavHistory {
22953        anchor: Anchor,
22954        is_deactivate: bool,
22955    },
22956}
22957
22958impl EventEmitter<EditorEvent> for Editor {}
22959
22960impl Focusable for Editor {
22961    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22962        self.focus_handle.clone()
22963    }
22964}
22965
22966impl Render for Editor {
22967    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22968        let settings = ThemeSettings::get_global(cx);
22969
22970        let mut text_style = match self.mode {
22971            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22972                color: cx.theme().colors().editor_foreground,
22973                font_family: settings.ui_font.family.clone(),
22974                font_features: settings.ui_font.features.clone(),
22975                font_fallbacks: settings.ui_font.fallbacks.clone(),
22976                font_size: rems(0.875).into(),
22977                font_weight: settings.ui_font.weight,
22978                line_height: relative(settings.buffer_line_height.value()),
22979                ..Default::default()
22980            },
22981            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22982                color: cx.theme().colors().editor_foreground,
22983                font_family: settings.buffer_font.family.clone(),
22984                font_features: settings.buffer_font.features.clone(),
22985                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22986                font_size: settings.buffer_font_size(cx).into(),
22987                font_weight: settings.buffer_font.weight,
22988                line_height: relative(settings.buffer_line_height.value()),
22989                ..Default::default()
22990            },
22991        };
22992        if let Some(text_style_refinement) = &self.text_style_refinement {
22993            text_style.refine(text_style_refinement)
22994        }
22995
22996        let background = match self.mode {
22997            EditorMode::SingleLine => cx.theme().system().transparent,
22998            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22999            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23000            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23001        };
23002
23003        EditorElement::new(
23004            &cx.entity(),
23005            EditorStyle {
23006                background,
23007                border: cx.theme().colors().border,
23008                local_player: cx.theme().players().local(),
23009                text: text_style,
23010                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23011                syntax: cx.theme().syntax().clone(),
23012                status: cx.theme().status().clone(),
23013                inlay_hints_style: make_inlay_hints_style(cx),
23014                edit_prediction_styles: make_suggestion_styles(cx),
23015                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23016                show_underlines: self.diagnostics_enabled(),
23017            },
23018        )
23019    }
23020}
23021
23022impl EntityInputHandler for Editor {
23023    fn text_for_range(
23024        &mut self,
23025        range_utf16: Range<usize>,
23026        adjusted_range: &mut Option<Range<usize>>,
23027        _: &mut Window,
23028        cx: &mut Context<Self>,
23029    ) -> Option<String> {
23030        let snapshot = self.buffer.read(cx).read(cx);
23031        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23032        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23033        if (start.0..end.0) != range_utf16 {
23034            adjusted_range.replace(start.0..end.0);
23035        }
23036        Some(snapshot.text_for_range(start..end).collect())
23037    }
23038
23039    fn selected_text_range(
23040        &mut self,
23041        ignore_disabled_input: bool,
23042        _: &mut Window,
23043        cx: &mut Context<Self>,
23044    ) -> Option<UTF16Selection> {
23045        // Prevent the IME menu from appearing when holding down an alphabetic key
23046        // while input is disabled.
23047        if !ignore_disabled_input && !self.input_enabled {
23048            return None;
23049        }
23050
23051        let selection = self.selections.newest::<OffsetUtf16>(cx);
23052        let range = selection.range();
23053
23054        Some(UTF16Selection {
23055            range: range.start.0..range.end.0,
23056            reversed: selection.reversed,
23057        })
23058    }
23059
23060    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23061        let snapshot = self.buffer.read(cx).read(cx);
23062        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23063        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23064    }
23065
23066    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23067        self.clear_highlights::<InputComposition>(cx);
23068        self.ime_transaction.take();
23069    }
23070
23071    fn replace_text_in_range(
23072        &mut self,
23073        range_utf16: Option<Range<usize>>,
23074        text: &str,
23075        window: &mut Window,
23076        cx: &mut Context<Self>,
23077    ) {
23078        if !self.input_enabled {
23079            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23080            return;
23081        }
23082
23083        self.transact(window, cx, |this, window, cx| {
23084            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23085                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23086                Some(this.selection_replacement_ranges(range_utf16, cx))
23087            } else {
23088                this.marked_text_ranges(cx)
23089            };
23090
23091            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23092                let newest_selection_id = this.selections.newest_anchor().id;
23093                this.selections
23094                    .all::<OffsetUtf16>(cx)
23095                    .iter()
23096                    .zip(ranges_to_replace.iter())
23097                    .find_map(|(selection, range)| {
23098                        if selection.id == newest_selection_id {
23099                            Some(
23100                                (range.start.0 as isize - selection.head().0 as isize)
23101                                    ..(range.end.0 as isize - selection.head().0 as isize),
23102                            )
23103                        } else {
23104                            None
23105                        }
23106                    })
23107            });
23108
23109            cx.emit(EditorEvent::InputHandled {
23110                utf16_range_to_replace: range_to_replace,
23111                text: text.into(),
23112            });
23113
23114            if let Some(new_selected_ranges) = new_selected_ranges {
23115                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23116                    selections.select_ranges(new_selected_ranges)
23117                });
23118                this.backspace(&Default::default(), window, cx);
23119            }
23120
23121            this.handle_input(text, window, cx);
23122        });
23123
23124        if let Some(transaction) = self.ime_transaction {
23125            self.buffer.update(cx, |buffer, cx| {
23126                buffer.group_until_transaction(transaction, cx);
23127            });
23128        }
23129
23130        self.unmark_text(window, cx);
23131    }
23132
23133    fn replace_and_mark_text_in_range(
23134        &mut self,
23135        range_utf16: Option<Range<usize>>,
23136        text: &str,
23137        new_selected_range_utf16: Option<Range<usize>>,
23138        window: &mut Window,
23139        cx: &mut Context<Self>,
23140    ) {
23141        if !self.input_enabled {
23142            return;
23143        }
23144
23145        let transaction = self.transact(window, cx, |this, window, cx| {
23146            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23147                let snapshot = this.buffer.read(cx).read(cx);
23148                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23149                    for marked_range in &mut marked_ranges {
23150                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23151                        marked_range.start.0 += relative_range_utf16.start;
23152                        marked_range.start =
23153                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23154                        marked_range.end =
23155                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23156                    }
23157                }
23158                Some(marked_ranges)
23159            } else if let Some(range_utf16) = range_utf16 {
23160                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23161                Some(this.selection_replacement_ranges(range_utf16, cx))
23162            } else {
23163                None
23164            };
23165
23166            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23167                let newest_selection_id = this.selections.newest_anchor().id;
23168                this.selections
23169                    .all::<OffsetUtf16>(cx)
23170                    .iter()
23171                    .zip(ranges_to_replace.iter())
23172                    .find_map(|(selection, range)| {
23173                        if selection.id == newest_selection_id {
23174                            Some(
23175                                (range.start.0 as isize - selection.head().0 as isize)
23176                                    ..(range.end.0 as isize - selection.head().0 as isize),
23177                            )
23178                        } else {
23179                            None
23180                        }
23181                    })
23182            });
23183
23184            cx.emit(EditorEvent::InputHandled {
23185                utf16_range_to_replace: range_to_replace,
23186                text: text.into(),
23187            });
23188
23189            if let Some(ranges) = ranges_to_replace {
23190                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23191                    s.select_ranges(ranges)
23192                });
23193            }
23194
23195            let marked_ranges = {
23196                let snapshot = this.buffer.read(cx).read(cx);
23197                this.selections
23198                    .disjoint_anchors()
23199                    .iter()
23200                    .map(|selection| {
23201                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23202                    })
23203                    .collect::<Vec<_>>()
23204            };
23205
23206            if text.is_empty() {
23207                this.unmark_text(window, cx);
23208            } else {
23209                this.highlight_text::<InputComposition>(
23210                    marked_ranges.clone(),
23211                    HighlightStyle {
23212                        underline: Some(UnderlineStyle {
23213                            thickness: px(1.),
23214                            color: None,
23215                            wavy: false,
23216                        }),
23217                        ..Default::default()
23218                    },
23219                    cx,
23220                );
23221            }
23222
23223            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23224            let use_autoclose = this.use_autoclose;
23225            let use_auto_surround = this.use_auto_surround;
23226            this.set_use_autoclose(false);
23227            this.set_use_auto_surround(false);
23228            this.handle_input(text, window, cx);
23229            this.set_use_autoclose(use_autoclose);
23230            this.set_use_auto_surround(use_auto_surround);
23231
23232            if let Some(new_selected_range) = new_selected_range_utf16 {
23233                let snapshot = this.buffer.read(cx).read(cx);
23234                let new_selected_ranges = marked_ranges
23235                    .into_iter()
23236                    .map(|marked_range| {
23237                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23238                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23239                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23240                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23241                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23242                    })
23243                    .collect::<Vec<_>>();
23244
23245                drop(snapshot);
23246                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23247                    selections.select_ranges(new_selected_ranges)
23248                });
23249            }
23250        });
23251
23252        self.ime_transaction = self.ime_transaction.or(transaction);
23253        if let Some(transaction) = self.ime_transaction {
23254            self.buffer.update(cx, |buffer, cx| {
23255                buffer.group_until_transaction(transaction, cx);
23256            });
23257        }
23258
23259        if self.text_highlights::<InputComposition>(cx).is_none() {
23260            self.ime_transaction.take();
23261        }
23262    }
23263
23264    fn bounds_for_range(
23265        &mut self,
23266        range_utf16: Range<usize>,
23267        element_bounds: gpui::Bounds<Pixels>,
23268        window: &mut Window,
23269        cx: &mut Context<Self>,
23270    ) -> Option<gpui::Bounds<Pixels>> {
23271        let text_layout_details = self.text_layout_details(window);
23272        let CharacterDimensions {
23273            em_width,
23274            em_advance,
23275            line_height,
23276        } = self.character_dimensions(window);
23277
23278        let snapshot = self.snapshot(window, cx);
23279        let scroll_position = snapshot.scroll_position();
23280        let scroll_left = scroll_position.x * em_advance;
23281
23282        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23283        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23284            + self.gutter_dimensions.full_width();
23285        let y = line_height * (start.row().as_f32() - scroll_position.y);
23286
23287        Some(Bounds {
23288            origin: element_bounds.origin + point(x, y),
23289            size: size(em_width, line_height),
23290        })
23291    }
23292
23293    fn character_index_for_point(
23294        &mut self,
23295        point: gpui::Point<Pixels>,
23296        _window: &mut Window,
23297        _cx: &mut Context<Self>,
23298    ) -> Option<usize> {
23299        let position_map = self.last_position_map.as_ref()?;
23300        if !position_map.text_hitbox.contains(&point) {
23301            return None;
23302        }
23303        let display_point = position_map.point_for_position(point).previous_valid;
23304        let anchor = position_map
23305            .snapshot
23306            .display_point_to_anchor(display_point, Bias::Left);
23307        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23308        Some(utf16_offset.0)
23309    }
23310}
23311
23312trait SelectionExt {
23313    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23314    fn spanned_rows(
23315        &self,
23316        include_end_if_at_line_start: bool,
23317        map: &DisplaySnapshot,
23318    ) -> Range<MultiBufferRow>;
23319}
23320
23321impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23322    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23323        let start = self
23324            .start
23325            .to_point(&map.buffer_snapshot)
23326            .to_display_point(map);
23327        let end = self
23328            .end
23329            .to_point(&map.buffer_snapshot)
23330            .to_display_point(map);
23331        if self.reversed {
23332            end..start
23333        } else {
23334            start..end
23335        }
23336    }
23337
23338    fn spanned_rows(
23339        &self,
23340        include_end_if_at_line_start: bool,
23341        map: &DisplaySnapshot,
23342    ) -> Range<MultiBufferRow> {
23343        let start = self.start.to_point(&map.buffer_snapshot);
23344        let mut end = self.end.to_point(&map.buffer_snapshot);
23345        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23346            end.row -= 1;
23347        }
23348
23349        let buffer_start = map.prev_line_boundary(start).0;
23350        let buffer_end = map.next_line_boundary(end).0;
23351        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23352    }
23353}
23354
23355impl<T: InvalidationRegion> InvalidationStack<T> {
23356    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23357    where
23358        S: Clone + ToOffset,
23359    {
23360        while let Some(region) = self.last() {
23361            let all_selections_inside_invalidation_ranges =
23362                if selections.len() == region.ranges().len() {
23363                    selections
23364                        .iter()
23365                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23366                        .all(|(selection, invalidation_range)| {
23367                            let head = selection.head().to_offset(buffer);
23368                            invalidation_range.start <= head && invalidation_range.end >= head
23369                        })
23370                } else {
23371                    false
23372                };
23373
23374            if all_selections_inside_invalidation_ranges {
23375                break;
23376            } else {
23377                self.pop();
23378            }
23379        }
23380    }
23381}
23382
23383impl<T> Default for InvalidationStack<T> {
23384    fn default() -> Self {
23385        Self(Default::default())
23386    }
23387}
23388
23389impl<T> Deref for InvalidationStack<T> {
23390    type Target = Vec<T>;
23391
23392    fn deref(&self) -> &Self::Target {
23393        &self.0
23394    }
23395}
23396
23397impl<T> DerefMut for InvalidationStack<T> {
23398    fn deref_mut(&mut self) -> &mut Self::Target {
23399        &mut self.0
23400    }
23401}
23402
23403impl InvalidationRegion for SnippetState {
23404    fn ranges(&self) -> &[Range<Anchor>] {
23405        &self.ranges[self.active_index]
23406    }
23407}
23408
23409fn edit_prediction_edit_text(
23410    current_snapshot: &BufferSnapshot,
23411    edits: &[(Range<Anchor>, String)],
23412    edit_preview: &EditPreview,
23413    include_deletions: bool,
23414    cx: &App,
23415) -> HighlightedText {
23416    let edits = edits
23417        .iter()
23418        .map(|(anchor, text)| {
23419            (
23420                anchor.start.text_anchor..anchor.end.text_anchor,
23421                text.clone(),
23422            )
23423        })
23424        .collect::<Vec<_>>();
23425
23426    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23427}
23428
23429fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23430    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23431    // Just show the raw edit text with basic styling
23432    let mut text = String::new();
23433    let mut highlights = Vec::new();
23434
23435    let insertion_highlight_style = HighlightStyle {
23436        color: Some(cx.theme().colors().text),
23437        ..Default::default()
23438    };
23439
23440    for (_, edit_text) in edits {
23441        let start_offset = text.len();
23442        text.push_str(edit_text);
23443        let end_offset = text.len();
23444
23445        if start_offset < end_offset {
23446            highlights.push((start_offset..end_offset, insertion_highlight_style));
23447        }
23448    }
23449
23450    HighlightedText {
23451        text: text.into(),
23452        highlights,
23453    }
23454}
23455
23456pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23457    match severity {
23458        lsp::DiagnosticSeverity::ERROR => colors.error,
23459        lsp::DiagnosticSeverity::WARNING => colors.warning,
23460        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23461        lsp::DiagnosticSeverity::HINT => colors.info,
23462        _ => colors.ignored,
23463    }
23464}
23465
23466pub fn styled_runs_for_code_label<'a>(
23467    label: &'a CodeLabel,
23468    syntax_theme: &'a theme::SyntaxTheme,
23469) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23470    let fade_out = HighlightStyle {
23471        fade_out: Some(0.35),
23472        ..Default::default()
23473    };
23474
23475    let mut prev_end = label.filter_range.end;
23476    label
23477        .runs
23478        .iter()
23479        .enumerate()
23480        .flat_map(move |(ix, (range, highlight_id))| {
23481            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23482                style
23483            } else {
23484                return Default::default();
23485            };
23486            let mut muted_style = style;
23487            muted_style.highlight(fade_out);
23488
23489            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23490            if range.start >= label.filter_range.end {
23491                if range.start > prev_end {
23492                    runs.push((prev_end..range.start, fade_out));
23493                }
23494                runs.push((range.clone(), muted_style));
23495            } else if range.end <= label.filter_range.end {
23496                runs.push((range.clone(), style));
23497            } else {
23498                runs.push((range.start..label.filter_range.end, style));
23499                runs.push((label.filter_range.end..range.end, muted_style));
23500            }
23501            prev_end = cmp::max(prev_end, range.end);
23502
23503            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23504                runs.push((prev_end..label.text.len(), fade_out));
23505            }
23506
23507            runs
23508        })
23509}
23510
23511pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23512    let mut prev_index = 0;
23513    let mut prev_codepoint: Option<char> = None;
23514    text.char_indices()
23515        .chain([(text.len(), '\0')])
23516        .filter_map(move |(index, codepoint)| {
23517            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23518            let is_boundary = index == text.len()
23519                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23520                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23521            if is_boundary {
23522                let chunk = &text[prev_index..index];
23523                prev_index = index;
23524                Some(chunk)
23525            } else {
23526                None
23527            }
23528        })
23529}
23530
23531pub trait RangeToAnchorExt: Sized {
23532    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23533
23534    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23535        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23536        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23537    }
23538}
23539
23540impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23541    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23542        let start_offset = self.start.to_offset(snapshot);
23543        let end_offset = self.end.to_offset(snapshot);
23544        if start_offset == end_offset {
23545            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23546        } else {
23547            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23548        }
23549    }
23550}
23551
23552pub trait RowExt {
23553    fn as_f32(&self) -> f32;
23554
23555    fn next_row(&self) -> Self;
23556
23557    fn previous_row(&self) -> Self;
23558
23559    fn minus(&self, other: Self) -> u32;
23560}
23561
23562impl RowExt for DisplayRow {
23563    fn as_f32(&self) -> f32 {
23564        self.0 as f32
23565    }
23566
23567    fn next_row(&self) -> Self {
23568        Self(self.0 + 1)
23569    }
23570
23571    fn previous_row(&self) -> Self {
23572        Self(self.0.saturating_sub(1))
23573    }
23574
23575    fn minus(&self, other: Self) -> u32 {
23576        self.0 - other.0
23577    }
23578}
23579
23580impl RowExt for MultiBufferRow {
23581    fn as_f32(&self) -> f32 {
23582        self.0 as f32
23583    }
23584
23585    fn next_row(&self) -> Self {
23586        Self(self.0 + 1)
23587    }
23588
23589    fn previous_row(&self) -> Self {
23590        Self(self.0.saturating_sub(1))
23591    }
23592
23593    fn minus(&self, other: Self) -> u32 {
23594        self.0 - other.0
23595    }
23596}
23597
23598trait RowRangeExt {
23599    type Row;
23600
23601    fn len(&self) -> usize;
23602
23603    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23604}
23605
23606impl RowRangeExt for Range<MultiBufferRow> {
23607    type Row = MultiBufferRow;
23608
23609    fn len(&self) -> usize {
23610        (self.end.0 - self.start.0) as usize
23611    }
23612
23613    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23614        (self.start.0..self.end.0).map(MultiBufferRow)
23615    }
23616}
23617
23618impl RowRangeExt for Range<DisplayRow> {
23619    type Row = DisplayRow;
23620
23621    fn len(&self) -> usize {
23622        (self.end.0 - self.start.0) as usize
23623    }
23624
23625    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23626        (self.start.0..self.end.0).map(DisplayRow)
23627    }
23628}
23629
23630/// If select range has more than one line, we
23631/// just point the cursor to range.start.
23632fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23633    if range.start.row == range.end.row {
23634        range
23635    } else {
23636        range.start..range.start
23637    }
23638}
23639pub struct KillRing(ClipboardItem);
23640impl Global for KillRing {}
23641
23642const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23643
23644enum BreakpointPromptEditAction {
23645    Log,
23646    Condition,
23647    HitCondition,
23648}
23649
23650struct BreakpointPromptEditor {
23651    pub(crate) prompt: Entity<Editor>,
23652    editor: WeakEntity<Editor>,
23653    breakpoint_anchor: Anchor,
23654    breakpoint: Breakpoint,
23655    edit_action: BreakpointPromptEditAction,
23656    block_ids: HashSet<CustomBlockId>,
23657    editor_margins: Arc<Mutex<EditorMargins>>,
23658    _subscriptions: Vec<Subscription>,
23659}
23660
23661impl BreakpointPromptEditor {
23662    const MAX_LINES: u8 = 4;
23663
23664    fn new(
23665        editor: WeakEntity<Editor>,
23666        breakpoint_anchor: Anchor,
23667        breakpoint: Breakpoint,
23668        edit_action: BreakpointPromptEditAction,
23669        window: &mut Window,
23670        cx: &mut Context<Self>,
23671    ) -> Self {
23672        let base_text = match edit_action {
23673            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23674            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23675            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23676        }
23677        .map(|msg| msg.to_string())
23678        .unwrap_or_default();
23679
23680        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23681        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23682
23683        let prompt = cx.new(|cx| {
23684            let mut prompt = Editor::new(
23685                EditorMode::AutoHeight {
23686                    min_lines: 1,
23687                    max_lines: Some(Self::MAX_LINES as usize),
23688                },
23689                buffer,
23690                None,
23691                window,
23692                cx,
23693            );
23694            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23695            prompt.set_show_cursor_when_unfocused(false, cx);
23696            prompt.set_placeholder_text(
23697                match edit_action {
23698                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23699                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23700                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23701                },
23702                cx,
23703            );
23704
23705            prompt
23706        });
23707
23708        Self {
23709            prompt,
23710            editor,
23711            breakpoint_anchor,
23712            breakpoint,
23713            edit_action,
23714            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23715            block_ids: Default::default(),
23716            _subscriptions: vec![],
23717        }
23718    }
23719
23720    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23721        self.block_ids.extend(block_ids)
23722    }
23723
23724    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23725        if let Some(editor) = self.editor.upgrade() {
23726            let message = self
23727                .prompt
23728                .read(cx)
23729                .buffer
23730                .read(cx)
23731                .as_singleton()
23732                .expect("A multi buffer in breakpoint prompt isn't possible")
23733                .read(cx)
23734                .as_rope()
23735                .to_string();
23736
23737            editor.update(cx, |editor, cx| {
23738                editor.edit_breakpoint_at_anchor(
23739                    self.breakpoint_anchor,
23740                    self.breakpoint.clone(),
23741                    match self.edit_action {
23742                        BreakpointPromptEditAction::Log => {
23743                            BreakpointEditAction::EditLogMessage(message.into())
23744                        }
23745                        BreakpointPromptEditAction::Condition => {
23746                            BreakpointEditAction::EditCondition(message.into())
23747                        }
23748                        BreakpointPromptEditAction::HitCondition => {
23749                            BreakpointEditAction::EditHitCondition(message.into())
23750                        }
23751                    },
23752                    cx,
23753                );
23754
23755                editor.remove_blocks(self.block_ids.clone(), None, cx);
23756                cx.focus_self(window);
23757            });
23758        }
23759    }
23760
23761    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23762        self.editor
23763            .update(cx, |editor, cx| {
23764                editor.remove_blocks(self.block_ids.clone(), None, cx);
23765                window.focus(&editor.focus_handle);
23766            })
23767            .log_err();
23768    }
23769
23770    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23771        let settings = ThemeSettings::get_global(cx);
23772        let text_style = TextStyle {
23773            color: if self.prompt.read(cx).read_only(cx) {
23774                cx.theme().colors().text_disabled
23775            } else {
23776                cx.theme().colors().text
23777            },
23778            font_family: settings.buffer_font.family.clone(),
23779            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23780            font_size: settings.buffer_font_size(cx).into(),
23781            font_weight: settings.buffer_font.weight,
23782            line_height: relative(settings.buffer_line_height.value()),
23783            ..Default::default()
23784        };
23785        EditorElement::new(
23786            &self.prompt,
23787            EditorStyle {
23788                background: cx.theme().colors().editor_background,
23789                local_player: cx.theme().players().local(),
23790                text: text_style,
23791                ..Default::default()
23792            },
23793        )
23794    }
23795}
23796
23797impl Render for BreakpointPromptEditor {
23798    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23799        let editor_margins = *self.editor_margins.lock();
23800        let gutter_dimensions = editor_margins.gutter;
23801        h_flex()
23802            .key_context("Editor")
23803            .bg(cx.theme().colors().editor_background)
23804            .border_y_1()
23805            .border_color(cx.theme().status().info_border)
23806            .size_full()
23807            .py(window.line_height() / 2.5)
23808            .on_action(cx.listener(Self::confirm))
23809            .on_action(cx.listener(Self::cancel))
23810            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23811            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23812    }
23813}
23814
23815impl Focusable for BreakpointPromptEditor {
23816    fn focus_handle(&self, cx: &App) -> FocusHandle {
23817        self.prompt.focus_handle(cx)
23818    }
23819}
23820
23821fn all_edits_insertions_or_deletions(
23822    edits: &Vec<(Range<Anchor>, String)>,
23823    snapshot: &MultiBufferSnapshot,
23824) -> bool {
23825    let mut all_insertions = true;
23826    let mut all_deletions = true;
23827
23828    for (range, new_text) in edits.iter() {
23829        let range_is_empty = range.to_offset(snapshot).is_empty();
23830        let text_is_empty = new_text.is_empty();
23831
23832        if range_is_empty != text_is_empty {
23833            if range_is_empty {
23834                all_deletions = false;
23835            } else {
23836                all_insertions = false;
23837            }
23838        } else {
23839            return false;
23840        }
23841
23842        if !all_insertions && !all_deletions {
23843            return false;
23844        }
23845    }
23846    all_insertions || all_deletions
23847}
23848
23849struct MissingEditPredictionKeybindingTooltip;
23850
23851impl Render for MissingEditPredictionKeybindingTooltip {
23852    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23853        ui::tooltip_container(window, cx, |container, _, cx| {
23854            container
23855                .flex_shrink_0()
23856                .max_w_80()
23857                .min_h(rems_from_px(124.))
23858                .justify_between()
23859                .child(
23860                    v_flex()
23861                        .flex_1()
23862                        .text_ui_sm(cx)
23863                        .child(Label::new("Conflict with Accept Keybinding"))
23864                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23865                )
23866                .child(
23867                    h_flex()
23868                        .pb_1()
23869                        .gap_1()
23870                        .items_end()
23871                        .w_full()
23872                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23873                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23874                        }))
23875                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23876                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23877                        })),
23878                )
23879        })
23880    }
23881}
23882
23883#[derive(Debug, Clone, Copy, PartialEq)]
23884pub struct LineHighlight {
23885    pub background: Background,
23886    pub border: Option<gpui::Hsla>,
23887    pub include_gutter: bool,
23888    pub type_id: Option<TypeId>,
23889}
23890
23891struct LineManipulationResult {
23892    pub new_text: String,
23893    pub line_count_before: usize,
23894    pub line_count_after: usize,
23895}
23896
23897fn render_diff_hunk_controls(
23898    row: u32,
23899    status: &DiffHunkStatus,
23900    hunk_range: Range<Anchor>,
23901    is_created_file: bool,
23902    line_height: Pixels,
23903    editor: &Entity<Editor>,
23904    _window: &mut Window,
23905    cx: &mut App,
23906) -> AnyElement {
23907    h_flex()
23908        .h(line_height)
23909        .mr_1()
23910        .gap_1()
23911        .px_0p5()
23912        .pb_1()
23913        .border_x_1()
23914        .border_b_1()
23915        .border_color(cx.theme().colors().border_variant)
23916        .rounded_b_lg()
23917        .bg(cx.theme().colors().editor_background)
23918        .gap_1()
23919        .block_mouse_except_scroll()
23920        .shadow_md()
23921        .child(if status.has_secondary_hunk() {
23922            Button::new(("stage", row as u64), "Stage")
23923                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23924                .tooltip({
23925                    let focus_handle = editor.focus_handle(cx);
23926                    move |window, cx| {
23927                        Tooltip::for_action_in(
23928                            "Stage Hunk",
23929                            &::git::ToggleStaged,
23930                            &focus_handle,
23931                            window,
23932                            cx,
23933                        )
23934                    }
23935                })
23936                .on_click({
23937                    let editor = editor.clone();
23938                    move |_event, _window, cx| {
23939                        editor.update(cx, |editor, cx| {
23940                            editor.stage_or_unstage_diff_hunks(
23941                                true,
23942                                vec![hunk_range.start..hunk_range.start],
23943                                cx,
23944                            );
23945                        });
23946                    }
23947                })
23948        } else {
23949            Button::new(("unstage", row as u64), "Unstage")
23950                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23951                .tooltip({
23952                    let focus_handle = editor.focus_handle(cx);
23953                    move |window, cx| {
23954                        Tooltip::for_action_in(
23955                            "Unstage Hunk",
23956                            &::git::ToggleStaged,
23957                            &focus_handle,
23958                            window,
23959                            cx,
23960                        )
23961                    }
23962                })
23963                .on_click({
23964                    let editor = editor.clone();
23965                    move |_event, _window, cx| {
23966                        editor.update(cx, |editor, cx| {
23967                            editor.stage_or_unstage_diff_hunks(
23968                                false,
23969                                vec![hunk_range.start..hunk_range.start],
23970                                cx,
23971                            );
23972                        });
23973                    }
23974                })
23975        })
23976        .child(
23977            Button::new(("restore", row as u64), "Restore")
23978                .tooltip({
23979                    let focus_handle = editor.focus_handle(cx);
23980                    move |window, cx| {
23981                        Tooltip::for_action_in(
23982                            "Restore Hunk",
23983                            &::git::Restore,
23984                            &focus_handle,
23985                            window,
23986                            cx,
23987                        )
23988                    }
23989                })
23990                .on_click({
23991                    let editor = editor.clone();
23992                    move |_event, window, cx| {
23993                        editor.update(cx, |editor, cx| {
23994                            let snapshot = editor.snapshot(window, cx);
23995                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23996                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23997                        });
23998                    }
23999                })
24000                .disabled(is_created_file),
24001        )
24002        .when(
24003            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24004            |el| {
24005                el.child(
24006                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24007                        .shape(IconButtonShape::Square)
24008                        .icon_size(IconSize::Small)
24009                        // .disabled(!has_multiple_hunks)
24010                        .tooltip({
24011                            let focus_handle = editor.focus_handle(cx);
24012                            move |window, cx| {
24013                                Tooltip::for_action_in(
24014                                    "Next Hunk",
24015                                    &GoToHunk,
24016                                    &focus_handle,
24017                                    window,
24018                                    cx,
24019                                )
24020                            }
24021                        })
24022                        .on_click({
24023                            let editor = editor.clone();
24024                            move |_event, window, cx| {
24025                                editor.update(cx, |editor, cx| {
24026                                    let snapshot = editor.snapshot(window, cx);
24027                                    let position =
24028                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24029                                    editor.go_to_hunk_before_or_after_position(
24030                                        &snapshot,
24031                                        position,
24032                                        Direction::Next,
24033                                        window,
24034                                        cx,
24035                                    );
24036                                    editor.expand_selected_diff_hunks(cx);
24037                                });
24038                            }
24039                        }),
24040                )
24041                .child(
24042                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24043                        .shape(IconButtonShape::Square)
24044                        .icon_size(IconSize::Small)
24045                        // .disabled(!has_multiple_hunks)
24046                        .tooltip({
24047                            let focus_handle = editor.focus_handle(cx);
24048                            move |window, cx| {
24049                                Tooltip::for_action_in(
24050                                    "Previous Hunk",
24051                                    &GoToPreviousHunk,
24052                                    &focus_handle,
24053                                    window,
24054                                    cx,
24055                                )
24056                            }
24057                        })
24058                        .on_click({
24059                            let editor = editor.clone();
24060                            move |_event, window, cx| {
24061                                editor.update(cx, |editor, cx| {
24062                                    let snapshot = editor.snapshot(window, cx);
24063                                    let point =
24064                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24065                                    editor.go_to_hunk_before_or_after_position(
24066                                        &snapshot,
24067                                        point,
24068                                        Direction::Prev,
24069                                        window,
24070                                        cx,
24071                                    );
24072                                    editor.expand_selected_diff_hunks(cx);
24073                                });
24074                            }
24075                        }),
24076                )
24077            },
24078        )
24079        .into_any_element()
24080}