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.clone())
 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::Keystroke>,
 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    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10451        let Some(project) = self.project.clone() else {
10452            return;
10453        };
10454        self.reload(project, window, cx)
10455            .detach_and_notify_err(window, cx);
10456    }
10457
10458    pub fn restore_file(
10459        &mut self,
10460        _: &::git::RestoreFile,
10461        window: &mut Window,
10462        cx: &mut Context<Self>,
10463    ) {
10464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10465        let mut buffer_ids = HashSet::default();
10466        let snapshot = self.buffer().read(cx).snapshot(cx);
10467        for selection in self.selections.all::<usize>(cx) {
10468            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10469        }
10470
10471        let buffer = self.buffer().read(cx);
10472        let ranges = buffer_ids
10473            .into_iter()
10474            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10475            .collect::<Vec<_>>();
10476
10477        self.restore_hunks_in_ranges(ranges, window, cx);
10478    }
10479
10480    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482        let selections = self
10483            .selections
10484            .all(cx)
10485            .into_iter()
10486            .map(|s| s.range())
10487            .collect();
10488        self.restore_hunks_in_ranges(selections, window, cx);
10489    }
10490
10491    pub fn restore_hunks_in_ranges(
10492        &mut self,
10493        ranges: Vec<Range<Point>>,
10494        window: &mut Window,
10495        cx: &mut Context<Editor>,
10496    ) {
10497        let mut revert_changes = HashMap::default();
10498        let chunk_by = self
10499            .snapshot(window, cx)
10500            .hunks_for_ranges(ranges)
10501            .into_iter()
10502            .chunk_by(|hunk| hunk.buffer_id);
10503        for (buffer_id, hunks) in &chunk_by {
10504            let hunks = hunks.collect::<Vec<_>>();
10505            for hunk in &hunks {
10506                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10507            }
10508            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10509        }
10510        drop(chunk_by);
10511        if !revert_changes.is_empty() {
10512            self.transact(window, cx, |editor, window, cx| {
10513                editor.restore(revert_changes, window, cx);
10514            });
10515        }
10516    }
10517
10518    pub fn open_active_item_in_terminal(
10519        &mut self,
10520        _: &OpenInTerminal,
10521        window: &mut Window,
10522        cx: &mut Context<Self>,
10523    ) {
10524        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10525            let project_path = buffer.read(cx).project_path(cx)?;
10526            let project = self.project()?.read(cx);
10527            let entry = project.entry_for_path(&project_path, cx)?;
10528            let parent = match &entry.canonical_path {
10529                Some(canonical_path) => canonical_path.to_path_buf(),
10530                None => project.absolute_path(&project_path, cx)?,
10531            }
10532            .parent()?
10533            .to_path_buf();
10534            Some(parent)
10535        }) {
10536            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10537        }
10538    }
10539
10540    fn set_breakpoint_context_menu(
10541        &mut self,
10542        display_row: DisplayRow,
10543        position: Option<Anchor>,
10544        clicked_point: gpui::Point<Pixels>,
10545        window: &mut Window,
10546        cx: &mut Context<Self>,
10547    ) {
10548        let source = self
10549            .buffer
10550            .read(cx)
10551            .snapshot(cx)
10552            .anchor_before(Point::new(display_row.0, 0u32));
10553
10554        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10555
10556        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10557            self,
10558            source,
10559            clicked_point,
10560            context_menu,
10561            window,
10562            cx,
10563        );
10564    }
10565
10566    fn add_edit_breakpoint_block(
10567        &mut self,
10568        anchor: Anchor,
10569        breakpoint: &Breakpoint,
10570        edit_action: BreakpointPromptEditAction,
10571        window: &mut Window,
10572        cx: &mut Context<Self>,
10573    ) {
10574        let weak_editor = cx.weak_entity();
10575        let bp_prompt = cx.new(|cx| {
10576            BreakpointPromptEditor::new(
10577                weak_editor,
10578                anchor,
10579                breakpoint.clone(),
10580                edit_action,
10581                window,
10582                cx,
10583            )
10584        });
10585
10586        let height = bp_prompt.update(cx, |this, cx| {
10587            this.prompt
10588                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10589        });
10590        let cloned_prompt = bp_prompt.clone();
10591        let blocks = vec![BlockProperties {
10592            style: BlockStyle::Sticky,
10593            placement: BlockPlacement::Above(anchor),
10594            height: Some(height),
10595            render: Arc::new(move |cx| {
10596                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10597                cloned_prompt.clone().into_any_element()
10598            }),
10599            priority: 0,
10600        }];
10601
10602        let focus_handle = bp_prompt.focus_handle(cx);
10603        window.focus(&focus_handle);
10604
10605        let block_ids = self.insert_blocks(blocks, None, cx);
10606        bp_prompt.update(cx, |prompt, _| {
10607            prompt.add_block_ids(block_ids);
10608        });
10609    }
10610
10611    pub(crate) fn breakpoint_at_row(
10612        &self,
10613        row: u32,
10614        window: &mut Window,
10615        cx: &mut Context<Self>,
10616    ) -> Option<(Anchor, Breakpoint)> {
10617        let snapshot = self.snapshot(window, cx);
10618        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10619
10620        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10621    }
10622
10623    pub(crate) fn breakpoint_at_anchor(
10624        &self,
10625        breakpoint_position: Anchor,
10626        snapshot: &EditorSnapshot,
10627        cx: &mut Context<Self>,
10628    ) -> Option<(Anchor, Breakpoint)> {
10629        let buffer = self
10630            .buffer
10631            .read(cx)
10632            .buffer_for_anchor(breakpoint_position, cx)?;
10633
10634        let enclosing_excerpt = breakpoint_position.excerpt_id;
10635        let buffer_snapshot = buffer.read(cx).snapshot();
10636
10637        let row = buffer_snapshot
10638            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10639            .row;
10640
10641        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10642        let anchor_end = snapshot
10643            .buffer_snapshot
10644            .anchor_after(Point::new(row, line_len));
10645
10646        self.breakpoint_store
10647            .as_ref()?
10648            .read_with(cx, |breakpoint_store, cx| {
10649                breakpoint_store
10650                    .breakpoints(
10651                        &buffer,
10652                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10653                        &buffer_snapshot,
10654                        cx,
10655                    )
10656                    .next()
10657                    .and_then(|(bp, _)| {
10658                        let breakpoint_row = buffer_snapshot
10659                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10660                            .row;
10661
10662                        if breakpoint_row == row {
10663                            snapshot
10664                                .buffer_snapshot
10665                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10666                                .map(|position| (position, bp.bp.clone()))
10667                        } else {
10668                            None
10669                        }
10670                    })
10671            })
10672    }
10673
10674    pub fn edit_log_breakpoint(
10675        &mut self,
10676        _: &EditLogBreakpoint,
10677        window: &mut Window,
10678        cx: &mut Context<Self>,
10679    ) {
10680        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10681            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10682                message: None,
10683                state: BreakpointState::Enabled,
10684                condition: None,
10685                hit_condition: None,
10686            });
10687
10688            self.add_edit_breakpoint_block(
10689                anchor,
10690                &breakpoint,
10691                BreakpointPromptEditAction::Log,
10692                window,
10693                cx,
10694            );
10695        }
10696    }
10697
10698    fn breakpoints_at_cursors(
10699        &self,
10700        window: &mut Window,
10701        cx: &mut Context<Self>,
10702    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10703        let snapshot = self.snapshot(window, cx);
10704        let cursors = self
10705            .selections
10706            .disjoint_anchors()
10707            .iter()
10708            .map(|selection| {
10709                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10710
10711                let breakpoint_position = self
10712                    .breakpoint_at_row(cursor_position.row, window, cx)
10713                    .map(|bp| bp.0)
10714                    .unwrap_or_else(|| {
10715                        snapshot
10716                            .display_snapshot
10717                            .buffer_snapshot
10718                            .anchor_after(Point::new(cursor_position.row, 0))
10719                    });
10720
10721                let breakpoint = self
10722                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10723                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10724
10725                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10726            })
10727            // 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.
10728            .collect::<HashMap<Anchor, _>>();
10729
10730        cursors.into_iter().collect()
10731    }
10732
10733    pub fn enable_breakpoint(
10734        &mut self,
10735        _: &crate::actions::EnableBreakpoint,
10736        window: &mut Window,
10737        cx: &mut Context<Self>,
10738    ) {
10739        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10740            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10741                continue;
10742            };
10743            self.edit_breakpoint_at_anchor(
10744                anchor,
10745                breakpoint,
10746                BreakpointEditAction::InvertState,
10747                cx,
10748            );
10749        }
10750    }
10751
10752    pub fn disable_breakpoint(
10753        &mut self,
10754        _: &crate::actions::DisableBreakpoint,
10755        window: &mut Window,
10756        cx: &mut Context<Self>,
10757    ) {
10758        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10759            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10760                continue;
10761            };
10762            self.edit_breakpoint_at_anchor(
10763                anchor,
10764                breakpoint,
10765                BreakpointEditAction::InvertState,
10766                cx,
10767            );
10768        }
10769    }
10770
10771    pub fn toggle_breakpoint(
10772        &mut self,
10773        _: &crate::actions::ToggleBreakpoint,
10774        window: &mut Window,
10775        cx: &mut Context<Self>,
10776    ) {
10777        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10778            if let Some(breakpoint) = breakpoint {
10779                self.edit_breakpoint_at_anchor(
10780                    anchor,
10781                    breakpoint,
10782                    BreakpointEditAction::Toggle,
10783                    cx,
10784                );
10785            } else {
10786                self.edit_breakpoint_at_anchor(
10787                    anchor,
10788                    Breakpoint::new_standard(),
10789                    BreakpointEditAction::Toggle,
10790                    cx,
10791                );
10792            }
10793        }
10794    }
10795
10796    pub fn edit_breakpoint_at_anchor(
10797        &mut self,
10798        breakpoint_position: Anchor,
10799        breakpoint: Breakpoint,
10800        edit_action: BreakpointEditAction,
10801        cx: &mut Context<Self>,
10802    ) {
10803        let Some(breakpoint_store) = &self.breakpoint_store else {
10804            return;
10805        };
10806
10807        let Some(buffer) = self
10808            .buffer
10809            .read(cx)
10810            .buffer_for_anchor(breakpoint_position, cx)
10811        else {
10812            return;
10813        };
10814
10815        breakpoint_store.update(cx, |breakpoint_store, cx| {
10816            breakpoint_store.toggle_breakpoint(
10817                buffer,
10818                BreakpointWithPosition {
10819                    position: breakpoint_position.text_anchor,
10820                    bp: breakpoint,
10821                },
10822                edit_action,
10823                cx,
10824            );
10825        });
10826
10827        cx.notify();
10828    }
10829
10830    #[cfg(any(test, feature = "test-support"))]
10831    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10832        self.breakpoint_store.clone()
10833    }
10834
10835    pub fn prepare_restore_change(
10836        &self,
10837        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10838        hunk: &MultiBufferDiffHunk,
10839        cx: &mut App,
10840    ) -> Option<()> {
10841        if hunk.is_created_file() {
10842            return None;
10843        }
10844        let buffer = self.buffer.read(cx);
10845        let diff = buffer.diff_for(hunk.buffer_id)?;
10846        let buffer = buffer.buffer(hunk.buffer_id)?;
10847        let buffer = buffer.read(cx);
10848        let original_text = diff
10849            .read(cx)
10850            .base_text()
10851            .as_rope()
10852            .slice(hunk.diff_base_byte_range.clone());
10853        let buffer_snapshot = buffer.snapshot();
10854        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10855        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10856            probe
10857                .0
10858                .start
10859                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10860                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10861        }) {
10862            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10863            Some(())
10864        } else {
10865            None
10866        }
10867    }
10868
10869    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10870        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10871    }
10872
10873    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10874        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10875    }
10876
10877    fn manipulate_lines<M>(
10878        &mut self,
10879        window: &mut Window,
10880        cx: &mut Context<Self>,
10881        mut manipulate: M,
10882    ) where
10883        M: FnMut(&str) -> LineManipulationResult,
10884    {
10885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10886
10887        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10888        let buffer = self.buffer.read(cx).snapshot(cx);
10889
10890        let mut edits = Vec::new();
10891
10892        let selections = self.selections.all::<Point>(cx);
10893        let mut selections = selections.iter().peekable();
10894        let mut contiguous_row_selections = Vec::new();
10895        let mut new_selections = Vec::new();
10896        let mut added_lines = 0;
10897        let mut removed_lines = 0;
10898
10899        while let Some(selection) = selections.next() {
10900            let (start_row, end_row) = consume_contiguous_rows(
10901                &mut contiguous_row_selections,
10902                selection,
10903                &display_map,
10904                &mut selections,
10905            );
10906
10907            let start_point = Point::new(start_row.0, 0);
10908            let end_point = Point::new(
10909                end_row.previous_row().0,
10910                buffer.line_len(end_row.previous_row()),
10911            );
10912            let text = buffer
10913                .text_for_range(start_point..end_point)
10914                .collect::<String>();
10915
10916            let LineManipulationResult {
10917                new_text,
10918                line_count_before,
10919                line_count_after,
10920            } = manipulate(&text);
10921
10922            edits.push((start_point..end_point, new_text));
10923
10924            // Selections must change based on added and removed line count
10925            let start_row =
10926                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10927            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10928            new_selections.push(Selection {
10929                id: selection.id,
10930                start: start_row,
10931                end: end_row,
10932                goal: SelectionGoal::None,
10933                reversed: selection.reversed,
10934            });
10935
10936            if line_count_after > line_count_before {
10937                added_lines += line_count_after - line_count_before;
10938            } else if line_count_before > line_count_after {
10939                removed_lines += line_count_before - line_count_after;
10940            }
10941        }
10942
10943        self.transact(window, cx, |this, window, cx| {
10944            let buffer = this.buffer.update(cx, |buffer, cx| {
10945                buffer.edit(edits, None, cx);
10946                buffer.snapshot(cx)
10947            });
10948
10949            // Recalculate offsets on newly edited buffer
10950            let new_selections = new_selections
10951                .iter()
10952                .map(|s| {
10953                    let start_point = Point::new(s.start.0, 0);
10954                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10955                    Selection {
10956                        id: s.id,
10957                        start: buffer.point_to_offset(start_point),
10958                        end: buffer.point_to_offset(end_point),
10959                        goal: s.goal,
10960                        reversed: s.reversed,
10961                    }
10962                })
10963                .collect();
10964
10965            this.change_selections(Default::default(), window, cx, |s| {
10966                s.select(new_selections);
10967            });
10968
10969            this.request_autoscroll(Autoscroll::fit(), cx);
10970        });
10971    }
10972
10973    fn manipulate_immutable_lines<Fn>(
10974        &mut self,
10975        window: &mut Window,
10976        cx: &mut Context<Self>,
10977        mut callback: Fn,
10978    ) where
10979        Fn: FnMut(&mut Vec<&str>),
10980    {
10981        self.manipulate_lines(window, cx, |text| {
10982            let mut lines: Vec<&str> = text.split('\n').collect();
10983            let line_count_before = lines.len();
10984
10985            callback(&mut lines);
10986
10987            LineManipulationResult {
10988                new_text: lines.join("\n"),
10989                line_count_before,
10990                line_count_after: lines.len(),
10991            }
10992        });
10993    }
10994
10995    fn manipulate_mutable_lines<Fn>(
10996        &mut self,
10997        window: &mut Window,
10998        cx: &mut Context<Self>,
10999        mut callback: Fn,
11000    ) where
11001        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11002    {
11003        self.manipulate_lines(window, cx, |text| {
11004            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11005            let line_count_before = lines.len();
11006
11007            callback(&mut lines);
11008
11009            LineManipulationResult {
11010                new_text: lines.join("\n"),
11011                line_count_before,
11012                line_count_after: lines.len(),
11013            }
11014        });
11015    }
11016
11017    pub fn convert_indentation_to_spaces(
11018        &mut self,
11019        _: &ConvertIndentationToSpaces,
11020        window: &mut Window,
11021        cx: &mut Context<Self>,
11022    ) {
11023        let settings = self.buffer.read(cx).language_settings(cx);
11024        let tab_size = settings.tab_size.get() as usize;
11025
11026        self.manipulate_mutable_lines(window, cx, |lines| {
11027            // Allocates a reasonably sized scratch buffer once for the whole loop
11028            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11029            // Avoids recomputing spaces that could be inserted many times
11030            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11031                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11032                .collect();
11033
11034            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11035                let mut chars = line.as_ref().chars();
11036                let mut col = 0;
11037                let mut changed = false;
11038
11039                for ch in chars.by_ref() {
11040                    match ch {
11041                        ' ' => {
11042                            reindented_line.push(' ');
11043                            col += 1;
11044                        }
11045                        '\t' => {
11046                            // \t are converted to spaces depending on the current column
11047                            let spaces_len = tab_size - (col % tab_size);
11048                            reindented_line.extend(&space_cache[spaces_len - 1]);
11049                            col += spaces_len;
11050                            changed = true;
11051                        }
11052                        _ => {
11053                            // If we dont append before break, the character is consumed
11054                            reindented_line.push(ch);
11055                            break;
11056                        }
11057                    }
11058                }
11059
11060                if !changed {
11061                    reindented_line.clear();
11062                    continue;
11063                }
11064                // Append the rest of the line and replace old reference with new one
11065                reindented_line.extend(chars);
11066                *line = Cow::Owned(reindented_line.clone());
11067                reindented_line.clear();
11068            }
11069        });
11070    }
11071
11072    pub fn convert_indentation_to_tabs(
11073        &mut self,
11074        _: &ConvertIndentationToTabs,
11075        window: &mut Window,
11076        cx: &mut Context<Self>,
11077    ) {
11078        let settings = self.buffer.read(cx).language_settings(cx);
11079        let tab_size = settings.tab_size.get() as usize;
11080
11081        self.manipulate_mutable_lines(window, cx, |lines| {
11082            // Allocates a reasonably sized buffer once for the whole loop
11083            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11084            // Avoids recomputing spaces that could be inserted many times
11085            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11086                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11087                .collect();
11088
11089            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11090                let mut chars = line.chars();
11091                let mut spaces_count = 0;
11092                let mut first_non_indent_char = None;
11093                let mut changed = false;
11094
11095                for ch in chars.by_ref() {
11096                    match ch {
11097                        ' ' => {
11098                            // Keep track of spaces. Append \t when we reach tab_size
11099                            spaces_count += 1;
11100                            changed = true;
11101                            if spaces_count == tab_size {
11102                                reindented_line.push('\t');
11103                                spaces_count = 0;
11104                            }
11105                        }
11106                        '\t' => {
11107                            reindented_line.push('\t');
11108                            spaces_count = 0;
11109                        }
11110                        _ => {
11111                            // Dont append it yet, we might have remaining spaces
11112                            first_non_indent_char = Some(ch);
11113                            break;
11114                        }
11115                    }
11116                }
11117
11118                if !changed {
11119                    reindented_line.clear();
11120                    continue;
11121                }
11122                // Remaining spaces that didn't make a full tab stop
11123                if spaces_count > 0 {
11124                    reindented_line.extend(&space_cache[spaces_count - 1]);
11125                }
11126                // If we consume an extra character that was not indentation, add it back
11127                if let Some(extra_char) = first_non_indent_char {
11128                    reindented_line.push(extra_char);
11129                }
11130                // Append the rest of the line and replace old reference with new one
11131                reindented_line.extend(chars);
11132                *line = Cow::Owned(reindented_line.clone());
11133                reindented_line.clear();
11134            }
11135        });
11136    }
11137
11138    pub fn convert_to_upper_case(
11139        &mut self,
11140        _: &ConvertToUpperCase,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143    ) {
11144        self.manipulate_text(window, cx, |text| text.to_uppercase())
11145    }
11146
11147    pub fn convert_to_lower_case(
11148        &mut self,
11149        _: &ConvertToLowerCase,
11150        window: &mut Window,
11151        cx: &mut Context<Self>,
11152    ) {
11153        self.manipulate_text(window, cx, |text| text.to_lowercase())
11154    }
11155
11156    pub fn convert_to_title_case(
11157        &mut self,
11158        _: &ConvertToTitleCase,
11159        window: &mut Window,
11160        cx: &mut Context<Self>,
11161    ) {
11162        self.manipulate_text(window, cx, |text| {
11163            text.split('\n')
11164                .map(|line| line.to_case(Case::Title))
11165                .join("\n")
11166        })
11167    }
11168
11169    pub fn convert_to_snake_case(
11170        &mut self,
11171        _: &ConvertToSnakeCase,
11172        window: &mut Window,
11173        cx: &mut Context<Self>,
11174    ) {
11175        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11176    }
11177
11178    pub fn convert_to_kebab_case(
11179        &mut self,
11180        _: &ConvertToKebabCase,
11181        window: &mut Window,
11182        cx: &mut Context<Self>,
11183    ) {
11184        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11185    }
11186
11187    pub fn convert_to_upper_camel_case(
11188        &mut self,
11189        _: &ConvertToUpperCamelCase,
11190        window: &mut Window,
11191        cx: &mut Context<Self>,
11192    ) {
11193        self.manipulate_text(window, cx, |text| {
11194            text.split('\n')
11195                .map(|line| line.to_case(Case::UpperCamel))
11196                .join("\n")
11197        })
11198    }
11199
11200    pub fn convert_to_lower_camel_case(
11201        &mut self,
11202        _: &ConvertToLowerCamelCase,
11203        window: &mut Window,
11204        cx: &mut Context<Self>,
11205    ) {
11206        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11207    }
11208
11209    pub fn convert_to_opposite_case(
11210        &mut self,
11211        _: &ConvertToOppositeCase,
11212        window: &mut Window,
11213        cx: &mut Context<Self>,
11214    ) {
11215        self.manipulate_text(window, cx, |text| {
11216            text.chars()
11217                .fold(String::with_capacity(text.len()), |mut t, c| {
11218                    if c.is_uppercase() {
11219                        t.extend(c.to_lowercase());
11220                    } else {
11221                        t.extend(c.to_uppercase());
11222                    }
11223                    t
11224                })
11225        })
11226    }
11227
11228    pub fn convert_to_sentence_case(
11229        &mut self,
11230        _: &ConvertToSentenceCase,
11231        window: &mut Window,
11232        cx: &mut Context<Self>,
11233    ) {
11234        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11235    }
11236
11237    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11238        self.manipulate_text(window, cx, |text| {
11239            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11240            if has_upper_case_characters {
11241                text.to_lowercase()
11242            } else {
11243                text.to_uppercase()
11244            }
11245        })
11246    }
11247
11248    pub fn convert_to_rot13(
11249        &mut self,
11250        _: &ConvertToRot13,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        self.manipulate_text(window, cx, |text| {
11255            text.chars()
11256                .map(|c| match c {
11257                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11258                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11259                    _ => c,
11260                })
11261                .collect()
11262        })
11263    }
11264
11265    pub fn convert_to_rot47(
11266        &mut self,
11267        _: &ConvertToRot47,
11268        window: &mut Window,
11269        cx: &mut Context<Self>,
11270    ) {
11271        self.manipulate_text(window, cx, |text| {
11272            text.chars()
11273                .map(|c| {
11274                    let code_point = c as u32;
11275                    if code_point >= 33 && code_point <= 126 {
11276                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11277                    }
11278                    c
11279                })
11280                .collect()
11281        })
11282    }
11283
11284    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11285    where
11286        Fn: FnMut(&str) -> String,
11287    {
11288        let buffer = self.buffer.read(cx).snapshot(cx);
11289
11290        let mut new_selections = Vec::new();
11291        let mut edits = Vec::new();
11292        let mut selection_adjustment = 0i32;
11293
11294        for selection in self.selections.all::<usize>(cx) {
11295            let selection_is_empty = selection.is_empty();
11296
11297            let (start, end) = if selection_is_empty {
11298                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11299                (word_range.start, word_range.end)
11300            } else {
11301                (selection.start, selection.end)
11302            };
11303
11304            let text = buffer.text_for_range(start..end).collect::<String>();
11305            let old_length = text.len() as i32;
11306            let text = callback(&text);
11307
11308            new_selections.push(Selection {
11309                start: (start as i32 - selection_adjustment) as usize,
11310                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11311                goal: SelectionGoal::None,
11312                ..selection
11313            });
11314
11315            selection_adjustment += old_length - text.len() as i32;
11316
11317            edits.push((start..end, text));
11318        }
11319
11320        self.transact(window, cx, |this, window, cx| {
11321            this.buffer.update(cx, |buffer, cx| {
11322                buffer.edit(edits, None, cx);
11323            });
11324
11325            this.change_selections(Default::default(), window, cx, |s| {
11326                s.select(new_selections);
11327            });
11328
11329            this.request_autoscroll(Autoscroll::fit(), cx);
11330        });
11331    }
11332
11333    pub fn move_selection_on_drop(
11334        &mut self,
11335        selection: &Selection<Anchor>,
11336        target: DisplayPoint,
11337        is_cut: bool,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11342        let buffer = &display_map.buffer_snapshot;
11343        let mut edits = Vec::new();
11344        let insert_point = display_map
11345            .clip_point(target, Bias::Left)
11346            .to_point(&display_map);
11347        let text = buffer
11348            .text_for_range(selection.start..selection.end)
11349            .collect::<String>();
11350        if is_cut {
11351            edits.push(((selection.start..selection.end), String::new()));
11352        }
11353        let insert_anchor = buffer.anchor_before(insert_point);
11354        edits.push(((insert_anchor..insert_anchor), text));
11355        let last_edit_start = insert_anchor.bias_left(buffer);
11356        let last_edit_end = insert_anchor.bias_right(buffer);
11357        self.transact(window, cx, |this, window, cx| {
11358            this.buffer.update(cx, |buffer, cx| {
11359                buffer.edit(edits, None, cx);
11360            });
11361            this.change_selections(Default::default(), window, cx, |s| {
11362                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11363            });
11364        });
11365    }
11366
11367    pub fn clear_selection_drag_state(&mut self) {
11368        self.selection_drag_state = SelectionDragState::None;
11369    }
11370
11371    pub fn duplicate(
11372        &mut self,
11373        upwards: bool,
11374        whole_lines: bool,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11379
11380        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11381        let buffer = &display_map.buffer_snapshot;
11382        let selections = self.selections.all::<Point>(cx);
11383
11384        let mut edits = Vec::new();
11385        let mut selections_iter = selections.iter().peekable();
11386        while let Some(selection) = selections_iter.next() {
11387            let mut rows = selection.spanned_rows(false, &display_map);
11388            // duplicate line-wise
11389            if whole_lines || selection.start == selection.end {
11390                // Avoid duplicating the same lines twice.
11391                while let Some(next_selection) = selections_iter.peek() {
11392                    let next_rows = next_selection.spanned_rows(false, &display_map);
11393                    if next_rows.start < rows.end {
11394                        rows.end = next_rows.end;
11395                        selections_iter.next().unwrap();
11396                    } else {
11397                        break;
11398                    }
11399                }
11400
11401                // Copy the text from the selected row region and splice it either at the start
11402                // or end of the region.
11403                let start = Point::new(rows.start.0, 0);
11404                let end = Point::new(
11405                    rows.end.previous_row().0,
11406                    buffer.line_len(rows.end.previous_row()),
11407                );
11408                let text = buffer
11409                    .text_for_range(start..end)
11410                    .chain(Some("\n"))
11411                    .collect::<String>();
11412                let insert_location = if upwards {
11413                    Point::new(rows.end.0, 0)
11414                } else {
11415                    start
11416                };
11417                edits.push((insert_location..insert_location, text));
11418            } else {
11419                // duplicate character-wise
11420                let start = selection.start;
11421                let end = selection.end;
11422                let text = buffer.text_for_range(start..end).collect::<String>();
11423                edits.push((selection.end..selection.end, text));
11424            }
11425        }
11426
11427        self.transact(window, cx, |this, _, cx| {
11428            this.buffer.update(cx, |buffer, cx| {
11429                buffer.edit(edits, None, cx);
11430            });
11431
11432            this.request_autoscroll(Autoscroll::fit(), cx);
11433        });
11434    }
11435
11436    pub fn duplicate_line_up(
11437        &mut self,
11438        _: &DuplicateLineUp,
11439        window: &mut Window,
11440        cx: &mut Context<Self>,
11441    ) {
11442        self.duplicate(true, true, window, cx);
11443    }
11444
11445    pub fn duplicate_line_down(
11446        &mut self,
11447        _: &DuplicateLineDown,
11448        window: &mut Window,
11449        cx: &mut Context<Self>,
11450    ) {
11451        self.duplicate(false, true, window, cx);
11452    }
11453
11454    pub fn duplicate_selection(
11455        &mut self,
11456        _: &DuplicateSelection,
11457        window: &mut Window,
11458        cx: &mut Context<Self>,
11459    ) {
11460        self.duplicate(false, false, window, cx);
11461    }
11462
11463    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11465        if self.mode.is_single_line() {
11466            cx.propagate();
11467            return;
11468        }
11469
11470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11471        let buffer = self.buffer.read(cx).snapshot(cx);
11472
11473        let mut edits = Vec::new();
11474        let mut unfold_ranges = Vec::new();
11475        let mut refold_creases = Vec::new();
11476
11477        let selections = self.selections.all::<Point>(cx);
11478        let mut selections = selections.iter().peekable();
11479        let mut contiguous_row_selections = Vec::new();
11480        let mut new_selections = Vec::new();
11481
11482        while let Some(selection) = selections.next() {
11483            // Find all the selections that span a contiguous row range
11484            let (start_row, end_row) = consume_contiguous_rows(
11485                &mut contiguous_row_selections,
11486                selection,
11487                &display_map,
11488                &mut selections,
11489            );
11490
11491            // Move the text spanned by the row range to be before the line preceding the row range
11492            if start_row.0 > 0 {
11493                let range_to_move = Point::new(
11494                    start_row.previous_row().0,
11495                    buffer.line_len(start_row.previous_row()),
11496                )
11497                    ..Point::new(
11498                        end_row.previous_row().0,
11499                        buffer.line_len(end_row.previous_row()),
11500                    );
11501                let insertion_point = display_map
11502                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11503                    .0;
11504
11505                // Don't move lines across excerpts
11506                if buffer
11507                    .excerpt_containing(insertion_point..range_to_move.end)
11508                    .is_some()
11509                {
11510                    let text = buffer
11511                        .text_for_range(range_to_move.clone())
11512                        .flat_map(|s| s.chars())
11513                        .skip(1)
11514                        .chain(['\n'])
11515                        .collect::<String>();
11516
11517                    edits.push((
11518                        buffer.anchor_after(range_to_move.start)
11519                            ..buffer.anchor_before(range_to_move.end),
11520                        String::new(),
11521                    ));
11522                    let insertion_anchor = buffer.anchor_after(insertion_point);
11523                    edits.push((insertion_anchor..insertion_anchor, text));
11524
11525                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11526
11527                    // Move selections up
11528                    new_selections.extend(contiguous_row_selections.drain(..).map(
11529                        |mut selection| {
11530                            selection.start.row -= row_delta;
11531                            selection.end.row -= row_delta;
11532                            selection
11533                        },
11534                    ));
11535
11536                    // Move folds up
11537                    unfold_ranges.push(range_to_move.clone());
11538                    for fold in display_map.folds_in_range(
11539                        buffer.anchor_before(range_to_move.start)
11540                            ..buffer.anchor_after(range_to_move.end),
11541                    ) {
11542                        let mut start = fold.range.start.to_point(&buffer);
11543                        let mut end = fold.range.end.to_point(&buffer);
11544                        start.row -= row_delta;
11545                        end.row -= row_delta;
11546                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11547                    }
11548                }
11549            }
11550
11551            // If we didn't move line(s), preserve the existing selections
11552            new_selections.append(&mut contiguous_row_selections);
11553        }
11554
11555        self.transact(window, cx, |this, window, cx| {
11556            this.unfold_ranges(&unfold_ranges, true, true, cx);
11557            this.buffer.update(cx, |buffer, cx| {
11558                for (range, text) in edits {
11559                    buffer.edit([(range, text)], None, cx);
11560                }
11561            });
11562            this.fold_creases(refold_creases, true, window, cx);
11563            this.change_selections(Default::default(), window, cx, |s| {
11564                s.select(new_selections);
11565            })
11566        });
11567    }
11568
11569    pub fn move_line_down(
11570        &mut self,
11571        _: &MoveLineDown,
11572        window: &mut Window,
11573        cx: &mut Context<Self>,
11574    ) {
11575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11576        if self.mode.is_single_line() {
11577            cx.propagate();
11578            return;
11579        }
11580
11581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11582        let buffer = self.buffer.read(cx).snapshot(cx);
11583
11584        let mut edits = Vec::new();
11585        let mut unfold_ranges = Vec::new();
11586        let mut refold_creases = Vec::new();
11587
11588        let selections = self.selections.all::<Point>(cx);
11589        let mut selections = selections.iter().peekable();
11590        let mut contiguous_row_selections = Vec::new();
11591        let mut new_selections = Vec::new();
11592
11593        while let Some(selection) = selections.next() {
11594            // Find all the selections that span a contiguous row range
11595            let (start_row, end_row) = consume_contiguous_rows(
11596                &mut contiguous_row_selections,
11597                selection,
11598                &display_map,
11599                &mut selections,
11600            );
11601
11602            // Move the text spanned by the row range to be after the last line of the row range
11603            if end_row.0 <= buffer.max_point().row {
11604                let range_to_move =
11605                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11606                let insertion_point = display_map
11607                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11608                    .0;
11609
11610                // Don't move lines across excerpt boundaries
11611                if buffer
11612                    .excerpt_containing(range_to_move.start..insertion_point)
11613                    .is_some()
11614                {
11615                    let mut text = String::from("\n");
11616                    text.extend(buffer.text_for_range(range_to_move.clone()));
11617                    text.pop(); // Drop trailing newline
11618                    edits.push((
11619                        buffer.anchor_after(range_to_move.start)
11620                            ..buffer.anchor_before(range_to_move.end),
11621                        String::new(),
11622                    ));
11623                    let insertion_anchor = buffer.anchor_after(insertion_point);
11624                    edits.push((insertion_anchor..insertion_anchor, text));
11625
11626                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11627
11628                    // Move selections down
11629                    new_selections.extend(contiguous_row_selections.drain(..).map(
11630                        |mut selection| {
11631                            selection.start.row += row_delta;
11632                            selection.end.row += row_delta;
11633                            selection
11634                        },
11635                    ));
11636
11637                    // Move folds down
11638                    unfold_ranges.push(range_to_move.clone());
11639                    for fold in display_map.folds_in_range(
11640                        buffer.anchor_before(range_to_move.start)
11641                            ..buffer.anchor_after(range_to_move.end),
11642                    ) {
11643                        let mut start = fold.range.start.to_point(&buffer);
11644                        let mut end = fold.range.end.to_point(&buffer);
11645                        start.row += row_delta;
11646                        end.row += row_delta;
11647                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11648                    }
11649                }
11650            }
11651
11652            // If we didn't move line(s), preserve the existing selections
11653            new_selections.append(&mut contiguous_row_selections);
11654        }
11655
11656        self.transact(window, cx, |this, window, cx| {
11657            this.unfold_ranges(&unfold_ranges, true, true, cx);
11658            this.buffer.update(cx, |buffer, cx| {
11659                for (range, text) in edits {
11660                    buffer.edit([(range, text)], None, cx);
11661                }
11662            });
11663            this.fold_creases(refold_creases, true, window, cx);
11664            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11665        });
11666    }
11667
11668    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11670        let text_layout_details = &self.text_layout_details(window);
11671        self.transact(window, cx, |this, window, cx| {
11672            let edits = this.change_selections(Default::default(), window, cx, |s| {
11673                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11674                s.move_with(|display_map, selection| {
11675                    if !selection.is_empty() {
11676                        return;
11677                    }
11678
11679                    let mut head = selection.head();
11680                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11681                    if head.column() == display_map.line_len(head.row()) {
11682                        transpose_offset = display_map
11683                            .buffer_snapshot
11684                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11685                    }
11686
11687                    if transpose_offset == 0 {
11688                        return;
11689                    }
11690
11691                    *head.column_mut() += 1;
11692                    head = display_map.clip_point(head, Bias::Right);
11693                    let goal = SelectionGoal::HorizontalPosition(
11694                        display_map
11695                            .x_for_display_point(head, text_layout_details)
11696                            .into(),
11697                    );
11698                    selection.collapse_to(head, goal);
11699
11700                    let transpose_start = display_map
11701                        .buffer_snapshot
11702                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11703                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11704                        let transpose_end = display_map
11705                            .buffer_snapshot
11706                            .clip_offset(transpose_offset + 1, Bias::Right);
11707                        if let Some(ch) =
11708                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11709                        {
11710                            edits.push((transpose_start..transpose_offset, String::new()));
11711                            edits.push((transpose_end..transpose_end, ch.to_string()));
11712                        }
11713                    }
11714                });
11715                edits
11716            });
11717            this.buffer
11718                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11719            let selections = this.selections.all::<usize>(cx);
11720            this.change_selections(Default::default(), window, cx, |s| {
11721                s.select(selections);
11722            });
11723        });
11724    }
11725
11726    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11728        if self.mode.is_single_line() {
11729            cx.propagate();
11730            return;
11731        }
11732
11733        self.rewrap_impl(RewrapOptions::default(), cx)
11734    }
11735
11736    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11737        let buffer = self.buffer.read(cx).snapshot(cx);
11738        let selections = self.selections.all::<Point>(cx);
11739
11740        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11741        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11742            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11743                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11744                .peekable();
11745
11746            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11747                row
11748            } else {
11749                return Vec::new();
11750            };
11751
11752            let language_settings = buffer.language_settings_at(selection.head(), cx);
11753            let language_scope = buffer.language_scope_at(selection.head());
11754
11755            let indent_and_prefix_for_row =
11756                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11757                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11758                    let (comment_prefix, rewrap_prefix) =
11759                        if let Some(language_scope) = &language_scope {
11760                            let indent_end = Point::new(row, indent.len);
11761                            let comment_prefix = language_scope
11762                                .line_comment_prefixes()
11763                                .iter()
11764                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11765                                .map(|prefix| prefix.to_string());
11766                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11767                            let line_text_after_indent = buffer
11768                                .text_for_range(indent_end..line_end)
11769                                .collect::<String>();
11770                            let rewrap_prefix = language_scope
11771                                .rewrap_prefixes()
11772                                .iter()
11773                                .find_map(|prefix_regex| {
11774                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11775                                        if mat.start() == 0 {
11776                                            Some(mat.as_str().to_string())
11777                                        } else {
11778                                            None
11779                                        }
11780                                    })
11781                                })
11782                                .flatten();
11783                            (comment_prefix, rewrap_prefix)
11784                        } else {
11785                            (None, None)
11786                        };
11787                    (indent, comment_prefix, rewrap_prefix)
11788                };
11789
11790            let mut ranges = Vec::new();
11791            let from_empty_selection = selection.is_empty();
11792
11793            let mut current_range_start = first_row;
11794            let mut prev_row = first_row;
11795            let (
11796                mut current_range_indent,
11797                mut current_range_comment_prefix,
11798                mut current_range_rewrap_prefix,
11799            ) = indent_and_prefix_for_row(first_row);
11800
11801            for row in non_blank_rows_iter.skip(1) {
11802                let has_paragraph_break = row > prev_row + 1;
11803
11804                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11805                    indent_and_prefix_for_row(row);
11806
11807                let has_indent_change = row_indent != current_range_indent;
11808                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11809
11810                let has_boundary_change = has_comment_change
11811                    || row_rewrap_prefix.is_some()
11812                    || (has_indent_change && current_range_comment_prefix.is_some());
11813
11814                if has_paragraph_break || has_boundary_change {
11815                    ranges.push((
11816                        language_settings.clone(),
11817                        Point::new(current_range_start, 0)
11818                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11819                        current_range_indent,
11820                        current_range_comment_prefix.clone(),
11821                        current_range_rewrap_prefix.clone(),
11822                        from_empty_selection,
11823                    ));
11824                    current_range_start = row;
11825                    current_range_indent = row_indent;
11826                    current_range_comment_prefix = row_comment_prefix;
11827                    current_range_rewrap_prefix = row_rewrap_prefix;
11828                }
11829                prev_row = row;
11830            }
11831
11832            ranges.push((
11833                language_settings.clone(),
11834                Point::new(current_range_start, 0)
11835                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11836                current_range_indent,
11837                current_range_comment_prefix,
11838                current_range_rewrap_prefix,
11839                from_empty_selection,
11840            ));
11841
11842            ranges
11843        });
11844
11845        let mut edits = Vec::new();
11846        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11847
11848        for (
11849            language_settings,
11850            wrap_range,
11851            indent_size,
11852            comment_prefix,
11853            rewrap_prefix,
11854            from_empty_selection,
11855        ) in wrap_ranges
11856        {
11857            let mut start_row = wrap_range.start.row;
11858            let mut end_row = wrap_range.end.row;
11859
11860            // Skip selections that overlap with a range that has already been rewrapped.
11861            let selection_range = start_row..end_row;
11862            if rewrapped_row_ranges
11863                .iter()
11864                .any(|range| range.overlaps(&selection_range))
11865            {
11866                continue;
11867            }
11868
11869            let tab_size = language_settings.tab_size;
11870
11871            let indent_prefix = indent_size.chars().collect::<String>();
11872            let mut line_prefix = indent_prefix.clone();
11873            let mut inside_comment = false;
11874            if let Some(prefix) = &comment_prefix {
11875                line_prefix.push_str(prefix);
11876                inside_comment = true;
11877            }
11878            if let Some(prefix) = &rewrap_prefix {
11879                line_prefix.push_str(prefix);
11880            }
11881
11882            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11883                RewrapBehavior::InComments => inside_comment,
11884                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11885                RewrapBehavior::Anywhere => true,
11886            };
11887
11888            let should_rewrap = options.override_language_settings
11889                || allow_rewrap_based_on_language
11890                || self.hard_wrap.is_some();
11891            if !should_rewrap {
11892                continue;
11893            }
11894
11895            if from_empty_selection {
11896                'expand_upwards: while start_row > 0 {
11897                    let prev_row = start_row - 1;
11898                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11899                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11900                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11901                    {
11902                        start_row = prev_row;
11903                    } else {
11904                        break 'expand_upwards;
11905                    }
11906                }
11907
11908                'expand_downwards: while end_row < buffer.max_point().row {
11909                    let next_row = end_row + 1;
11910                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11911                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11912                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11913                    {
11914                        end_row = next_row;
11915                    } else {
11916                        break 'expand_downwards;
11917                    }
11918                }
11919            }
11920
11921            let start = Point::new(start_row, 0);
11922            let start_offset = start.to_offset(&buffer);
11923            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11924            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11925            let Some(lines_without_prefixes) = selection_text
11926                .lines()
11927                .enumerate()
11928                .map(|(ix, line)| {
11929                    let line_trimmed = line.trim_start();
11930                    if rewrap_prefix.is_some() && ix > 0 {
11931                        Ok(line_trimmed)
11932                    } else {
11933                        line_trimmed
11934                            .strip_prefix(&line_prefix.trim_start())
11935                            .with_context(|| {
11936                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11937                            })
11938                    }
11939                })
11940                .collect::<Result<Vec<_>, _>>()
11941                .log_err()
11942            else {
11943                continue;
11944            };
11945
11946            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11947                buffer
11948                    .language_settings_at(Point::new(start_row, 0), cx)
11949                    .preferred_line_length as usize
11950            });
11951
11952            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11953                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11954            } else {
11955                line_prefix.clone()
11956            };
11957
11958            let wrapped_text = wrap_with_prefix(
11959                line_prefix,
11960                subsequent_lines_prefix,
11961                lines_without_prefixes.join("\n"),
11962                wrap_column,
11963                tab_size,
11964                options.preserve_existing_whitespace,
11965            );
11966
11967            // TODO: should always use char-based diff while still supporting cursor behavior that
11968            // matches vim.
11969            let mut diff_options = DiffOptions::default();
11970            if options.override_language_settings {
11971                diff_options.max_word_diff_len = 0;
11972                diff_options.max_word_diff_line_count = 0;
11973            } else {
11974                diff_options.max_word_diff_len = usize::MAX;
11975                diff_options.max_word_diff_line_count = usize::MAX;
11976            }
11977
11978            for (old_range, new_text) in
11979                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11980            {
11981                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11982                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11983                edits.push((edit_start..edit_end, new_text));
11984            }
11985
11986            rewrapped_row_ranges.push(start_row..=end_row);
11987        }
11988
11989        self.buffer
11990            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11991    }
11992
11993    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11994        let mut text = String::new();
11995        let buffer = self.buffer.read(cx).snapshot(cx);
11996        let mut selections = self.selections.all::<Point>(cx);
11997        let mut clipboard_selections = Vec::with_capacity(selections.len());
11998        {
11999            let max_point = buffer.max_point();
12000            let mut is_first = true;
12001            for selection in &mut selections {
12002                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12003                if is_entire_line {
12004                    selection.start = Point::new(selection.start.row, 0);
12005                    if !selection.is_empty() && selection.end.column == 0 {
12006                        selection.end = cmp::min(max_point, selection.end);
12007                    } else {
12008                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12009                    }
12010                    selection.goal = SelectionGoal::None;
12011                }
12012                if is_first {
12013                    is_first = false;
12014                } else {
12015                    text += "\n";
12016                }
12017                let mut len = 0;
12018                for chunk in buffer.text_for_range(selection.start..selection.end) {
12019                    text.push_str(chunk);
12020                    len += chunk.len();
12021                }
12022                clipboard_selections.push(ClipboardSelection {
12023                    len,
12024                    is_entire_line,
12025                    first_line_indent: buffer
12026                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12027                        .len,
12028                });
12029            }
12030        }
12031
12032        self.transact(window, cx, |this, window, cx| {
12033            this.change_selections(Default::default(), window, cx, |s| {
12034                s.select(selections);
12035            });
12036            this.insert("", window, cx);
12037        });
12038        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12039    }
12040
12041    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12043        let item = self.cut_common(window, cx);
12044        cx.write_to_clipboard(item);
12045    }
12046
12047    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12048        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12049        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12050            s.move_with(|snapshot, sel| {
12051                if sel.is_empty() {
12052                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12053                }
12054            });
12055        });
12056        let item = self.cut_common(window, cx);
12057        cx.set_global(KillRing(item))
12058    }
12059
12060    pub fn kill_ring_yank(
12061        &mut self,
12062        _: &KillRingYank,
12063        window: &mut Window,
12064        cx: &mut Context<Self>,
12065    ) {
12066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12067        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12068            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12069                (kill_ring.text().to_string(), kill_ring.metadata_json())
12070            } else {
12071                return;
12072            }
12073        } else {
12074            return;
12075        };
12076        self.do_paste(&text, metadata, false, window, cx);
12077    }
12078
12079    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12080        self.do_copy(true, cx);
12081    }
12082
12083    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12084        self.do_copy(false, cx);
12085    }
12086
12087    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12088        let selections = self.selections.all::<Point>(cx);
12089        let buffer = self.buffer.read(cx).read(cx);
12090        let mut text = String::new();
12091
12092        let mut clipboard_selections = Vec::with_capacity(selections.len());
12093        {
12094            let max_point = buffer.max_point();
12095            let mut is_first = true;
12096            for selection in &selections {
12097                let mut start = selection.start;
12098                let mut end = selection.end;
12099                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12100                if is_entire_line {
12101                    start = Point::new(start.row, 0);
12102                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12103                }
12104
12105                let mut trimmed_selections = Vec::new();
12106                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12107                    let row = MultiBufferRow(start.row);
12108                    let first_indent = buffer.indent_size_for_line(row);
12109                    if first_indent.len == 0 || start.column > first_indent.len {
12110                        trimmed_selections.push(start..end);
12111                    } else {
12112                        trimmed_selections.push(
12113                            Point::new(row.0, first_indent.len)
12114                                ..Point::new(row.0, buffer.line_len(row)),
12115                        );
12116                        for row in start.row + 1..=end.row {
12117                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12118                            if row == end.row {
12119                                line_len = end.column;
12120                            }
12121                            if line_len == 0 {
12122                                trimmed_selections
12123                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12124                                continue;
12125                            }
12126                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12127                            if row_indent_size.len >= first_indent.len {
12128                                trimmed_selections.push(
12129                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12130                                );
12131                            } else {
12132                                trimmed_selections.clear();
12133                                trimmed_selections.push(start..end);
12134                                break;
12135                            }
12136                        }
12137                    }
12138                } else {
12139                    trimmed_selections.push(start..end);
12140                }
12141
12142                for trimmed_range in trimmed_selections {
12143                    if is_first {
12144                        is_first = false;
12145                    } else {
12146                        text += "\n";
12147                    }
12148                    let mut len = 0;
12149                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12150                        text.push_str(chunk);
12151                        len += chunk.len();
12152                    }
12153                    clipboard_selections.push(ClipboardSelection {
12154                        len,
12155                        is_entire_line,
12156                        first_line_indent: buffer
12157                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12158                            .len,
12159                    });
12160                }
12161            }
12162        }
12163
12164        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12165            text,
12166            clipboard_selections,
12167        ));
12168    }
12169
12170    pub fn do_paste(
12171        &mut self,
12172        text: &String,
12173        clipboard_selections: Option<Vec<ClipboardSelection>>,
12174        handle_entire_lines: bool,
12175        window: &mut Window,
12176        cx: &mut Context<Self>,
12177    ) {
12178        if self.read_only(cx) {
12179            return;
12180        }
12181
12182        let clipboard_text = Cow::Borrowed(text);
12183
12184        self.transact(window, cx, |this, window, cx| {
12185            let had_active_edit_prediction = this.has_active_edit_prediction();
12186
12187            if let Some(mut clipboard_selections) = clipboard_selections {
12188                let old_selections = this.selections.all::<usize>(cx);
12189                let all_selections_were_entire_line =
12190                    clipboard_selections.iter().all(|s| s.is_entire_line);
12191                let first_selection_indent_column =
12192                    clipboard_selections.first().map(|s| s.first_line_indent);
12193                if clipboard_selections.len() != old_selections.len() {
12194                    clipboard_selections.drain(..);
12195                }
12196                let cursor_offset = this.selections.last::<usize>(cx).head();
12197                let mut auto_indent_on_paste = true;
12198
12199                this.buffer.update(cx, |buffer, cx| {
12200                    let snapshot = buffer.read(cx);
12201                    auto_indent_on_paste = snapshot
12202                        .language_settings_at(cursor_offset, cx)
12203                        .auto_indent_on_paste;
12204
12205                    let mut start_offset = 0;
12206                    let mut edits = Vec::new();
12207                    let mut original_indent_columns = Vec::new();
12208                    for (ix, selection) in old_selections.iter().enumerate() {
12209                        let to_insert;
12210                        let entire_line;
12211                        let original_indent_column;
12212                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12213                            let end_offset = start_offset + clipboard_selection.len;
12214                            to_insert = &clipboard_text[start_offset..end_offset];
12215                            entire_line = clipboard_selection.is_entire_line;
12216                            start_offset = end_offset + 1;
12217                            original_indent_column = Some(clipboard_selection.first_line_indent);
12218                        } else {
12219                            to_insert = clipboard_text.as_str();
12220                            entire_line = all_selections_were_entire_line;
12221                            original_indent_column = first_selection_indent_column
12222                        }
12223
12224                        // If the corresponding selection was empty when this slice of the
12225                        // clipboard text was written, then the entire line containing the
12226                        // selection was copied. If this selection is also currently empty,
12227                        // then paste the line before the current line of the buffer.
12228                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12229                            let column = selection.start.to_point(&snapshot).column as usize;
12230                            let line_start = selection.start - column;
12231                            line_start..line_start
12232                        } else {
12233                            selection.range()
12234                        };
12235
12236                        edits.push((range, to_insert));
12237                        original_indent_columns.push(original_indent_column);
12238                    }
12239                    drop(snapshot);
12240
12241                    buffer.edit(
12242                        edits,
12243                        if auto_indent_on_paste {
12244                            Some(AutoindentMode::Block {
12245                                original_indent_columns,
12246                            })
12247                        } else {
12248                            None
12249                        },
12250                        cx,
12251                    );
12252                });
12253
12254                let selections = this.selections.all::<usize>(cx);
12255                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12256            } else {
12257                this.insert(&clipboard_text, window, cx);
12258            }
12259
12260            let trigger_in_words =
12261                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12262
12263            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12264        });
12265    }
12266
12267    pub fn diff_clipboard_with_selection(
12268        &mut self,
12269        _: &DiffClipboardWithSelection,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        let selections = self.selections.all::<usize>(cx);
12274
12275        if selections.is_empty() {
12276            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12277            return;
12278        };
12279
12280        let clipboard_text = match cx.read_from_clipboard() {
12281            Some(item) => match item.entries().first() {
12282                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12283                _ => None,
12284            },
12285            None => None,
12286        };
12287
12288        let Some(clipboard_text) = clipboard_text else {
12289            log::warn!("Clipboard doesn't contain text.");
12290            return;
12291        };
12292
12293        window.dispatch_action(
12294            Box::new(DiffClipboardWithSelectionData {
12295                clipboard_text,
12296                editor: cx.entity(),
12297            }),
12298            cx,
12299        );
12300    }
12301
12302    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12303        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12304        if let Some(item) = cx.read_from_clipboard() {
12305            let entries = item.entries();
12306
12307            match entries.first() {
12308                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12309                // of all the pasted entries.
12310                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12311                    .do_paste(
12312                        clipboard_string.text(),
12313                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12314                        true,
12315                        window,
12316                        cx,
12317                    ),
12318                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12319            }
12320        }
12321    }
12322
12323    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12324        if self.read_only(cx) {
12325            return;
12326        }
12327
12328        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12329
12330        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12331            if let Some((selections, _)) =
12332                self.selection_history.transaction(transaction_id).cloned()
12333            {
12334                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12335                    s.select_anchors(selections.to_vec());
12336                });
12337            } else {
12338                log::error!(
12339                    "No entry in selection_history found for undo. \
12340                     This may correspond to a bug where undo does not update the selection. \
12341                     If this is occurring, please add details to \
12342                     https://github.com/zed-industries/zed/issues/22692"
12343                );
12344            }
12345            self.request_autoscroll(Autoscroll::fit(), cx);
12346            self.unmark_text(window, cx);
12347            self.refresh_edit_prediction(true, false, window, cx);
12348            cx.emit(EditorEvent::Edited { transaction_id });
12349            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12350        }
12351    }
12352
12353    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12354        if self.read_only(cx) {
12355            return;
12356        }
12357
12358        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12359
12360        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12361            if let Some((_, Some(selections))) =
12362                self.selection_history.transaction(transaction_id).cloned()
12363            {
12364                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12365                    s.select_anchors(selections.to_vec());
12366                });
12367            } else {
12368                log::error!(
12369                    "No entry in selection_history found for redo. \
12370                     This may correspond to a bug where undo does not update the selection. \
12371                     If this is occurring, please add details to \
12372                     https://github.com/zed-industries/zed/issues/22692"
12373                );
12374            }
12375            self.request_autoscroll(Autoscroll::fit(), cx);
12376            self.unmark_text(window, cx);
12377            self.refresh_edit_prediction(true, false, window, cx);
12378            cx.emit(EditorEvent::Edited { transaction_id });
12379        }
12380    }
12381
12382    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12383        self.buffer
12384            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12385    }
12386
12387    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12388        self.buffer
12389            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12390    }
12391
12392    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12394        self.change_selections(Default::default(), window, cx, |s| {
12395            s.move_with(|map, selection| {
12396                let cursor = if selection.is_empty() {
12397                    movement::left(map, selection.start)
12398                } else {
12399                    selection.start
12400                };
12401                selection.collapse_to(cursor, SelectionGoal::None);
12402            });
12403        })
12404    }
12405
12406    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12408        self.change_selections(Default::default(), window, cx, |s| {
12409            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12410        })
12411    }
12412
12413    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12415        self.change_selections(Default::default(), window, cx, |s| {
12416            s.move_with(|map, selection| {
12417                let cursor = if selection.is_empty() {
12418                    movement::right(map, selection.end)
12419                } else {
12420                    selection.end
12421                };
12422                selection.collapse_to(cursor, SelectionGoal::None)
12423            });
12424        })
12425    }
12426
12427    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12429        self.change_selections(Default::default(), window, cx, |s| {
12430            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12431        })
12432    }
12433
12434    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12435        if self.take_rename(true, window, cx).is_some() {
12436            return;
12437        }
12438
12439        if self.mode.is_single_line() {
12440            cx.propagate();
12441            return;
12442        }
12443
12444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12445
12446        let text_layout_details = &self.text_layout_details(window);
12447        let selection_count = self.selections.count();
12448        let first_selection = self.selections.first_anchor();
12449
12450        self.change_selections(Default::default(), window, cx, |s| {
12451            s.move_with(|map, selection| {
12452                if !selection.is_empty() {
12453                    selection.goal = SelectionGoal::None;
12454                }
12455                let (cursor, goal) = movement::up(
12456                    map,
12457                    selection.start,
12458                    selection.goal,
12459                    false,
12460                    text_layout_details,
12461                );
12462                selection.collapse_to(cursor, goal);
12463            });
12464        });
12465
12466        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12467        {
12468            cx.propagate();
12469        }
12470    }
12471
12472    pub fn move_up_by_lines(
12473        &mut self,
12474        action: &MoveUpByLines,
12475        window: &mut Window,
12476        cx: &mut Context<Self>,
12477    ) {
12478        if self.take_rename(true, window, cx).is_some() {
12479            return;
12480        }
12481
12482        if self.mode.is_single_line() {
12483            cx.propagate();
12484            return;
12485        }
12486
12487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12488
12489        let text_layout_details = &self.text_layout_details(window);
12490
12491        self.change_selections(Default::default(), window, cx, |s| {
12492            s.move_with(|map, selection| {
12493                if !selection.is_empty() {
12494                    selection.goal = SelectionGoal::None;
12495                }
12496                let (cursor, goal) = movement::up_by_rows(
12497                    map,
12498                    selection.start,
12499                    action.lines,
12500                    selection.goal,
12501                    false,
12502                    text_layout_details,
12503                );
12504                selection.collapse_to(cursor, goal);
12505            });
12506        })
12507    }
12508
12509    pub fn move_down_by_lines(
12510        &mut self,
12511        action: &MoveDownByLines,
12512        window: &mut Window,
12513        cx: &mut Context<Self>,
12514    ) {
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
12528        self.change_selections(Default::default(), window, cx, |s| {
12529            s.move_with(|map, selection| {
12530                if !selection.is_empty() {
12531                    selection.goal = SelectionGoal::None;
12532                }
12533                let (cursor, goal) = movement::down_by_rows(
12534                    map,
12535                    selection.start,
12536                    action.lines,
12537                    selection.goal,
12538                    false,
12539                    text_layout_details,
12540                );
12541                selection.collapse_to(cursor, goal);
12542            });
12543        })
12544    }
12545
12546    pub fn select_down_by_lines(
12547        &mut self,
12548        action: &SelectDownByLines,
12549        window: &mut Window,
12550        cx: &mut Context<Self>,
12551    ) {
12552        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12553        let text_layout_details = &self.text_layout_details(window);
12554        self.change_selections(Default::default(), window, cx, |s| {
12555            s.move_heads_with(|map, head, goal| {
12556                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12557            })
12558        })
12559    }
12560
12561    pub fn select_up_by_lines(
12562        &mut self,
12563        action: &SelectUpByLines,
12564        window: &mut Window,
12565        cx: &mut Context<Self>,
12566    ) {
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12568        let text_layout_details = &self.text_layout_details(window);
12569        self.change_selections(Default::default(), window, cx, |s| {
12570            s.move_heads_with(|map, head, goal| {
12571                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12572            })
12573        })
12574    }
12575
12576    pub fn select_page_up(
12577        &mut self,
12578        _: &SelectPageUp,
12579        window: &mut Window,
12580        cx: &mut Context<Self>,
12581    ) {
12582        let Some(row_count) = self.visible_row_count() else {
12583            return;
12584        };
12585
12586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12587
12588        let text_layout_details = &self.text_layout_details(window);
12589
12590        self.change_selections(Default::default(), window, cx, |s| {
12591            s.move_heads_with(|map, head, goal| {
12592                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12593            })
12594        })
12595    }
12596
12597    pub fn move_page_up(
12598        &mut self,
12599        action: &MovePageUp,
12600        window: &mut Window,
12601        cx: &mut Context<Self>,
12602    ) {
12603        if self.take_rename(true, window, cx).is_some() {
12604            return;
12605        }
12606
12607        if self
12608            .context_menu
12609            .borrow_mut()
12610            .as_mut()
12611            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12612            .unwrap_or(false)
12613        {
12614            return;
12615        }
12616
12617        if matches!(self.mode, EditorMode::SingleLine) {
12618            cx.propagate();
12619            return;
12620        }
12621
12622        let Some(row_count) = self.visible_row_count() else {
12623            return;
12624        };
12625
12626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12627
12628        let effects = if action.center_cursor {
12629            SelectionEffects::scroll(Autoscroll::center())
12630        } else {
12631            SelectionEffects::default()
12632        };
12633
12634        let text_layout_details = &self.text_layout_details(window);
12635
12636        self.change_selections(effects, window, cx, |s| {
12637            s.move_with(|map, selection| {
12638                if !selection.is_empty() {
12639                    selection.goal = SelectionGoal::None;
12640                }
12641                let (cursor, goal) = movement::up_by_rows(
12642                    map,
12643                    selection.end,
12644                    row_count,
12645                    selection.goal,
12646                    false,
12647                    text_layout_details,
12648                );
12649                selection.collapse_to(cursor, goal);
12650            });
12651        });
12652    }
12653
12654    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12655        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12656        let text_layout_details = &self.text_layout_details(window);
12657        self.change_selections(Default::default(), window, cx, |s| {
12658            s.move_heads_with(|map, head, goal| {
12659                movement::up(map, head, goal, false, text_layout_details)
12660            })
12661        })
12662    }
12663
12664    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12665        self.take_rename(true, window, cx);
12666
12667        if self.mode.is_single_line() {
12668            cx.propagate();
12669            return;
12670        }
12671
12672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12673
12674        let text_layout_details = &self.text_layout_details(window);
12675        let selection_count = self.selections.count();
12676        let first_selection = self.selections.first_anchor();
12677
12678        self.change_selections(Default::default(), window, cx, |s| {
12679            s.move_with(|map, selection| {
12680                if !selection.is_empty() {
12681                    selection.goal = SelectionGoal::None;
12682                }
12683                let (cursor, goal) = movement::down(
12684                    map,
12685                    selection.end,
12686                    selection.goal,
12687                    false,
12688                    text_layout_details,
12689                );
12690                selection.collapse_to(cursor, goal);
12691            });
12692        });
12693
12694        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12695        {
12696            cx.propagate();
12697        }
12698    }
12699
12700    pub fn select_page_down(
12701        &mut self,
12702        _: &SelectPageDown,
12703        window: &mut Window,
12704        cx: &mut Context<Self>,
12705    ) {
12706        let Some(row_count) = self.visible_row_count() else {
12707            return;
12708        };
12709
12710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12711
12712        let text_layout_details = &self.text_layout_details(window);
12713
12714        self.change_selections(Default::default(), window, cx, |s| {
12715            s.move_heads_with(|map, head, goal| {
12716                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12717            })
12718        })
12719    }
12720
12721    pub fn move_page_down(
12722        &mut self,
12723        action: &MovePageDown,
12724        window: &mut Window,
12725        cx: &mut Context<Self>,
12726    ) {
12727        if self.take_rename(true, window, cx).is_some() {
12728            return;
12729        }
12730
12731        if self
12732            .context_menu
12733            .borrow_mut()
12734            .as_mut()
12735            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12736            .unwrap_or(false)
12737        {
12738            return;
12739        }
12740
12741        if matches!(self.mode, EditorMode::SingleLine) {
12742            cx.propagate();
12743            return;
12744        }
12745
12746        let Some(row_count) = self.visible_row_count() else {
12747            return;
12748        };
12749
12750        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12751
12752        let effects = if action.center_cursor {
12753            SelectionEffects::scroll(Autoscroll::center())
12754        } else {
12755            SelectionEffects::default()
12756        };
12757
12758        let text_layout_details = &self.text_layout_details(window);
12759        self.change_selections(effects, window, cx, |s| {
12760            s.move_with(|map, selection| {
12761                if !selection.is_empty() {
12762                    selection.goal = SelectionGoal::None;
12763                }
12764                let (cursor, goal) = movement::down_by_rows(
12765                    map,
12766                    selection.end,
12767                    row_count,
12768                    selection.goal,
12769                    false,
12770                    text_layout_details,
12771                );
12772                selection.collapse_to(cursor, goal);
12773            });
12774        });
12775    }
12776
12777    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12779        let text_layout_details = &self.text_layout_details(window);
12780        self.change_selections(Default::default(), window, cx, |s| {
12781            s.move_heads_with(|map, head, goal| {
12782                movement::down(map, head, goal, false, text_layout_details)
12783            })
12784        });
12785    }
12786
12787    pub fn context_menu_first(
12788        &mut self,
12789        _: &ContextMenuFirst,
12790        window: &mut Window,
12791        cx: &mut Context<Self>,
12792    ) {
12793        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12794            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12795        }
12796    }
12797
12798    pub fn context_menu_prev(
12799        &mut self,
12800        _: &ContextMenuPrevious,
12801        window: &mut Window,
12802        cx: &mut Context<Self>,
12803    ) {
12804        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12805            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12806        }
12807    }
12808
12809    pub fn context_menu_next(
12810        &mut self,
12811        _: &ContextMenuNext,
12812        window: &mut Window,
12813        cx: &mut Context<Self>,
12814    ) {
12815        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12816            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12817        }
12818    }
12819
12820    pub fn context_menu_last(
12821        &mut self,
12822        _: &ContextMenuLast,
12823        window: &mut Window,
12824        cx: &mut Context<Self>,
12825    ) {
12826        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12827            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12828        }
12829    }
12830
12831    pub fn signature_help_prev(
12832        &mut self,
12833        _: &SignatureHelpPrevious,
12834        _: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        if let Some(popover) = self.signature_help_state.popover_mut() {
12838            if popover.current_signature == 0 {
12839                popover.current_signature = popover.signatures.len() - 1;
12840            } else {
12841                popover.current_signature -= 1;
12842            }
12843            cx.notify();
12844        }
12845    }
12846
12847    pub fn signature_help_next(
12848        &mut self,
12849        _: &SignatureHelpNext,
12850        _: &mut Window,
12851        cx: &mut Context<Self>,
12852    ) {
12853        if let Some(popover) = self.signature_help_state.popover_mut() {
12854            if popover.current_signature + 1 == popover.signatures.len() {
12855                popover.current_signature = 0;
12856            } else {
12857                popover.current_signature += 1;
12858            }
12859            cx.notify();
12860        }
12861    }
12862
12863    pub fn move_to_previous_word_start(
12864        &mut self,
12865        _: &MoveToPreviousWordStart,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12870        self.change_selections(Default::default(), window, cx, |s| {
12871            s.move_cursors_with(|map, head, _| {
12872                (
12873                    movement::previous_word_start(map, head),
12874                    SelectionGoal::None,
12875                )
12876            });
12877        })
12878    }
12879
12880    pub fn move_to_previous_subword_start(
12881        &mut self,
12882        _: &MoveToPreviousSubwordStart,
12883        window: &mut Window,
12884        cx: &mut Context<Self>,
12885    ) {
12886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_cursors_with(|map, head, _| {
12889                (
12890                    movement::previous_subword_start(map, head),
12891                    SelectionGoal::None,
12892                )
12893            });
12894        })
12895    }
12896
12897    pub fn select_to_previous_word_start(
12898        &mut self,
12899        _: &SelectToPreviousWordStart,
12900        window: &mut Window,
12901        cx: &mut Context<Self>,
12902    ) {
12903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12904        self.change_selections(Default::default(), window, cx, |s| {
12905            s.move_heads_with(|map, head, _| {
12906                (
12907                    movement::previous_word_start(map, head),
12908                    SelectionGoal::None,
12909                )
12910            });
12911        })
12912    }
12913
12914    pub fn select_to_previous_subword_start(
12915        &mut self,
12916        _: &SelectToPreviousSubwordStart,
12917        window: &mut Window,
12918        cx: &mut Context<Self>,
12919    ) {
12920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12921        self.change_selections(Default::default(), window, cx, |s| {
12922            s.move_heads_with(|map, head, _| {
12923                (
12924                    movement::previous_subword_start(map, head),
12925                    SelectionGoal::None,
12926                )
12927            });
12928        })
12929    }
12930
12931    pub fn delete_to_previous_word_start(
12932        &mut self,
12933        action: &DeleteToPreviousWordStart,
12934        window: &mut Window,
12935        cx: &mut Context<Self>,
12936    ) {
12937        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12938        self.transact(window, cx, |this, window, cx| {
12939            this.select_autoclose_pair(window, cx);
12940            this.change_selections(Default::default(), window, cx, |s| {
12941                s.move_with(|map, selection| {
12942                    if selection.is_empty() {
12943                        let cursor = if action.ignore_newlines {
12944                            movement::previous_word_start(map, selection.head())
12945                        } else {
12946                            movement::previous_word_start_or_newline(map, selection.head())
12947                        };
12948                        selection.set_head(cursor, SelectionGoal::None);
12949                    }
12950                });
12951            });
12952            this.insert("", window, cx);
12953        });
12954    }
12955
12956    pub fn delete_to_previous_subword_start(
12957        &mut self,
12958        _: &DeleteToPreviousSubwordStart,
12959        window: &mut Window,
12960        cx: &mut Context<Self>,
12961    ) {
12962        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12963        self.transact(window, cx, |this, window, cx| {
12964            this.select_autoclose_pair(window, cx);
12965            this.change_selections(Default::default(), window, cx, |s| {
12966                s.move_with(|map, selection| {
12967                    if selection.is_empty() {
12968                        let cursor = movement::previous_subword_start(map, selection.head());
12969                        selection.set_head(cursor, SelectionGoal::None);
12970                    }
12971                });
12972            });
12973            this.insert("", window, cx);
12974        });
12975    }
12976
12977    pub fn move_to_next_word_end(
12978        &mut self,
12979        _: &MoveToNextWordEnd,
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_cursors_with(|map, head, _| {
12986                (movement::next_word_end(map, head), SelectionGoal::None)
12987            });
12988        })
12989    }
12990
12991    pub fn move_to_next_subword_end(
12992        &mut self,
12993        _: &MoveToNextSubwordEnd,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) {
12997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12998        self.change_selections(Default::default(), window, cx, |s| {
12999            s.move_cursors_with(|map, head, _| {
13000                (movement::next_subword_end(map, head), SelectionGoal::None)
13001            });
13002        })
13003    }
13004
13005    pub fn select_to_next_word_end(
13006        &mut self,
13007        _: &SelectToNextWordEnd,
13008        window: &mut Window,
13009        cx: &mut Context<Self>,
13010    ) {
13011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13012        self.change_selections(Default::default(), window, cx, |s| {
13013            s.move_heads_with(|map, head, _| {
13014                (movement::next_word_end(map, head), SelectionGoal::None)
13015            });
13016        })
13017    }
13018
13019    pub fn select_to_next_subword_end(
13020        &mut self,
13021        _: &SelectToNextSubwordEnd,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_heads_with(|map, head, _| {
13028                (movement::next_subword_end(map, head), SelectionGoal::None)
13029            });
13030        })
13031    }
13032
13033    pub fn delete_to_next_word_end(
13034        &mut self,
13035        action: &DeleteToNextWordEnd,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13040        self.transact(window, cx, |this, window, cx| {
13041            this.change_selections(Default::default(), window, cx, |s| {
13042                s.move_with(|map, selection| {
13043                    if selection.is_empty() {
13044                        let cursor = if action.ignore_newlines {
13045                            movement::next_word_end(map, selection.head())
13046                        } else {
13047                            movement::next_word_end_or_newline(map, selection.head())
13048                        };
13049                        selection.set_head(cursor, SelectionGoal::None);
13050                    }
13051                });
13052            });
13053            this.insert("", window, cx);
13054        });
13055    }
13056
13057    pub fn delete_to_next_subword_end(
13058        &mut self,
13059        _: &DeleteToNextSubwordEnd,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13064        self.transact(window, cx, |this, window, cx| {
13065            this.change_selections(Default::default(), window, cx, |s| {
13066                s.move_with(|map, selection| {
13067                    if selection.is_empty() {
13068                        let cursor = movement::next_subword_end(map, selection.head());
13069                        selection.set_head(cursor, SelectionGoal::None);
13070                    }
13071                });
13072            });
13073            this.insert("", window, cx);
13074        });
13075    }
13076
13077    pub fn move_to_beginning_of_line(
13078        &mut self,
13079        action: &MoveToBeginningOfLine,
13080        window: &mut Window,
13081        cx: &mut Context<Self>,
13082    ) {
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084        self.change_selections(Default::default(), window, cx, |s| {
13085            s.move_cursors_with(|map, head, _| {
13086                (
13087                    movement::indented_line_beginning(
13088                        map,
13089                        head,
13090                        action.stop_at_soft_wraps,
13091                        action.stop_at_indent,
13092                    ),
13093                    SelectionGoal::None,
13094                )
13095            });
13096        })
13097    }
13098
13099    pub fn select_to_beginning_of_line(
13100        &mut self,
13101        action: &SelectToBeginningOfLine,
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                (
13109                    movement::indented_line_beginning(
13110                        map,
13111                        head,
13112                        action.stop_at_soft_wraps,
13113                        action.stop_at_indent,
13114                    ),
13115                    SelectionGoal::None,
13116                )
13117            });
13118        });
13119    }
13120
13121    pub fn delete_to_beginning_of_line(
13122        &mut self,
13123        action: &DeleteToBeginningOfLine,
13124        window: &mut Window,
13125        cx: &mut Context<Self>,
13126    ) {
13127        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13128        self.transact(window, cx, |this, window, cx| {
13129            this.change_selections(Default::default(), window, cx, |s| {
13130                s.move_with(|_, selection| {
13131                    selection.reversed = true;
13132                });
13133            });
13134
13135            this.select_to_beginning_of_line(
13136                &SelectToBeginningOfLine {
13137                    stop_at_soft_wraps: false,
13138                    stop_at_indent: action.stop_at_indent,
13139                },
13140                window,
13141                cx,
13142            );
13143            this.backspace(&Backspace, window, cx);
13144        });
13145    }
13146
13147    pub fn move_to_end_of_line(
13148        &mut self,
13149        action: &MoveToEndOfLine,
13150        window: &mut Window,
13151        cx: &mut Context<Self>,
13152    ) {
13153        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13154        self.change_selections(Default::default(), window, cx, |s| {
13155            s.move_cursors_with(|map, head, _| {
13156                (
13157                    movement::line_end(map, head, action.stop_at_soft_wraps),
13158                    SelectionGoal::None,
13159                )
13160            });
13161        })
13162    }
13163
13164    pub fn select_to_end_of_line(
13165        &mut self,
13166        action: &SelectToEndOfLine,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13171        self.change_selections(Default::default(), window, cx, |s| {
13172            s.move_heads_with(|map, head, _| {
13173                (
13174                    movement::line_end(map, head, action.stop_at_soft_wraps),
13175                    SelectionGoal::None,
13176                )
13177            });
13178        })
13179    }
13180
13181    pub fn delete_to_end_of_line(
13182        &mut self,
13183        _: &DeleteToEndOfLine,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13188        self.transact(window, cx, |this, window, cx| {
13189            this.select_to_end_of_line(
13190                &SelectToEndOfLine {
13191                    stop_at_soft_wraps: false,
13192                },
13193                window,
13194                cx,
13195            );
13196            this.delete(&Delete, window, cx);
13197        });
13198    }
13199
13200    pub fn cut_to_end_of_line(
13201        &mut self,
13202        _: &CutToEndOfLine,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13207        self.transact(window, cx, |this, window, cx| {
13208            this.select_to_end_of_line(
13209                &SelectToEndOfLine {
13210                    stop_at_soft_wraps: false,
13211                },
13212                window,
13213                cx,
13214            );
13215            this.cut(&Cut, window, cx);
13216        });
13217    }
13218
13219    pub fn move_to_start_of_paragraph(
13220        &mut self,
13221        _: &MoveToStartOfParagraph,
13222        window: &mut Window,
13223        cx: &mut Context<Self>,
13224    ) {
13225        if matches!(self.mode, EditorMode::SingleLine) {
13226            cx.propagate();
13227            return;
13228        }
13229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13230        self.change_selections(Default::default(), window, cx, |s| {
13231            s.move_with(|map, selection| {
13232                selection.collapse_to(
13233                    movement::start_of_paragraph(map, selection.head(), 1),
13234                    SelectionGoal::None,
13235                )
13236            });
13237        })
13238    }
13239
13240    pub fn move_to_end_of_paragraph(
13241        &mut self,
13242        _: &MoveToEndOfParagraph,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        if matches!(self.mode, EditorMode::SingleLine) {
13247            cx.propagate();
13248            return;
13249        }
13250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13251        self.change_selections(Default::default(), window, cx, |s| {
13252            s.move_with(|map, selection| {
13253                selection.collapse_to(
13254                    movement::end_of_paragraph(map, selection.head(), 1),
13255                    SelectionGoal::None,
13256                )
13257            });
13258        })
13259    }
13260
13261    pub fn select_to_start_of_paragraph(
13262        &mut self,
13263        _: &SelectToStartOfParagraph,
13264        window: &mut Window,
13265        cx: &mut Context<Self>,
13266    ) {
13267        if matches!(self.mode, EditorMode::SingleLine) {
13268            cx.propagate();
13269            return;
13270        }
13271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13272        self.change_selections(Default::default(), window, cx, |s| {
13273            s.move_heads_with(|map, head, _| {
13274                (
13275                    movement::start_of_paragraph(map, head, 1),
13276                    SelectionGoal::None,
13277                )
13278            });
13279        })
13280    }
13281
13282    pub fn select_to_end_of_paragraph(
13283        &mut self,
13284        _: &SelectToEndOfParagraph,
13285        window: &mut Window,
13286        cx: &mut Context<Self>,
13287    ) {
13288        if matches!(self.mode, EditorMode::SingleLine) {
13289            cx.propagate();
13290            return;
13291        }
13292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13293        self.change_selections(Default::default(), window, cx, |s| {
13294            s.move_heads_with(|map, head, _| {
13295                (
13296                    movement::end_of_paragraph(map, head, 1),
13297                    SelectionGoal::None,
13298                )
13299            });
13300        })
13301    }
13302
13303    pub fn move_to_start_of_excerpt(
13304        &mut self,
13305        _: &MoveToStartOfExcerpt,
13306        window: &mut Window,
13307        cx: &mut Context<Self>,
13308    ) {
13309        if matches!(self.mode, EditorMode::SingleLine) {
13310            cx.propagate();
13311            return;
13312        }
13313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13314        self.change_selections(Default::default(), window, cx, |s| {
13315            s.move_with(|map, selection| {
13316                selection.collapse_to(
13317                    movement::start_of_excerpt(
13318                        map,
13319                        selection.head(),
13320                        workspace::searchable::Direction::Prev,
13321                    ),
13322                    SelectionGoal::None,
13323                )
13324            });
13325        })
13326    }
13327
13328    pub fn move_to_start_of_next_excerpt(
13329        &mut self,
13330        _: &MoveToStartOfNextExcerpt,
13331        window: &mut Window,
13332        cx: &mut Context<Self>,
13333    ) {
13334        if matches!(self.mode, EditorMode::SingleLine) {
13335            cx.propagate();
13336            return;
13337        }
13338
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_with(|map, selection| {
13341                selection.collapse_to(
13342                    movement::start_of_excerpt(
13343                        map,
13344                        selection.head(),
13345                        workspace::searchable::Direction::Next,
13346                    ),
13347                    SelectionGoal::None,
13348                )
13349            });
13350        })
13351    }
13352
13353    pub fn move_to_end_of_excerpt(
13354        &mut self,
13355        _: &MoveToEndOfExcerpt,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        if matches!(self.mode, EditorMode::SingleLine) {
13360            cx.propagate();
13361            return;
13362        }
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        self.change_selections(Default::default(), window, cx, |s| {
13365            s.move_with(|map, selection| {
13366                selection.collapse_to(
13367                    movement::end_of_excerpt(
13368                        map,
13369                        selection.head(),
13370                        workspace::searchable::Direction::Next,
13371                    ),
13372                    SelectionGoal::None,
13373                )
13374            });
13375        })
13376    }
13377
13378    pub fn move_to_end_of_previous_excerpt(
13379        &mut self,
13380        _: &MoveToEndOfPreviousExcerpt,
13381        window: &mut Window,
13382        cx: &mut Context<Self>,
13383    ) {
13384        if matches!(self.mode, EditorMode::SingleLine) {
13385            cx.propagate();
13386            return;
13387        }
13388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13389        self.change_selections(Default::default(), window, cx, |s| {
13390            s.move_with(|map, selection| {
13391                selection.collapse_to(
13392                    movement::end_of_excerpt(
13393                        map,
13394                        selection.head(),
13395                        workspace::searchable::Direction::Prev,
13396                    ),
13397                    SelectionGoal::None,
13398                )
13399            });
13400        })
13401    }
13402
13403    pub fn select_to_start_of_excerpt(
13404        &mut self,
13405        _: &SelectToStartOfExcerpt,
13406        window: &mut Window,
13407        cx: &mut Context<Self>,
13408    ) {
13409        if matches!(self.mode, EditorMode::SingleLine) {
13410            cx.propagate();
13411            return;
13412        }
13413        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13414        self.change_selections(Default::default(), window, cx, |s| {
13415            s.move_heads_with(|map, head, _| {
13416                (
13417                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13418                    SelectionGoal::None,
13419                )
13420            });
13421        })
13422    }
13423
13424    pub fn select_to_start_of_next_excerpt(
13425        &mut self,
13426        _: &SelectToStartOfNextExcerpt,
13427        window: &mut Window,
13428        cx: &mut Context<Self>,
13429    ) {
13430        if matches!(self.mode, EditorMode::SingleLine) {
13431            cx.propagate();
13432            return;
13433        }
13434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13435        self.change_selections(Default::default(), window, cx, |s| {
13436            s.move_heads_with(|map, head, _| {
13437                (
13438                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13439                    SelectionGoal::None,
13440                )
13441            });
13442        })
13443    }
13444
13445    pub fn select_to_end_of_excerpt(
13446        &mut self,
13447        _: &SelectToEndOfExcerpt,
13448        window: &mut Window,
13449        cx: &mut Context<Self>,
13450    ) {
13451        if matches!(self.mode, EditorMode::SingleLine) {
13452            cx.propagate();
13453            return;
13454        }
13455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13456        self.change_selections(Default::default(), window, cx, |s| {
13457            s.move_heads_with(|map, head, _| {
13458                (
13459                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13460                    SelectionGoal::None,
13461                )
13462            });
13463        })
13464    }
13465
13466    pub fn select_to_end_of_previous_excerpt(
13467        &mut self,
13468        _: &SelectToEndOfPreviousExcerpt,
13469        window: &mut Window,
13470        cx: &mut Context<Self>,
13471    ) {
13472        if matches!(self.mode, EditorMode::SingleLine) {
13473            cx.propagate();
13474            return;
13475        }
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13477        self.change_selections(Default::default(), window, cx, |s| {
13478            s.move_heads_with(|map, head, _| {
13479                (
13480                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13481                    SelectionGoal::None,
13482                )
13483            });
13484        })
13485    }
13486
13487    pub fn move_to_beginning(
13488        &mut self,
13489        _: &MoveToBeginning,
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        if matches!(self.mode, EditorMode::SingleLine) {
13494            cx.propagate();
13495            return;
13496        }
13497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13498        self.change_selections(Default::default(), window, cx, |s| {
13499            s.select_ranges(vec![0..0]);
13500        });
13501    }
13502
13503    pub fn select_to_beginning(
13504        &mut self,
13505        _: &SelectToBeginning,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) {
13509        let mut selection = self.selections.last::<Point>(cx);
13510        selection.set_head(Point::zero(), SelectionGoal::None);
13511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13512        self.change_selections(Default::default(), window, cx, |s| {
13513            s.select(vec![selection]);
13514        });
13515    }
13516
13517    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13518        if matches!(self.mode, EditorMode::SingleLine) {
13519            cx.propagate();
13520            return;
13521        }
13522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13523        let cursor = self.buffer.read(cx).read(cx).len();
13524        self.change_selections(Default::default(), window, cx, |s| {
13525            s.select_ranges(vec![cursor..cursor])
13526        });
13527    }
13528
13529    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13530        self.nav_history = nav_history;
13531    }
13532
13533    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13534        self.nav_history.as_ref()
13535    }
13536
13537    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13538        self.push_to_nav_history(
13539            self.selections.newest_anchor().head(),
13540            None,
13541            false,
13542            true,
13543            cx,
13544        );
13545    }
13546
13547    fn push_to_nav_history(
13548        &mut self,
13549        cursor_anchor: Anchor,
13550        new_position: Option<Point>,
13551        is_deactivate: bool,
13552        always: bool,
13553        cx: &mut Context<Self>,
13554    ) {
13555        if let Some(nav_history) = self.nav_history.as_mut() {
13556            let buffer = self.buffer.read(cx).read(cx);
13557            let cursor_position = cursor_anchor.to_point(&buffer);
13558            let scroll_state = self.scroll_manager.anchor();
13559            let scroll_top_row = scroll_state.top_row(&buffer);
13560            drop(buffer);
13561
13562            if let Some(new_position) = new_position {
13563                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13564                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13565                    return;
13566                }
13567            }
13568
13569            nav_history.push(
13570                Some(NavigationData {
13571                    cursor_anchor,
13572                    cursor_position,
13573                    scroll_anchor: scroll_state,
13574                    scroll_top_row,
13575                }),
13576                cx,
13577            );
13578            cx.emit(EditorEvent::PushedToNavHistory {
13579                anchor: cursor_anchor,
13580                is_deactivate,
13581            })
13582        }
13583    }
13584
13585    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13587        let buffer = self.buffer.read(cx).snapshot(cx);
13588        let mut selection = self.selections.first::<usize>(cx);
13589        selection.set_head(buffer.len(), SelectionGoal::None);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.select(vec![selection]);
13592        });
13593    }
13594
13595    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13597        let end = self.buffer.read(cx).read(cx).len();
13598        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13599            s.select_ranges(vec![0..end]);
13600        });
13601    }
13602
13603    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13606        let mut selections = self.selections.all::<Point>(cx);
13607        let max_point = display_map.buffer_snapshot.max_point();
13608        for selection in &mut selections {
13609            let rows = selection.spanned_rows(true, &display_map);
13610            selection.start = Point::new(rows.start.0, 0);
13611            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13612            selection.reversed = false;
13613        }
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.select(selections);
13616        });
13617    }
13618
13619    pub fn split_selection_into_lines(
13620        &mut self,
13621        action: &SplitSelectionIntoLines,
13622        window: &mut Window,
13623        cx: &mut Context<Self>,
13624    ) {
13625        let selections = self
13626            .selections
13627            .all::<Point>(cx)
13628            .into_iter()
13629            .map(|selection| selection.start..selection.end)
13630            .collect::<Vec<_>>();
13631        self.unfold_ranges(&selections, true, true, cx);
13632
13633        let mut new_selection_ranges = Vec::new();
13634        {
13635            let buffer = self.buffer.read(cx).read(cx);
13636            for selection in selections {
13637                for row in selection.start.row..selection.end.row {
13638                    let line_start = Point::new(row, 0);
13639                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13640
13641                    if action.keep_selections {
13642                        // Keep the selection range for each line
13643                        let selection_start = if row == selection.start.row {
13644                            selection.start
13645                        } else {
13646                            line_start
13647                        };
13648                        new_selection_ranges.push(selection_start..line_end);
13649                    } else {
13650                        // Collapse to cursor at end of line
13651                        new_selection_ranges.push(line_end..line_end);
13652                    }
13653                }
13654
13655                let is_multiline_selection = selection.start.row != selection.end.row;
13656                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13657                // so this action feels more ergonomic when paired with other selection operations
13658                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13659                if !should_skip_last {
13660                    if action.keep_selections {
13661                        if is_multiline_selection {
13662                            let line_start = Point::new(selection.end.row, 0);
13663                            new_selection_ranges.push(line_start..selection.end);
13664                        } else {
13665                            new_selection_ranges.push(selection.start..selection.end);
13666                        }
13667                    } else {
13668                        new_selection_ranges.push(selection.end..selection.end);
13669                    }
13670                }
13671            }
13672        }
13673        self.change_selections(Default::default(), window, cx, |s| {
13674            s.select_ranges(new_selection_ranges);
13675        });
13676    }
13677
13678    pub fn add_selection_above(
13679        &mut self,
13680        _: &AddSelectionAbove,
13681        window: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        self.add_selection(true, window, cx);
13685    }
13686
13687    pub fn add_selection_below(
13688        &mut self,
13689        _: &AddSelectionBelow,
13690        window: &mut Window,
13691        cx: &mut Context<Self>,
13692    ) {
13693        self.add_selection(false, window, cx);
13694    }
13695
13696    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13697        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13698
13699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13700        let all_selections = self.selections.all::<Point>(cx);
13701        let text_layout_details = self.text_layout_details(window);
13702
13703        let (mut columnar_selections, new_selections_to_columnarize) = {
13704            if let Some(state) = self.add_selections_state.as_ref() {
13705                let columnar_selection_ids: HashSet<_> = state
13706                    .groups
13707                    .iter()
13708                    .flat_map(|group| group.stack.iter())
13709                    .copied()
13710                    .collect();
13711
13712                all_selections
13713                    .into_iter()
13714                    .partition(|s| columnar_selection_ids.contains(&s.id))
13715            } else {
13716                (Vec::new(), all_selections)
13717            }
13718        };
13719
13720        let mut state = self
13721            .add_selections_state
13722            .take()
13723            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13724
13725        for selection in new_selections_to_columnarize {
13726            let range = selection.display_range(&display_map).sorted();
13727            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13728            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13729            let positions = start_x.min(end_x)..start_x.max(end_x);
13730            let mut stack = Vec::new();
13731            for row in range.start.row().0..=range.end.row().0 {
13732                if let Some(selection) = self.selections.build_columnar_selection(
13733                    &display_map,
13734                    DisplayRow(row),
13735                    &positions,
13736                    selection.reversed,
13737                    &text_layout_details,
13738                ) {
13739                    stack.push(selection.id);
13740                    columnar_selections.push(selection);
13741                }
13742            }
13743            if !stack.is_empty() {
13744                if above {
13745                    stack.reverse();
13746                }
13747                state.groups.push(AddSelectionsGroup { above, stack });
13748            }
13749        }
13750
13751        let mut final_selections = Vec::new();
13752        let end_row = if above {
13753            DisplayRow(0)
13754        } else {
13755            display_map.max_point().row()
13756        };
13757
13758        let mut last_added_item_per_group = HashMap::default();
13759        for group in state.groups.iter_mut() {
13760            if let Some(last_id) = group.stack.last() {
13761                last_added_item_per_group.insert(*last_id, group);
13762            }
13763        }
13764
13765        for selection in columnar_selections {
13766            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13767                if above == group.above {
13768                    let range = selection.display_range(&display_map).sorted();
13769                    debug_assert_eq!(range.start.row(), range.end.row());
13770                    let mut row = range.start.row();
13771                    let positions =
13772                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13773                            px(start)..px(end)
13774                        } else {
13775                            let start_x =
13776                                display_map.x_for_display_point(range.start, &text_layout_details);
13777                            let end_x =
13778                                display_map.x_for_display_point(range.end, &text_layout_details);
13779                            start_x.min(end_x)..start_x.max(end_x)
13780                        };
13781
13782                    let mut maybe_new_selection = None;
13783                    while row != end_row {
13784                        if above {
13785                            row.0 -= 1;
13786                        } else {
13787                            row.0 += 1;
13788                        }
13789                        if let Some(new_selection) = self.selections.build_columnar_selection(
13790                            &display_map,
13791                            row,
13792                            &positions,
13793                            selection.reversed,
13794                            &text_layout_details,
13795                        ) {
13796                            maybe_new_selection = Some(new_selection);
13797                            break;
13798                        }
13799                    }
13800
13801                    if let Some(new_selection) = maybe_new_selection {
13802                        group.stack.push(new_selection.id);
13803                        if above {
13804                            final_selections.push(new_selection);
13805                            final_selections.push(selection);
13806                        } else {
13807                            final_selections.push(selection);
13808                            final_selections.push(new_selection);
13809                        }
13810                    } else {
13811                        final_selections.push(selection);
13812                    }
13813                } else {
13814                    group.stack.pop();
13815                }
13816            } else {
13817                final_selections.push(selection);
13818            }
13819        }
13820
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.select(final_selections);
13823        });
13824
13825        let final_selection_ids: HashSet<_> = self
13826            .selections
13827            .all::<Point>(cx)
13828            .iter()
13829            .map(|s| s.id)
13830            .collect();
13831        state.groups.retain_mut(|group| {
13832            // selections might get merged above so we remove invalid items from stacks
13833            group.stack.retain(|id| final_selection_ids.contains(id));
13834
13835            // single selection in stack can be treated as initial state
13836            group.stack.len() > 1
13837        });
13838
13839        if !state.groups.is_empty() {
13840            self.add_selections_state = Some(state);
13841        }
13842    }
13843
13844    fn select_match_ranges(
13845        &mut self,
13846        range: Range<usize>,
13847        reversed: bool,
13848        replace_newest: bool,
13849        auto_scroll: Option<Autoscroll>,
13850        window: &mut Window,
13851        cx: &mut Context<Editor>,
13852    ) {
13853        self.unfold_ranges(
13854            std::slice::from_ref(&range),
13855            false,
13856            auto_scroll.is_some(),
13857            cx,
13858        );
13859        let effects = if let Some(scroll) = auto_scroll {
13860            SelectionEffects::scroll(scroll)
13861        } else {
13862            SelectionEffects::no_scroll()
13863        };
13864        self.change_selections(effects, window, cx, |s| {
13865            if replace_newest {
13866                s.delete(s.newest_anchor().id);
13867            }
13868            if reversed {
13869                s.insert_range(range.end..range.start);
13870            } else {
13871                s.insert_range(range);
13872            }
13873        });
13874    }
13875
13876    pub fn select_next_match_internal(
13877        &mut self,
13878        display_map: &DisplaySnapshot,
13879        replace_newest: bool,
13880        autoscroll: Option<Autoscroll>,
13881        window: &mut Window,
13882        cx: &mut Context<Self>,
13883    ) -> Result<()> {
13884        let buffer = &display_map.buffer_snapshot;
13885        let mut selections = self.selections.all::<usize>(cx);
13886        if let Some(mut select_next_state) = self.select_next_state.take() {
13887            let query = &select_next_state.query;
13888            if !select_next_state.done {
13889                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13890                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13891                let mut next_selected_range = None;
13892
13893                let bytes_after_last_selection =
13894                    buffer.bytes_in_range(last_selection.end..buffer.len());
13895                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13896                let query_matches = query
13897                    .stream_find_iter(bytes_after_last_selection)
13898                    .map(|result| (last_selection.end, result))
13899                    .chain(
13900                        query
13901                            .stream_find_iter(bytes_before_first_selection)
13902                            .map(|result| (0, result)),
13903                    );
13904
13905                for (start_offset, query_match) in query_matches {
13906                    let query_match = query_match.unwrap(); // can only fail due to I/O
13907                    let offset_range =
13908                        start_offset + query_match.start()..start_offset + query_match.end();
13909
13910                    if !select_next_state.wordwise
13911                        || (!buffer.is_inside_word(offset_range.start, false)
13912                            && !buffer.is_inside_word(offset_range.end, false))
13913                    {
13914                        // TODO: This is n^2, because we might check all the selections
13915                        if !selections
13916                            .iter()
13917                            .any(|selection| selection.range().overlaps(&offset_range))
13918                        {
13919                            next_selected_range = Some(offset_range);
13920                            break;
13921                        }
13922                    }
13923                }
13924
13925                if let Some(next_selected_range) = next_selected_range {
13926                    self.select_match_ranges(
13927                        next_selected_range,
13928                        last_selection.reversed,
13929                        replace_newest,
13930                        autoscroll,
13931                        window,
13932                        cx,
13933                    );
13934                } else {
13935                    select_next_state.done = true;
13936                }
13937            }
13938
13939            self.select_next_state = Some(select_next_state);
13940        } else {
13941            let mut only_carets = true;
13942            let mut same_text_selected = true;
13943            let mut selected_text = None;
13944
13945            let mut selections_iter = selections.iter().peekable();
13946            while let Some(selection) = selections_iter.next() {
13947                if selection.start != selection.end {
13948                    only_carets = false;
13949                }
13950
13951                if same_text_selected {
13952                    if selected_text.is_none() {
13953                        selected_text =
13954                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13955                    }
13956
13957                    if let Some(next_selection) = selections_iter.peek() {
13958                        if next_selection.range().len() == selection.range().len() {
13959                            let next_selected_text = buffer
13960                                .text_for_range(next_selection.range())
13961                                .collect::<String>();
13962                            if Some(next_selected_text) != selected_text {
13963                                same_text_selected = false;
13964                                selected_text = None;
13965                            }
13966                        } else {
13967                            same_text_selected = false;
13968                            selected_text = None;
13969                        }
13970                    }
13971                }
13972            }
13973
13974            if only_carets {
13975                for selection in &mut selections {
13976                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13977                    selection.start = word_range.start;
13978                    selection.end = word_range.end;
13979                    selection.goal = SelectionGoal::None;
13980                    selection.reversed = false;
13981                    self.select_match_ranges(
13982                        selection.start..selection.end,
13983                        selection.reversed,
13984                        replace_newest,
13985                        autoscroll,
13986                        window,
13987                        cx,
13988                    );
13989                }
13990
13991                if selections.len() == 1 {
13992                    let selection = selections
13993                        .last()
13994                        .expect("ensured that there's only one selection");
13995                    let query = buffer
13996                        .text_for_range(selection.start..selection.end)
13997                        .collect::<String>();
13998                    let is_empty = query.is_empty();
13999                    let select_state = SelectNextState {
14000                        query: AhoCorasick::new(&[query])?,
14001                        wordwise: true,
14002                        done: is_empty,
14003                    };
14004                    self.select_next_state = Some(select_state);
14005                } else {
14006                    self.select_next_state = None;
14007                }
14008            } else if let Some(selected_text) = selected_text {
14009                self.select_next_state = Some(SelectNextState {
14010                    query: AhoCorasick::new(&[selected_text])?,
14011                    wordwise: false,
14012                    done: false,
14013                });
14014                self.select_next_match_internal(
14015                    display_map,
14016                    replace_newest,
14017                    autoscroll,
14018                    window,
14019                    cx,
14020                )?;
14021            }
14022        }
14023        Ok(())
14024    }
14025
14026    pub fn select_all_matches(
14027        &mut self,
14028        _action: &SelectAllMatches,
14029        window: &mut Window,
14030        cx: &mut Context<Self>,
14031    ) -> Result<()> {
14032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14033
14034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14035
14036        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14037        let Some(select_next_state) = self.select_next_state.as_mut() else {
14038            return Ok(());
14039        };
14040        if select_next_state.done {
14041            return Ok(());
14042        }
14043
14044        let mut new_selections = Vec::new();
14045
14046        let reversed = self.selections.oldest::<usize>(cx).reversed;
14047        let buffer = &display_map.buffer_snapshot;
14048        let query_matches = select_next_state
14049            .query
14050            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14051
14052        for query_match in query_matches.into_iter() {
14053            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14054            let offset_range = if reversed {
14055                query_match.end()..query_match.start()
14056            } else {
14057                query_match.start()..query_match.end()
14058            };
14059
14060            if !select_next_state.wordwise
14061                || (!buffer.is_inside_word(offset_range.start, false)
14062                    && !buffer.is_inside_word(offset_range.end, false))
14063            {
14064                new_selections.push(offset_range.start..offset_range.end);
14065            }
14066        }
14067
14068        select_next_state.done = true;
14069
14070        if new_selections.is_empty() {
14071            log::error!("bug: new_selections is empty in select_all_matches");
14072            return Ok(());
14073        }
14074
14075        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14076        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14077            selections.select_ranges(new_selections)
14078        });
14079
14080        Ok(())
14081    }
14082
14083    pub fn select_next(
14084        &mut self,
14085        action: &SelectNext,
14086        window: &mut Window,
14087        cx: &mut Context<Self>,
14088    ) -> Result<()> {
14089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14090        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14091        self.select_next_match_internal(
14092            &display_map,
14093            action.replace_newest,
14094            Some(Autoscroll::newest()),
14095            window,
14096            cx,
14097        )?;
14098        Ok(())
14099    }
14100
14101    pub fn select_previous(
14102        &mut self,
14103        action: &SelectPrevious,
14104        window: &mut Window,
14105        cx: &mut Context<Self>,
14106    ) -> Result<()> {
14107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14108        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14109        let buffer = &display_map.buffer_snapshot;
14110        let mut selections = self.selections.all::<usize>(cx);
14111        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14112            let query = &select_prev_state.query;
14113            if !select_prev_state.done {
14114                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14115                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14116                let mut next_selected_range = None;
14117                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14118                let bytes_before_last_selection =
14119                    buffer.reversed_bytes_in_range(0..last_selection.start);
14120                let bytes_after_first_selection =
14121                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14122                let query_matches = query
14123                    .stream_find_iter(bytes_before_last_selection)
14124                    .map(|result| (last_selection.start, result))
14125                    .chain(
14126                        query
14127                            .stream_find_iter(bytes_after_first_selection)
14128                            .map(|result| (buffer.len(), result)),
14129                    );
14130                for (end_offset, query_match) in query_matches {
14131                    let query_match = query_match.unwrap(); // can only fail due to I/O
14132                    let offset_range =
14133                        end_offset - query_match.end()..end_offset - query_match.start();
14134
14135                    if !select_prev_state.wordwise
14136                        || (!buffer.is_inside_word(offset_range.start, false)
14137                            && !buffer.is_inside_word(offset_range.end, false))
14138                    {
14139                        next_selected_range = Some(offset_range);
14140                        break;
14141                    }
14142                }
14143
14144                if let Some(next_selected_range) = next_selected_range {
14145                    self.select_match_ranges(
14146                        next_selected_range,
14147                        last_selection.reversed,
14148                        action.replace_newest,
14149                        Some(Autoscroll::newest()),
14150                        window,
14151                        cx,
14152                    );
14153                } else {
14154                    select_prev_state.done = true;
14155                }
14156            }
14157
14158            self.select_prev_state = Some(select_prev_state);
14159        } else {
14160            let mut only_carets = true;
14161            let mut same_text_selected = true;
14162            let mut selected_text = None;
14163
14164            let mut selections_iter = selections.iter().peekable();
14165            while let Some(selection) = selections_iter.next() {
14166                if selection.start != selection.end {
14167                    only_carets = false;
14168                }
14169
14170                if same_text_selected {
14171                    if selected_text.is_none() {
14172                        selected_text =
14173                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14174                    }
14175
14176                    if let Some(next_selection) = selections_iter.peek() {
14177                        if next_selection.range().len() == selection.range().len() {
14178                            let next_selected_text = buffer
14179                                .text_for_range(next_selection.range())
14180                                .collect::<String>();
14181                            if Some(next_selected_text) != selected_text {
14182                                same_text_selected = false;
14183                                selected_text = None;
14184                            }
14185                        } else {
14186                            same_text_selected = false;
14187                            selected_text = None;
14188                        }
14189                    }
14190                }
14191            }
14192
14193            if only_carets {
14194                for selection in &mut selections {
14195                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14196                    selection.start = word_range.start;
14197                    selection.end = word_range.end;
14198                    selection.goal = SelectionGoal::None;
14199                    selection.reversed = false;
14200                    self.select_match_ranges(
14201                        selection.start..selection.end,
14202                        selection.reversed,
14203                        action.replace_newest,
14204                        Some(Autoscroll::newest()),
14205                        window,
14206                        cx,
14207                    );
14208                }
14209                if selections.len() == 1 {
14210                    let selection = selections
14211                        .last()
14212                        .expect("ensured that there's only one selection");
14213                    let query = buffer
14214                        .text_for_range(selection.start..selection.end)
14215                        .collect::<String>();
14216                    let is_empty = query.is_empty();
14217                    let select_state = SelectNextState {
14218                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14219                        wordwise: true,
14220                        done: is_empty,
14221                    };
14222                    self.select_prev_state = Some(select_state);
14223                } else {
14224                    self.select_prev_state = None;
14225                }
14226            } else if let Some(selected_text) = selected_text {
14227                self.select_prev_state = Some(SelectNextState {
14228                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14229                    wordwise: false,
14230                    done: false,
14231                });
14232                self.select_previous(action, window, cx)?;
14233            }
14234        }
14235        Ok(())
14236    }
14237
14238    pub fn find_next_match(
14239        &mut self,
14240        _: &FindNextMatch,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Result<()> {
14244        let selections = self.selections.disjoint_anchors();
14245        match selections.first() {
14246            Some(first) if selections.len() >= 2 => {
14247                self.change_selections(Default::default(), window, cx, |s| {
14248                    s.select_ranges([first.range()]);
14249                });
14250            }
14251            _ => self.select_next(
14252                &SelectNext {
14253                    replace_newest: true,
14254                },
14255                window,
14256                cx,
14257            )?,
14258        }
14259        Ok(())
14260    }
14261
14262    pub fn find_previous_match(
14263        &mut self,
14264        _: &FindPreviousMatch,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) -> Result<()> {
14268        let selections = self.selections.disjoint_anchors();
14269        match selections.last() {
14270            Some(last) if selections.len() >= 2 => {
14271                self.change_selections(Default::default(), window, cx, |s| {
14272                    s.select_ranges([last.range()]);
14273                });
14274            }
14275            _ => self.select_previous(
14276                &SelectPrevious {
14277                    replace_newest: true,
14278                },
14279                window,
14280                cx,
14281            )?,
14282        }
14283        Ok(())
14284    }
14285
14286    pub fn toggle_comments(
14287        &mut self,
14288        action: &ToggleComments,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) {
14292        if self.read_only(cx) {
14293            return;
14294        }
14295        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14296        let text_layout_details = &self.text_layout_details(window);
14297        self.transact(window, cx, |this, window, cx| {
14298            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14299            let mut edits = Vec::new();
14300            let mut selection_edit_ranges = Vec::new();
14301            let mut last_toggled_row = None;
14302            let snapshot = this.buffer.read(cx).read(cx);
14303            let empty_str: Arc<str> = Arc::default();
14304            let mut suffixes_inserted = Vec::new();
14305            let ignore_indent = action.ignore_indent;
14306
14307            fn comment_prefix_range(
14308                snapshot: &MultiBufferSnapshot,
14309                row: MultiBufferRow,
14310                comment_prefix: &str,
14311                comment_prefix_whitespace: &str,
14312                ignore_indent: bool,
14313            ) -> Range<Point> {
14314                let indent_size = if ignore_indent {
14315                    0
14316                } else {
14317                    snapshot.indent_size_for_line(row).len
14318                };
14319
14320                let start = Point::new(row.0, indent_size);
14321
14322                let mut line_bytes = snapshot
14323                    .bytes_in_range(start..snapshot.max_point())
14324                    .flatten()
14325                    .copied();
14326
14327                // If this line currently begins with the line comment prefix, then record
14328                // the range containing the prefix.
14329                if line_bytes
14330                    .by_ref()
14331                    .take(comment_prefix.len())
14332                    .eq(comment_prefix.bytes())
14333                {
14334                    // Include any whitespace that matches the comment prefix.
14335                    let matching_whitespace_len = line_bytes
14336                        .zip(comment_prefix_whitespace.bytes())
14337                        .take_while(|(a, b)| a == b)
14338                        .count() as u32;
14339                    let end = Point::new(
14340                        start.row,
14341                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14342                    );
14343                    start..end
14344                } else {
14345                    start..start
14346                }
14347            }
14348
14349            fn comment_suffix_range(
14350                snapshot: &MultiBufferSnapshot,
14351                row: MultiBufferRow,
14352                comment_suffix: &str,
14353                comment_suffix_has_leading_space: bool,
14354            ) -> Range<Point> {
14355                let end = Point::new(row.0, snapshot.line_len(row));
14356                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14357
14358                let mut line_end_bytes = snapshot
14359                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14360                    .flatten()
14361                    .copied();
14362
14363                let leading_space_len = if suffix_start_column > 0
14364                    && line_end_bytes.next() == Some(b' ')
14365                    && comment_suffix_has_leading_space
14366                {
14367                    1
14368                } else {
14369                    0
14370                };
14371
14372                // If this line currently begins with the line comment prefix, then record
14373                // the range containing the prefix.
14374                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14375                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14376                    start..end
14377                } else {
14378                    end..end
14379                }
14380            }
14381
14382            // TODO: Handle selections that cross excerpts
14383            for selection in &mut selections {
14384                let start_column = snapshot
14385                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14386                    .len;
14387                let language = if let Some(language) =
14388                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14389                {
14390                    language
14391                } else {
14392                    continue;
14393                };
14394
14395                selection_edit_ranges.clear();
14396
14397                // If multiple selections contain a given row, avoid processing that
14398                // row more than once.
14399                let mut start_row = MultiBufferRow(selection.start.row);
14400                if last_toggled_row == Some(start_row) {
14401                    start_row = start_row.next_row();
14402                }
14403                let end_row =
14404                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14405                        MultiBufferRow(selection.end.row - 1)
14406                    } else {
14407                        MultiBufferRow(selection.end.row)
14408                    };
14409                last_toggled_row = Some(end_row);
14410
14411                if start_row > end_row {
14412                    continue;
14413                }
14414
14415                // If the language has line comments, toggle those.
14416                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14417
14418                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14419                if ignore_indent {
14420                    full_comment_prefixes = full_comment_prefixes
14421                        .into_iter()
14422                        .map(|s| Arc::from(s.trim_end()))
14423                        .collect();
14424                }
14425
14426                if !full_comment_prefixes.is_empty() {
14427                    let first_prefix = full_comment_prefixes
14428                        .first()
14429                        .expect("prefixes is non-empty");
14430                    let prefix_trimmed_lengths = full_comment_prefixes
14431                        .iter()
14432                        .map(|p| p.trim_end_matches(' ').len())
14433                        .collect::<SmallVec<[usize; 4]>>();
14434
14435                    let mut all_selection_lines_are_comments = true;
14436
14437                    for row in start_row.0..=end_row.0 {
14438                        let row = MultiBufferRow(row);
14439                        if start_row < end_row && snapshot.is_line_blank(row) {
14440                            continue;
14441                        }
14442
14443                        let prefix_range = full_comment_prefixes
14444                            .iter()
14445                            .zip(prefix_trimmed_lengths.iter().copied())
14446                            .map(|(prefix, trimmed_prefix_len)| {
14447                                comment_prefix_range(
14448                                    snapshot.deref(),
14449                                    row,
14450                                    &prefix[..trimmed_prefix_len],
14451                                    &prefix[trimmed_prefix_len..],
14452                                    ignore_indent,
14453                                )
14454                            })
14455                            .max_by_key(|range| range.end.column - range.start.column)
14456                            .expect("prefixes is non-empty");
14457
14458                        if prefix_range.is_empty() {
14459                            all_selection_lines_are_comments = false;
14460                        }
14461
14462                        selection_edit_ranges.push(prefix_range);
14463                    }
14464
14465                    if all_selection_lines_are_comments {
14466                        edits.extend(
14467                            selection_edit_ranges
14468                                .iter()
14469                                .cloned()
14470                                .map(|range| (range, empty_str.clone())),
14471                        );
14472                    } else {
14473                        let min_column = selection_edit_ranges
14474                            .iter()
14475                            .map(|range| range.start.column)
14476                            .min()
14477                            .unwrap_or(0);
14478                        edits.extend(selection_edit_ranges.iter().map(|range| {
14479                            let position = Point::new(range.start.row, min_column);
14480                            (position..position, first_prefix.clone())
14481                        }));
14482                    }
14483                } else if let Some(BlockCommentConfig {
14484                    start: full_comment_prefix,
14485                    end: comment_suffix,
14486                    ..
14487                }) = language.block_comment()
14488                {
14489                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14490                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14491                    let prefix_range = comment_prefix_range(
14492                        snapshot.deref(),
14493                        start_row,
14494                        comment_prefix,
14495                        comment_prefix_whitespace,
14496                        ignore_indent,
14497                    );
14498                    let suffix_range = comment_suffix_range(
14499                        snapshot.deref(),
14500                        end_row,
14501                        comment_suffix.trim_start_matches(' '),
14502                        comment_suffix.starts_with(' '),
14503                    );
14504
14505                    if prefix_range.is_empty() || suffix_range.is_empty() {
14506                        edits.push((
14507                            prefix_range.start..prefix_range.start,
14508                            full_comment_prefix.clone(),
14509                        ));
14510                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14511                        suffixes_inserted.push((end_row, comment_suffix.len()));
14512                    } else {
14513                        edits.push((prefix_range, empty_str.clone()));
14514                        edits.push((suffix_range, empty_str.clone()));
14515                    }
14516                } else {
14517                    continue;
14518                }
14519            }
14520
14521            drop(snapshot);
14522            this.buffer.update(cx, |buffer, cx| {
14523                buffer.edit(edits, None, cx);
14524            });
14525
14526            // Adjust selections so that they end before any comment suffixes that
14527            // were inserted.
14528            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14529            let mut selections = this.selections.all::<Point>(cx);
14530            let snapshot = this.buffer.read(cx).read(cx);
14531            for selection in &mut selections {
14532                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14533                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14534                        Ordering::Less => {
14535                            suffixes_inserted.next();
14536                            continue;
14537                        }
14538                        Ordering::Greater => break,
14539                        Ordering::Equal => {
14540                            if selection.end.column == snapshot.line_len(row) {
14541                                if selection.is_empty() {
14542                                    selection.start.column -= suffix_len as u32;
14543                                }
14544                                selection.end.column -= suffix_len as u32;
14545                            }
14546                            break;
14547                        }
14548                    }
14549                }
14550            }
14551
14552            drop(snapshot);
14553            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14554
14555            let selections = this.selections.all::<Point>(cx);
14556            let selections_on_single_row = selections.windows(2).all(|selections| {
14557                selections[0].start.row == selections[1].start.row
14558                    && selections[0].end.row == selections[1].end.row
14559                    && selections[0].start.row == selections[0].end.row
14560            });
14561            let selections_selecting = selections
14562                .iter()
14563                .any(|selection| selection.start != selection.end);
14564            let advance_downwards = action.advance_downwards
14565                && selections_on_single_row
14566                && !selections_selecting
14567                && !matches!(this.mode, EditorMode::SingleLine);
14568
14569            if advance_downwards {
14570                let snapshot = this.buffer.read(cx).snapshot(cx);
14571
14572                this.change_selections(Default::default(), window, cx, |s| {
14573                    s.move_cursors_with(|display_snapshot, display_point, _| {
14574                        let mut point = display_point.to_point(display_snapshot);
14575                        point.row += 1;
14576                        point = snapshot.clip_point(point, Bias::Left);
14577                        let display_point = point.to_display_point(display_snapshot);
14578                        let goal = SelectionGoal::HorizontalPosition(
14579                            display_snapshot
14580                                .x_for_display_point(display_point, text_layout_details)
14581                                .into(),
14582                        );
14583                        (display_point, goal)
14584                    })
14585                });
14586            }
14587        });
14588    }
14589
14590    pub fn select_enclosing_symbol(
14591        &mut self,
14592        _: &SelectEnclosingSymbol,
14593        window: &mut Window,
14594        cx: &mut Context<Self>,
14595    ) {
14596        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14597
14598        let buffer = self.buffer.read(cx).snapshot(cx);
14599        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14600
14601        fn update_selection(
14602            selection: &Selection<usize>,
14603            buffer_snap: &MultiBufferSnapshot,
14604        ) -> Option<Selection<usize>> {
14605            let cursor = selection.head();
14606            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14607            for symbol in symbols.iter().rev() {
14608                let start = symbol.range.start.to_offset(buffer_snap);
14609                let end = symbol.range.end.to_offset(buffer_snap);
14610                let new_range = start..end;
14611                if start < selection.start || end > selection.end {
14612                    return Some(Selection {
14613                        id: selection.id,
14614                        start: new_range.start,
14615                        end: new_range.end,
14616                        goal: SelectionGoal::None,
14617                        reversed: selection.reversed,
14618                    });
14619                }
14620            }
14621            None
14622        }
14623
14624        let mut selected_larger_symbol = false;
14625        let new_selections = old_selections
14626            .iter()
14627            .map(|selection| match update_selection(selection, &buffer) {
14628                Some(new_selection) => {
14629                    if new_selection.range() != selection.range() {
14630                        selected_larger_symbol = true;
14631                    }
14632                    new_selection
14633                }
14634                None => selection.clone(),
14635            })
14636            .collect::<Vec<_>>();
14637
14638        if selected_larger_symbol {
14639            self.change_selections(Default::default(), window, cx, |s| {
14640                s.select(new_selections);
14641            });
14642        }
14643    }
14644
14645    pub fn select_larger_syntax_node(
14646        &mut self,
14647        _: &SelectLargerSyntaxNode,
14648        window: &mut Window,
14649        cx: &mut Context<Self>,
14650    ) {
14651        let Some(visible_row_count) = self.visible_row_count() else {
14652            return;
14653        };
14654        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14655        if old_selections.is_empty() {
14656            return;
14657        }
14658
14659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14660
14661        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14662        let buffer = self.buffer.read(cx).snapshot(cx);
14663
14664        let mut selected_larger_node = false;
14665        let mut new_selections = old_selections
14666            .iter()
14667            .map(|selection| {
14668                let old_range = selection.start..selection.end;
14669
14670                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14671                    // manually select word at selection
14672                    if ["string_content", "inline"].contains(&node.kind()) {
14673                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14674                        // ignore if word is already selected
14675                        if !word_range.is_empty() && old_range != word_range {
14676                            let (last_word_range, _) =
14677                                buffer.surrounding_word(old_range.end, false);
14678                            // only select word if start and end point belongs to same word
14679                            if word_range == last_word_range {
14680                                selected_larger_node = true;
14681                                return Selection {
14682                                    id: selection.id,
14683                                    start: word_range.start,
14684                                    end: word_range.end,
14685                                    goal: SelectionGoal::None,
14686                                    reversed: selection.reversed,
14687                                };
14688                            }
14689                        }
14690                    }
14691                }
14692
14693                let mut new_range = old_range.clone();
14694                while let Some((_node, containing_range)) =
14695                    buffer.syntax_ancestor(new_range.clone())
14696                {
14697                    new_range = match containing_range {
14698                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14699                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14700                    };
14701                    if !display_map.intersects_fold(new_range.start)
14702                        && !display_map.intersects_fold(new_range.end)
14703                    {
14704                        break;
14705                    }
14706                }
14707
14708                selected_larger_node |= new_range != old_range;
14709                Selection {
14710                    id: selection.id,
14711                    start: new_range.start,
14712                    end: new_range.end,
14713                    goal: SelectionGoal::None,
14714                    reversed: selection.reversed,
14715                }
14716            })
14717            .collect::<Vec<_>>();
14718
14719        if !selected_larger_node {
14720            return; // don't put this call in the history
14721        }
14722
14723        // scroll based on transformation done to the last selection created by the user
14724        let (last_old, last_new) = old_selections
14725            .last()
14726            .zip(new_selections.last().cloned())
14727            .expect("old_selections isn't empty");
14728
14729        // revert selection
14730        let is_selection_reversed = {
14731            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14732            new_selections.last_mut().expect("checked above").reversed =
14733                should_newest_selection_be_reversed;
14734            should_newest_selection_be_reversed
14735        };
14736
14737        if selected_larger_node {
14738            self.select_syntax_node_history.disable_clearing = true;
14739            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14740                s.select(new_selections.clone());
14741            });
14742            self.select_syntax_node_history.disable_clearing = false;
14743        }
14744
14745        let start_row = last_new.start.to_display_point(&display_map).row().0;
14746        let end_row = last_new.end.to_display_point(&display_map).row().0;
14747        let selection_height = end_row - start_row + 1;
14748        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14749
14750        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14751        let scroll_behavior = if fits_on_the_screen {
14752            self.request_autoscroll(Autoscroll::fit(), cx);
14753            SelectSyntaxNodeScrollBehavior::FitSelection
14754        } else if is_selection_reversed {
14755            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14756            SelectSyntaxNodeScrollBehavior::CursorTop
14757        } else {
14758            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14759            SelectSyntaxNodeScrollBehavior::CursorBottom
14760        };
14761
14762        self.select_syntax_node_history.push((
14763            old_selections,
14764            scroll_behavior,
14765            is_selection_reversed,
14766        ));
14767    }
14768
14769    pub fn select_smaller_syntax_node(
14770        &mut self,
14771        _: &SelectSmallerSyntaxNode,
14772        window: &mut Window,
14773        cx: &mut Context<Self>,
14774    ) {
14775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14776
14777        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14778            self.select_syntax_node_history.pop()
14779        {
14780            if let Some(selection) = selections.last_mut() {
14781                selection.reversed = is_selection_reversed;
14782            }
14783
14784            self.select_syntax_node_history.disable_clearing = true;
14785            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14786                s.select(selections.to_vec());
14787            });
14788            self.select_syntax_node_history.disable_clearing = false;
14789
14790            match scroll_behavior {
14791                SelectSyntaxNodeScrollBehavior::CursorTop => {
14792                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14793                }
14794                SelectSyntaxNodeScrollBehavior::FitSelection => {
14795                    self.request_autoscroll(Autoscroll::fit(), cx);
14796                }
14797                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14798                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14799                }
14800            }
14801        }
14802    }
14803
14804    pub fn unwrap_syntax_node(
14805        &mut self,
14806        _: &UnwrapSyntaxNode,
14807        window: &mut Window,
14808        cx: &mut Context<Self>,
14809    ) {
14810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14811
14812        let buffer = self.buffer.read(cx).snapshot(cx);
14813        let selections = self
14814            .selections
14815            .all::<usize>(cx)
14816            .into_iter()
14817            // subtracting the offset requires sorting
14818            .sorted_by_key(|i| i.start);
14819
14820        let full_edits = selections
14821            .into_iter()
14822            .filter_map(|selection| {
14823                // Only requires two branches once if-let-chains stabilize (#53667)
14824                let child = if !selection.is_empty() {
14825                    selection.range()
14826                } else if let Some((_, ancestor_range)) =
14827                    buffer.syntax_ancestor(selection.start..selection.end)
14828                {
14829                    match ancestor_range {
14830                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14831                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14832                    }
14833                } else {
14834                    selection.range()
14835                };
14836
14837                let mut parent = child.clone();
14838                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14839                    parent = match ancestor_range {
14840                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14841                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14842                    };
14843                    if parent.start < child.start || parent.end > child.end {
14844                        break;
14845                    }
14846                }
14847
14848                if parent == child {
14849                    return None;
14850                }
14851                let text = buffer.text_for_range(child).collect::<String>();
14852                Some((selection.id, parent, text))
14853            })
14854            .collect::<Vec<_>>();
14855
14856        self.transact(window, cx, |this, window, cx| {
14857            this.buffer.update(cx, |buffer, cx| {
14858                buffer.edit(
14859                    full_edits
14860                        .iter()
14861                        .map(|(_, p, t)| (p.clone(), t.clone()))
14862                        .collect::<Vec<_>>(),
14863                    None,
14864                    cx,
14865                );
14866            });
14867            this.change_selections(Default::default(), window, cx, |s| {
14868                let mut offset = 0;
14869                let mut selections = vec![];
14870                for (id, parent, text) in full_edits {
14871                    let start = parent.start - offset;
14872                    offset += parent.len() - text.len();
14873                    selections.push(Selection {
14874                        id,
14875                        start,
14876                        end: start + text.len(),
14877                        reversed: false,
14878                        goal: Default::default(),
14879                    });
14880                }
14881                s.select(selections);
14882            });
14883        });
14884    }
14885
14886    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14887        if !EditorSettings::get_global(cx).gutter.runnables {
14888            self.clear_tasks();
14889            return Task::ready(());
14890        }
14891        let project = self.project().map(Entity::downgrade);
14892        let task_sources = self.lsp_task_sources(cx);
14893        let multi_buffer = self.buffer.downgrade();
14894        cx.spawn_in(window, async move |editor, cx| {
14895            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14896            let Some(project) = project.and_then(|p| p.upgrade()) else {
14897                return;
14898            };
14899            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14900                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14901            }) else {
14902                return;
14903            };
14904
14905            let hide_runnables = project
14906                .update(cx, |project, _| project.is_via_collab())
14907                .unwrap_or(true);
14908            if hide_runnables {
14909                return;
14910            }
14911            let new_rows =
14912                cx.background_spawn({
14913                    let snapshot = display_snapshot.clone();
14914                    async move {
14915                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14916                    }
14917                })
14918                    .await;
14919            let Ok(lsp_tasks) =
14920                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14921            else {
14922                return;
14923            };
14924            let lsp_tasks = lsp_tasks.await;
14925
14926            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14927                lsp_tasks
14928                    .into_iter()
14929                    .flat_map(|(kind, tasks)| {
14930                        tasks.into_iter().filter_map(move |(location, task)| {
14931                            Some((kind.clone(), location?, task))
14932                        })
14933                    })
14934                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14935                        let buffer = location.target.buffer;
14936                        let buffer_snapshot = buffer.read(cx).snapshot();
14937                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14938                            |(excerpt_id, snapshot, _)| {
14939                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14940                                    display_snapshot
14941                                        .buffer_snapshot
14942                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14943                                } else {
14944                                    None
14945                                }
14946                            },
14947                        );
14948                        if let Some(offset) = offset {
14949                            let task_buffer_range =
14950                                location.target.range.to_point(&buffer_snapshot);
14951                            let context_buffer_range =
14952                                task_buffer_range.to_offset(&buffer_snapshot);
14953                            let context_range = BufferOffset(context_buffer_range.start)
14954                                ..BufferOffset(context_buffer_range.end);
14955
14956                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14957                                .or_insert_with(|| RunnableTasks {
14958                                    templates: Vec::new(),
14959                                    offset,
14960                                    column: task_buffer_range.start.column,
14961                                    extra_variables: HashMap::default(),
14962                                    context_range,
14963                                })
14964                                .templates
14965                                .push((kind, task.original_task().clone()));
14966                        }
14967
14968                        acc
14969                    })
14970            }) else {
14971                return;
14972            };
14973
14974            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14975                buffer.language_settings(cx).tasks.prefer_lsp
14976            }) else {
14977                return;
14978            };
14979
14980            let rows = Self::runnable_rows(
14981                project,
14982                display_snapshot,
14983                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14984                new_rows,
14985                cx.clone(),
14986            )
14987            .await;
14988            editor
14989                .update(cx, |editor, _| {
14990                    editor.clear_tasks();
14991                    for (key, mut value) in rows {
14992                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14993                            value.templates.extend(lsp_tasks.templates);
14994                        }
14995
14996                        editor.insert_tasks(key, value);
14997                    }
14998                    for (key, value) in lsp_tasks_by_rows {
14999                        editor.insert_tasks(key, value);
15000                    }
15001                })
15002                .ok();
15003        })
15004    }
15005    fn fetch_runnable_ranges(
15006        snapshot: &DisplaySnapshot,
15007        range: Range<Anchor>,
15008    ) -> Vec<language::RunnableRange> {
15009        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15010    }
15011
15012    fn runnable_rows(
15013        project: Entity<Project>,
15014        snapshot: DisplaySnapshot,
15015        prefer_lsp: bool,
15016        runnable_ranges: Vec<RunnableRange>,
15017        cx: AsyncWindowContext,
15018    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15019        cx.spawn(async move |cx| {
15020            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15021            for mut runnable in runnable_ranges {
15022                let Some(tasks) = cx
15023                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15024                    .ok()
15025                else {
15026                    continue;
15027                };
15028                let mut tasks = tasks.await;
15029
15030                if prefer_lsp {
15031                    tasks.retain(|(task_kind, _)| {
15032                        !matches!(task_kind, TaskSourceKind::Language { .. })
15033                    });
15034                }
15035                if tasks.is_empty() {
15036                    continue;
15037                }
15038
15039                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15040                let Some(row) = snapshot
15041                    .buffer_snapshot
15042                    .buffer_line_for_row(MultiBufferRow(point.row))
15043                    .map(|(_, range)| range.start.row)
15044                else {
15045                    continue;
15046                };
15047
15048                let context_range =
15049                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15050                runnable_rows.push((
15051                    (runnable.buffer_id, row),
15052                    RunnableTasks {
15053                        templates: tasks,
15054                        offset: snapshot
15055                            .buffer_snapshot
15056                            .anchor_before(runnable.run_range.start),
15057                        context_range,
15058                        column: point.column,
15059                        extra_variables: runnable.extra_captures,
15060                    },
15061                ));
15062            }
15063            runnable_rows
15064        })
15065    }
15066
15067    fn templates_with_tags(
15068        project: &Entity<Project>,
15069        runnable: &mut Runnable,
15070        cx: &mut App,
15071    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15072        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15073            let (worktree_id, file) = project
15074                .buffer_for_id(runnable.buffer, cx)
15075                .and_then(|buffer| buffer.read(cx).file())
15076                .map(|file| (file.worktree_id(cx), file.clone()))
15077                .unzip();
15078
15079            (
15080                project.task_store().read(cx).task_inventory().cloned(),
15081                worktree_id,
15082                file,
15083            )
15084        });
15085
15086        let tags = mem::take(&mut runnable.tags);
15087        let language = runnable.language.clone();
15088        cx.spawn(async move |cx| {
15089            let mut templates_with_tags = Vec::new();
15090            if let Some(inventory) = inventory {
15091                for RunnableTag(tag) in tags {
15092                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15093                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15094                    }) else {
15095                        return templates_with_tags;
15096                    };
15097                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15098                        move |(_, template)| {
15099                            template.tags.iter().any(|source_tag| source_tag == &tag)
15100                        },
15101                    ));
15102                }
15103            }
15104            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15105
15106            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15107                // Strongest source wins; if we have worktree tag binding, prefer that to
15108                // global and language bindings;
15109                // if we have a global binding, prefer that to language binding.
15110                let first_mismatch = templates_with_tags
15111                    .iter()
15112                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15113                if let Some(index) = first_mismatch {
15114                    templates_with_tags.truncate(index);
15115                }
15116            }
15117
15118            templates_with_tags
15119        })
15120    }
15121
15122    pub fn move_to_enclosing_bracket(
15123        &mut self,
15124        _: &MoveToEnclosingBracket,
15125        window: &mut Window,
15126        cx: &mut Context<Self>,
15127    ) {
15128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15129        self.change_selections(Default::default(), window, cx, |s| {
15130            s.move_offsets_with(|snapshot, selection| {
15131                let Some(enclosing_bracket_ranges) =
15132                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15133                else {
15134                    return;
15135                };
15136
15137                let mut best_length = usize::MAX;
15138                let mut best_inside = false;
15139                let mut best_in_bracket_range = false;
15140                let mut best_destination = None;
15141                for (open, close) in enclosing_bracket_ranges {
15142                    let close = close.to_inclusive();
15143                    let length = close.end() - open.start;
15144                    let inside = selection.start >= open.end && selection.end <= *close.start();
15145                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15146                        || close.contains(&selection.head());
15147
15148                    // If best is next to a bracket and current isn't, skip
15149                    if !in_bracket_range && best_in_bracket_range {
15150                        continue;
15151                    }
15152
15153                    // Prefer smaller lengths unless best is inside and current isn't
15154                    if length > best_length && (best_inside || !inside) {
15155                        continue;
15156                    }
15157
15158                    best_length = length;
15159                    best_inside = inside;
15160                    best_in_bracket_range = in_bracket_range;
15161                    best_destination = Some(
15162                        if close.contains(&selection.start) && close.contains(&selection.end) {
15163                            if inside { open.end } else { open.start }
15164                        } else if inside {
15165                            *close.start()
15166                        } else {
15167                            *close.end()
15168                        },
15169                    );
15170                }
15171
15172                if let Some(destination) = best_destination {
15173                    selection.collapse_to(destination, SelectionGoal::None);
15174                }
15175            })
15176        });
15177    }
15178
15179    pub fn undo_selection(
15180        &mut self,
15181        _: &UndoSelection,
15182        window: &mut Window,
15183        cx: &mut Context<Self>,
15184    ) {
15185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15186        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15187            self.selection_history.mode = SelectionHistoryMode::Undoing;
15188            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15189                this.end_selection(window, cx);
15190                this.change_selections(
15191                    SelectionEffects::scroll(Autoscroll::newest()),
15192                    window,
15193                    cx,
15194                    |s| s.select_anchors(entry.selections.to_vec()),
15195                );
15196            });
15197            self.selection_history.mode = SelectionHistoryMode::Normal;
15198
15199            self.select_next_state = entry.select_next_state;
15200            self.select_prev_state = entry.select_prev_state;
15201            self.add_selections_state = entry.add_selections_state;
15202        }
15203    }
15204
15205    pub fn redo_selection(
15206        &mut self,
15207        _: &RedoSelection,
15208        window: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15212        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15213            self.selection_history.mode = SelectionHistoryMode::Redoing;
15214            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15215                this.end_selection(window, cx);
15216                this.change_selections(
15217                    SelectionEffects::scroll(Autoscroll::newest()),
15218                    window,
15219                    cx,
15220                    |s| s.select_anchors(entry.selections.to_vec()),
15221                );
15222            });
15223            self.selection_history.mode = SelectionHistoryMode::Normal;
15224
15225            self.select_next_state = entry.select_next_state;
15226            self.select_prev_state = entry.select_prev_state;
15227            self.add_selections_state = entry.add_selections_state;
15228        }
15229    }
15230
15231    pub fn expand_excerpts(
15232        &mut self,
15233        action: &ExpandExcerpts,
15234        _: &mut Window,
15235        cx: &mut Context<Self>,
15236    ) {
15237        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15238    }
15239
15240    pub fn expand_excerpts_down(
15241        &mut self,
15242        action: &ExpandExcerptsDown,
15243        _: &mut Window,
15244        cx: &mut Context<Self>,
15245    ) {
15246        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15247    }
15248
15249    pub fn expand_excerpts_up(
15250        &mut self,
15251        action: &ExpandExcerptsUp,
15252        _: &mut Window,
15253        cx: &mut Context<Self>,
15254    ) {
15255        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15256    }
15257
15258    pub fn expand_excerpts_for_direction(
15259        &mut self,
15260        lines: u32,
15261        direction: ExpandExcerptDirection,
15262
15263        cx: &mut Context<Self>,
15264    ) {
15265        let selections = self.selections.disjoint_anchors();
15266
15267        let lines = if lines == 0 {
15268            EditorSettings::get_global(cx).expand_excerpt_lines
15269        } else {
15270            lines
15271        };
15272
15273        self.buffer.update(cx, |buffer, cx| {
15274            let snapshot = buffer.snapshot(cx);
15275            let mut excerpt_ids = selections
15276                .iter()
15277                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15278                .collect::<Vec<_>>();
15279            excerpt_ids.sort();
15280            excerpt_ids.dedup();
15281            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15282        })
15283    }
15284
15285    pub fn expand_excerpt(
15286        &mut self,
15287        excerpt: ExcerptId,
15288        direction: ExpandExcerptDirection,
15289        window: &mut Window,
15290        cx: &mut Context<Self>,
15291    ) {
15292        let current_scroll_position = self.scroll_position(cx);
15293        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15294        let mut should_scroll_up = false;
15295
15296        if direction == ExpandExcerptDirection::Down {
15297            let multi_buffer = self.buffer.read(cx);
15298            let snapshot = multi_buffer.snapshot(cx);
15299            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15300                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15301                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15302            {
15303                let buffer_snapshot = buffer.read(cx).snapshot();
15304                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15305                let last_row = buffer_snapshot.max_point().row;
15306                let lines_below = last_row.saturating_sub(excerpt_end_row);
15307                should_scroll_up = lines_below >= lines_to_expand;
15308            }
15309        }
15310
15311        self.buffer.update(cx, |buffer, cx| {
15312            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15313        });
15314
15315        if should_scroll_up {
15316            let new_scroll_position =
15317                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15318            self.set_scroll_position(new_scroll_position, window, cx);
15319        }
15320    }
15321
15322    pub fn go_to_singleton_buffer_point(
15323        &mut self,
15324        point: Point,
15325        window: &mut Window,
15326        cx: &mut Context<Self>,
15327    ) {
15328        self.go_to_singleton_buffer_range(point..point, window, cx);
15329    }
15330
15331    pub fn go_to_singleton_buffer_range(
15332        &mut self,
15333        range: Range<Point>,
15334        window: &mut Window,
15335        cx: &mut Context<Self>,
15336    ) {
15337        let multibuffer = self.buffer().read(cx);
15338        let Some(buffer) = multibuffer.as_singleton() else {
15339            return;
15340        };
15341        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15342            return;
15343        };
15344        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15345            return;
15346        };
15347        self.change_selections(
15348            SelectionEffects::default().nav_history(true),
15349            window,
15350            cx,
15351            |s| s.select_anchor_ranges([start..end]),
15352        );
15353    }
15354
15355    pub fn go_to_diagnostic(
15356        &mut self,
15357        action: &GoToDiagnostic,
15358        window: &mut Window,
15359        cx: &mut Context<Self>,
15360    ) {
15361        if !self.diagnostics_enabled() {
15362            return;
15363        }
15364        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15365        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15366    }
15367
15368    pub fn go_to_prev_diagnostic(
15369        &mut self,
15370        action: &GoToPreviousDiagnostic,
15371        window: &mut Window,
15372        cx: &mut Context<Self>,
15373    ) {
15374        if !self.diagnostics_enabled() {
15375            return;
15376        }
15377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15378        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15379    }
15380
15381    pub fn go_to_diagnostic_impl(
15382        &mut self,
15383        direction: Direction,
15384        severity: GoToDiagnosticSeverityFilter,
15385        window: &mut Window,
15386        cx: &mut Context<Self>,
15387    ) {
15388        let buffer = self.buffer.read(cx).snapshot(cx);
15389        let selection = self.selections.newest::<usize>(cx);
15390
15391        let mut active_group_id = None;
15392        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15393            && active_group.active_range.start.to_offset(&buffer) == selection.start
15394        {
15395            active_group_id = Some(active_group.group_id);
15396        }
15397
15398        fn filtered(
15399            snapshot: EditorSnapshot,
15400            severity: GoToDiagnosticSeverityFilter,
15401            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15402        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15403            diagnostics
15404                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15405                .filter(|entry| entry.range.start != entry.range.end)
15406                .filter(|entry| !entry.diagnostic.is_unnecessary)
15407                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15408        }
15409
15410        let snapshot = self.snapshot(window, cx);
15411        let before = filtered(
15412            snapshot.clone(),
15413            severity,
15414            buffer
15415                .diagnostics_in_range(0..selection.start)
15416                .filter(|entry| entry.range.start <= selection.start),
15417        );
15418        let after = filtered(
15419            snapshot,
15420            severity,
15421            buffer
15422                .diagnostics_in_range(selection.start..buffer.len())
15423                .filter(|entry| entry.range.start >= selection.start),
15424        );
15425
15426        let mut found: Option<DiagnosticEntry<usize>> = None;
15427        if direction == Direction::Prev {
15428            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15429            {
15430                for diagnostic in prev_diagnostics.into_iter().rev() {
15431                    if diagnostic.range.start != selection.start
15432                        || active_group_id
15433                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15434                    {
15435                        found = Some(diagnostic);
15436                        break 'outer;
15437                    }
15438                }
15439            }
15440        } else {
15441            for diagnostic in after.chain(before) {
15442                if diagnostic.range.start != selection.start
15443                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15444                {
15445                    found = Some(diagnostic);
15446                    break;
15447                }
15448            }
15449        }
15450        let Some(next_diagnostic) = found else {
15451            return;
15452        };
15453
15454        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15455        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15456            return;
15457        };
15458        self.change_selections(Default::default(), window, cx, |s| {
15459            s.select_ranges(vec![
15460                next_diagnostic.range.start..next_diagnostic.range.start,
15461            ])
15462        });
15463        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15464        self.refresh_edit_prediction(false, true, window, cx);
15465    }
15466
15467    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15469        let snapshot = self.snapshot(window, cx);
15470        let selection = self.selections.newest::<Point>(cx);
15471        self.go_to_hunk_before_or_after_position(
15472            &snapshot,
15473            selection.head(),
15474            Direction::Next,
15475            window,
15476            cx,
15477        );
15478    }
15479
15480    pub fn go_to_hunk_before_or_after_position(
15481        &mut self,
15482        snapshot: &EditorSnapshot,
15483        position: Point,
15484        direction: Direction,
15485        window: &mut Window,
15486        cx: &mut Context<Editor>,
15487    ) {
15488        let row = if direction == Direction::Next {
15489            self.hunk_after_position(snapshot, position)
15490                .map(|hunk| hunk.row_range.start)
15491        } else {
15492            self.hunk_before_position(snapshot, position)
15493        };
15494
15495        if let Some(row) = row {
15496            let destination = Point::new(row.0, 0);
15497            let autoscroll = Autoscroll::center();
15498
15499            self.unfold_ranges(&[destination..destination], false, false, cx);
15500            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15501                s.select_ranges([destination..destination]);
15502            });
15503        }
15504    }
15505
15506    fn hunk_after_position(
15507        &mut self,
15508        snapshot: &EditorSnapshot,
15509        position: Point,
15510    ) -> Option<MultiBufferDiffHunk> {
15511        snapshot
15512            .buffer_snapshot
15513            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15514            .find(|hunk| hunk.row_range.start.0 > position.row)
15515            .or_else(|| {
15516                snapshot
15517                    .buffer_snapshot
15518                    .diff_hunks_in_range(Point::zero()..position)
15519                    .find(|hunk| hunk.row_range.end.0 < position.row)
15520            })
15521    }
15522
15523    fn go_to_prev_hunk(
15524        &mut self,
15525        _: &GoToPreviousHunk,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) {
15529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15530        let snapshot = self.snapshot(window, cx);
15531        let selection = self.selections.newest::<Point>(cx);
15532        self.go_to_hunk_before_or_after_position(
15533            &snapshot,
15534            selection.head(),
15535            Direction::Prev,
15536            window,
15537            cx,
15538        );
15539    }
15540
15541    fn hunk_before_position(
15542        &mut self,
15543        snapshot: &EditorSnapshot,
15544        position: Point,
15545    ) -> Option<MultiBufferRow> {
15546        snapshot
15547            .buffer_snapshot
15548            .diff_hunk_before(position)
15549            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15550    }
15551
15552    fn go_to_next_change(
15553        &mut self,
15554        _: &GoToNextChange,
15555        window: &mut Window,
15556        cx: &mut Context<Self>,
15557    ) {
15558        if let Some(selections) = self
15559            .change_list
15560            .next_change(1, Direction::Next)
15561            .map(|s| s.to_vec())
15562        {
15563            self.change_selections(Default::default(), window, cx, |s| {
15564                let map = s.display_map();
15565                s.select_display_ranges(selections.iter().map(|a| {
15566                    let point = a.to_display_point(&map);
15567                    point..point
15568                }))
15569            })
15570        }
15571    }
15572
15573    fn go_to_previous_change(
15574        &mut self,
15575        _: &GoToPreviousChange,
15576        window: &mut Window,
15577        cx: &mut Context<Self>,
15578    ) {
15579        if let Some(selections) = self
15580            .change_list
15581            .next_change(1, Direction::Prev)
15582            .map(|s| s.to_vec())
15583        {
15584            self.change_selections(Default::default(), window, cx, |s| {
15585                let map = s.display_map();
15586                s.select_display_ranges(selections.iter().map(|a| {
15587                    let point = a.to_display_point(&map);
15588                    point..point
15589                }))
15590            })
15591        }
15592    }
15593
15594    fn go_to_line<T: 'static>(
15595        &mut self,
15596        position: Anchor,
15597        highlight_color: Option<Hsla>,
15598        window: &mut Window,
15599        cx: &mut Context<Self>,
15600    ) {
15601        let snapshot = self.snapshot(window, cx).display_snapshot;
15602        let position = position.to_point(&snapshot.buffer_snapshot);
15603        let start = snapshot
15604            .buffer_snapshot
15605            .clip_point(Point::new(position.row, 0), Bias::Left);
15606        let end = start + Point::new(1, 0);
15607        let start = snapshot.buffer_snapshot.anchor_before(start);
15608        let end = snapshot.buffer_snapshot.anchor_before(end);
15609
15610        self.highlight_rows::<T>(
15611            start..end,
15612            highlight_color
15613                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15614            Default::default(),
15615            cx,
15616        );
15617
15618        if self.buffer.read(cx).is_singleton() {
15619            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15620        }
15621    }
15622
15623    pub fn go_to_definition(
15624        &mut self,
15625        _: &GoToDefinition,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) -> Task<Result<Navigated>> {
15629        let definition =
15630            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15631        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15632        cx.spawn_in(window, async move |editor, cx| {
15633            if definition.await? == Navigated::Yes {
15634                return Ok(Navigated::Yes);
15635            }
15636            match fallback_strategy {
15637                GoToDefinitionFallback::None => Ok(Navigated::No),
15638                GoToDefinitionFallback::FindAllReferences => {
15639                    match editor.update_in(cx, |editor, window, cx| {
15640                        editor.find_all_references(&FindAllReferences, window, cx)
15641                    })? {
15642                        Some(references) => references.await,
15643                        None => Ok(Navigated::No),
15644                    }
15645                }
15646            }
15647        })
15648    }
15649
15650    pub fn go_to_declaration(
15651        &mut self,
15652        _: &GoToDeclaration,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) -> Task<Result<Navigated>> {
15656        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15657    }
15658
15659    pub fn go_to_declaration_split(
15660        &mut self,
15661        _: &GoToDeclaration,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) -> Task<Result<Navigated>> {
15665        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15666    }
15667
15668    pub fn go_to_implementation(
15669        &mut self,
15670        _: &GoToImplementation,
15671        window: &mut Window,
15672        cx: &mut Context<Self>,
15673    ) -> Task<Result<Navigated>> {
15674        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15675    }
15676
15677    pub fn go_to_implementation_split(
15678        &mut self,
15679        _: &GoToImplementationSplit,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) -> Task<Result<Navigated>> {
15683        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15684    }
15685
15686    pub fn go_to_type_definition(
15687        &mut self,
15688        _: &GoToTypeDefinition,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) -> Task<Result<Navigated>> {
15692        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15693    }
15694
15695    pub fn go_to_definition_split(
15696        &mut self,
15697        _: &GoToDefinitionSplit,
15698        window: &mut Window,
15699        cx: &mut Context<Self>,
15700    ) -> Task<Result<Navigated>> {
15701        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15702    }
15703
15704    pub fn go_to_type_definition_split(
15705        &mut self,
15706        _: &GoToTypeDefinitionSplit,
15707        window: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) -> Task<Result<Navigated>> {
15710        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15711    }
15712
15713    fn go_to_definition_of_kind(
15714        &mut self,
15715        kind: GotoDefinitionKind,
15716        split: bool,
15717        window: &mut Window,
15718        cx: &mut Context<Self>,
15719    ) -> Task<Result<Navigated>> {
15720        let Some(provider) = self.semantics_provider.clone() else {
15721            return Task::ready(Ok(Navigated::No));
15722        };
15723        let head = self.selections.newest::<usize>(cx).head();
15724        let buffer = self.buffer.read(cx);
15725        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15726            return Task::ready(Ok(Navigated::No));
15727        };
15728        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15729            return Task::ready(Ok(Navigated::No));
15730        };
15731
15732        cx.spawn_in(window, async move |editor, cx| {
15733            let Some(definitions) = definitions.await? else {
15734                return Ok(Navigated::No);
15735            };
15736            let navigated = editor
15737                .update_in(cx, |editor, window, cx| {
15738                    editor.navigate_to_hover_links(
15739                        Some(kind),
15740                        definitions
15741                            .into_iter()
15742                            .filter(|location| {
15743                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15744                            })
15745                            .map(HoverLink::Text)
15746                            .collect::<Vec<_>>(),
15747                        split,
15748                        window,
15749                        cx,
15750                    )
15751                })?
15752                .await?;
15753            anyhow::Ok(navigated)
15754        })
15755    }
15756
15757    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15758        let selection = self.selections.newest_anchor();
15759        let head = selection.head();
15760        let tail = selection.tail();
15761
15762        let Some((buffer, start_position)) =
15763            self.buffer.read(cx).text_anchor_for_position(head, cx)
15764        else {
15765            return;
15766        };
15767
15768        let end_position = if head != tail {
15769            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15770                return;
15771            };
15772            Some(pos)
15773        } else {
15774            None
15775        };
15776
15777        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15778            let url = if let Some(end_pos) = end_position {
15779                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15780            } else {
15781                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15782            };
15783
15784            if let Some(url) = url {
15785                editor.update(cx, |_, cx| {
15786                    cx.open_url(&url);
15787                })
15788            } else {
15789                Ok(())
15790            }
15791        });
15792
15793        url_finder.detach();
15794    }
15795
15796    pub fn open_selected_filename(
15797        &mut self,
15798        _: &OpenSelectedFilename,
15799        window: &mut Window,
15800        cx: &mut Context<Self>,
15801    ) {
15802        let Some(workspace) = self.workspace() else {
15803            return;
15804        };
15805
15806        let position = self.selections.newest_anchor().head();
15807
15808        let Some((buffer, buffer_position)) =
15809            self.buffer.read(cx).text_anchor_for_position(position, cx)
15810        else {
15811            return;
15812        };
15813
15814        let project = self.project.clone();
15815
15816        cx.spawn_in(window, async move |_, cx| {
15817            let result = find_file(&buffer, project, buffer_position, cx).await;
15818
15819            if let Some((_, path)) = result {
15820                workspace
15821                    .update_in(cx, |workspace, window, cx| {
15822                        workspace.open_resolved_path(path, window, cx)
15823                    })?
15824                    .await?;
15825            }
15826            anyhow::Ok(())
15827        })
15828        .detach();
15829    }
15830
15831    pub(crate) fn navigate_to_hover_links(
15832        &mut self,
15833        kind: Option<GotoDefinitionKind>,
15834        definitions: Vec<HoverLink>,
15835        split: bool,
15836        window: &mut Window,
15837        cx: &mut Context<Editor>,
15838    ) -> Task<Result<Navigated>> {
15839        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15840        let mut first_url_or_file = None;
15841        let definitions: Vec<_> = definitions
15842            .into_iter()
15843            .filter_map(|def| match def {
15844                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15845                HoverLink::InlayHint(lsp_location, server_id) => {
15846                    let computation =
15847                        self.compute_target_location(lsp_location, server_id, window, cx);
15848                    Some(cx.background_spawn(computation))
15849                }
15850                HoverLink::Url(url) => {
15851                    first_url_or_file = Some(Either::Left(url));
15852                    None
15853                }
15854                HoverLink::File(path) => {
15855                    first_url_or_file = Some(Either::Right(path));
15856                    None
15857                }
15858            })
15859            .collect();
15860
15861        let workspace = self.workspace();
15862
15863        cx.spawn_in(window, async move |editor, acx| {
15864            let mut locations: Vec<Location> = future::join_all(definitions)
15865                .await
15866                .into_iter()
15867                .filter_map(|location| location.transpose())
15868                .collect::<Result<_>>()
15869                .context("location tasks")?;
15870
15871            if locations.len() > 1 {
15872                let Some(workspace) = workspace else {
15873                    return Ok(Navigated::No);
15874                };
15875
15876                let tab_kind = match kind {
15877                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15878                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15879                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15880                    Some(GotoDefinitionKind::Type) => "Types",
15881                };
15882                let title = editor
15883                    .update_in(acx, |_, _, cx| {
15884                        let target = locations
15885                            .iter()
15886                            .map(|location| {
15887                                location
15888                                    .buffer
15889                                    .read(cx)
15890                                    .text_for_range(location.range.clone())
15891                                    .collect::<String>()
15892                            })
15893                            .filter(|text| !text.contains('\n'))
15894                            .unique()
15895                            .take(3)
15896                            .join(", ");
15897                        if target.is_empty() {
15898                            tab_kind.to_owned()
15899                        } else {
15900                            format!("{tab_kind} for {target}")
15901                        }
15902                    })
15903                    .context("buffer title")?;
15904
15905                let opened = workspace
15906                    .update_in(acx, |workspace, window, cx| {
15907                        Self::open_locations_in_multibuffer(
15908                            workspace,
15909                            locations,
15910                            title,
15911                            split,
15912                            MultibufferSelectionMode::First,
15913                            window,
15914                            cx,
15915                        )
15916                    })
15917                    .is_ok();
15918
15919                anyhow::Ok(Navigated::from_bool(opened))
15920            } else if locations.is_empty() {
15921                // If there is one definition, just open it directly
15922                match first_url_or_file {
15923                    Some(Either::Left(url)) => {
15924                        acx.update(|_, cx| cx.open_url(&url))?;
15925                        Ok(Navigated::Yes)
15926                    }
15927                    Some(Either::Right(path)) => {
15928                        let Some(workspace) = workspace else {
15929                            return Ok(Navigated::No);
15930                        };
15931
15932                        workspace
15933                            .update_in(acx, |workspace, window, cx| {
15934                                workspace.open_resolved_path(path, window, cx)
15935                            })?
15936                            .await?;
15937                        Ok(Navigated::Yes)
15938                    }
15939                    None => Ok(Navigated::No),
15940                }
15941            } else {
15942                let Some(workspace) = workspace else {
15943                    return Ok(Navigated::No);
15944                };
15945
15946                let target = locations.pop().unwrap();
15947                editor.update_in(acx, |editor, window, cx| {
15948                    let pane = workspace.read(cx).active_pane().clone();
15949
15950                    let range = target.range.to_point(target.buffer.read(cx));
15951                    let range = editor.range_for_match(&range);
15952                    let range = collapse_multiline_range(range);
15953
15954                    if !split
15955                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15956                    {
15957                        editor.go_to_singleton_buffer_range(range, window, cx);
15958                    } else {
15959                        window.defer(cx, move |window, cx| {
15960                            let target_editor: Entity<Self> =
15961                                workspace.update(cx, |workspace, cx| {
15962                                    let pane = if split {
15963                                        workspace.adjacent_pane(window, cx)
15964                                    } else {
15965                                        workspace.active_pane().clone()
15966                                    };
15967
15968                                    workspace.open_project_item(
15969                                        pane,
15970                                        target.buffer.clone(),
15971                                        true,
15972                                        true,
15973                                        window,
15974                                        cx,
15975                                    )
15976                                });
15977                            target_editor.update(cx, |target_editor, cx| {
15978                                // When selecting a definition in a different buffer, disable the nav history
15979                                // to avoid creating a history entry at the previous cursor location.
15980                                pane.update(cx, |pane, _| pane.disable_history());
15981                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15982                                pane.update(cx, |pane, _| pane.enable_history());
15983                            });
15984                        });
15985                    }
15986                    Navigated::Yes
15987                })
15988            }
15989        })
15990    }
15991
15992    fn compute_target_location(
15993        &self,
15994        lsp_location: lsp::Location,
15995        server_id: LanguageServerId,
15996        window: &mut Window,
15997        cx: &mut Context<Self>,
15998    ) -> Task<anyhow::Result<Option<Location>>> {
15999        let Some(project) = self.project.clone() else {
16000            return Task::ready(Ok(None));
16001        };
16002
16003        cx.spawn_in(window, async move |editor, cx| {
16004            let location_task = editor.update(cx, |_, cx| {
16005                project.update(cx, |project, cx| {
16006                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16007                })
16008            })?;
16009            let location = Some({
16010                let target_buffer_handle = location_task.await.context("open local buffer")?;
16011                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16012                    let target_start = target_buffer
16013                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16014                    let target_end = target_buffer
16015                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16016                    target_buffer.anchor_after(target_start)
16017                        ..target_buffer.anchor_before(target_end)
16018                })?;
16019                Location {
16020                    buffer: target_buffer_handle,
16021                    range,
16022                }
16023            });
16024            Ok(location)
16025        })
16026    }
16027
16028    pub fn find_all_references(
16029        &mut self,
16030        _: &FindAllReferences,
16031        window: &mut Window,
16032        cx: &mut Context<Self>,
16033    ) -> Option<Task<Result<Navigated>>> {
16034        let selection = self.selections.newest::<usize>(cx);
16035        let multi_buffer = self.buffer.read(cx);
16036        let head = selection.head();
16037
16038        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16039        let head_anchor = multi_buffer_snapshot.anchor_at(
16040            head,
16041            if head < selection.tail() {
16042                Bias::Right
16043            } else {
16044                Bias::Left
16045            },
16046        );
16047
16048        match self
16049            .find_all_references_task_sources
16050            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16051        {
16052            Ok(_) => {
16053                log::info!(
16054                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16055                );
16056                return None;
16057            }
16058            Err(i) => {
16059                self.find_all_references_task_sources.insert(i, head_anchor);
16060            }
16061        }
16062
16063        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16064        let workspace = self.workspace()?;
16065        let project = workspace.read(cx).project().clone();
16066        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16067        Some(cx.spawn_in(window, async move |editor, cx| {
16068            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16069                if let Ok(i) = editor
16070                    .find_all_references_task_sources
16071                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16072                {
16073                    editor.find_all_references_task_sources.remove(i);
16074                }
16075            });
16076
16077            let Some(locations) = references.await? else {
16078                return anyhow::Ok(Navigated::No);
16079            };
16080            if locations.is_empty() {
16081                return anyhow::Ok(Navigated::No);
16082            }
16083
16084            workspace.update_in(cx, |workspace, window, cx| {
16085                let target = locations
16086                    .iter()
16087                    .map(|location| {
16088                        location
16089                            .buffer
16090                            .read(cx)
16091                            .text_for_range(location.range.clone())
16092                            .collect::<String>()
16093                    })
16094                    .filter(|text| !text.contains('\n'))
16095                    .unique()
16096                    .take(3)
16097                    .join(", ");
16098                let title = if target.is_empty() {
16099                    "References".to_owned()
16100                } else {
16101                    format!("References to {target}")
16102                };
16103                Self::open_locations_in_multibuffer(
16104                    workspace,
16105                    locations,
16106                    title,
16107                    false,
16108                    MultibufferSelectionMode::First,
16109                    window,
16110                    cx,
16111                );
16112                Navigated::Yes
16113            })
16114        }))
16115    }
16116
16117    /// Opens a multibuffer with the given project locations in it
16118    pub fn open_locations_in_multibuffer(
16119        workspace: &mut Workspace,
16120        mut locations: Vec<Location>,
16121        title: String,
16122        split: bool,
16123        multibuffer_selection_mode: MultibufferSelectionMode,
16124        window: &mut Window,
16125        cx: &mut Context<Workspace>,
16126    ) {
16127        if locations.is_empty() {
16128            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16129            return;
16130        }
16131
16132        // If there are multiple definitions, open them in a multibuffer
16133        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16134        let mut locations = locations.into_iter().peekable();
16135        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16136        let capability = workspace.project().read(cx).capability();
16137
16138        let excerpt_buffer = cx.new(|cx| {
16139            let mut multibuffer = MultiBuffer::new(capability);
16140            while let Some(location) = locations.next() {
16141                let buffer = location.buffer.read(cx);
16142                let mut ranges_for_buffer = Vec::new();
16143                let range = location.range.to_point(buffer);
16144                ranges_for_buffer.push(range.clone());
16145
16146                while let Some(next_location) = locations.peek() {
16147                    if next_location.buffer == location.buffer {
16148                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16149                        locations.next();
16150                    } else {
16151                        break;
16152                    }
16153                }
16154
16155                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16156                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16157                    PathKey::for_buffer(&location.buffer, cx),
16158                    location.buffer.clone(),
16159                    ranges_for_buffer,
16160                    DEFAULT_MULTIBUFFER_CONTEXT,
16161                    cx,
16162                );
16163                ranges.extend(new_ranges)
16164            }
16165
16166            multibuffer.with_title(title)
16167        });
16168
16169        let editor = cx.new(|cx| {
16170            Editor::for_multibuffer(
16171                excerpt_buffer,
16172                Some(workspace.project().clone()),
16173                window,
16174                cx,
16175            )
16176        });
16177        editor.update(cx, |editor, cx| {
16178            match multibuffer_selection_mode {
16179                MultibufferSelectionMode::First => {
16180                    if let Some(first_range) = ranges.first() {
16181                        editor.change_selections(
16182                            SelectionEffects::no_scroll(),
16183                            window,
16184                            cx,
16185                            |selections| {
16186                                selections.clear_disjoint();
16187                                selections
16188                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16189                            },
16190                        );
16191                    }
16192                    editor.highlight_background::<Self>(
16193                        &ranges,
16194                        |theme| theme.colors().editor_highlighted_line_background,
16195                        cx,
16196                    );
16197                }
16198                MultibufferSelectionMode::All => {
16199                    editor.change_selections(
16200                        SelectionEffects::no_scroll(),
16201                        window,
16202                        cx,
16203                        |selections| {
16204                            selections.clear_disjoint();
16205                            selections.select_anchor_ranges(ranges);
16206                        },
16207                    );
16208                }
16209            }
16210            editor.register_buffers_with_language_servers(cx);
16211        });
16212
16213        let item = Box::new(editor);
16214        let item_id = item.item_id();
16215
16216        if split {
16217            workspace.split_item(SplitDirection::Right, item, window, cx);
16218        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16219            let (preview_item_id, preview_item_idx) =
16220                workspace.active_pane().read_with(cx, |pane, _| {
16221                    (pane.preview_item_id(), pane.preview_item_idx())
16222                });
16223
16224            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16225
16226            if let Some(preview_item_id) = preview_item_id {
16227                workspace.active_pane().update(cx, |pane, cx| {
16228                    pane.remove_item(preview_item_id, false, false, window, cx);
16229                });
16230            }
16231        } else {
16232            workspace.add_item_to_active_pane(item, None, true, window, cx);
16233        }
16234        workspace.active_pane().update(cx, |pane, cx| {
16235            pane.set_preview_item_id(Some(item_id), cx);
16236        });
16237    }
16238
16239    pub fn rename(
16240        &mut self,
16241        _: &Rename,
16242        window: &mut Window,
16243        cx: &mut Context<Self>,
16244    ) -> Option<Task<Result<()>>> {
16245        use language::ToOffset as _;
16246
16247        let provider = self.semantics_provider.clone()?;
16248        let selection = self.selections.newest_anchor().clone();
16249        let (cursor_buffer, cursor_buffer_position) = self
16250            .buffer
16251            .read(cx)
16252            .text_anchor_for_position(selection.head(), cx)?;
16253        let (tail_buffer, cursor_buffer_position_end) = self
16254            .buffer
16255            .read(cx)
16256            .text_anchor_for_position(selection.tail(), cx)?;
16257        if tail_buffer != cursor_buffer {
16258            return None;
16259        }
16260
16261        let snapshot = cursor_buffer.read(cx).snapshot();
16262        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16263        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16264        let prepare_rename = provider
16265            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16266            .unwrap_or_else(|| Task::ready(Ok(None)));
16267        drop(snapshot);
16268
16269        Some(cx.spawn_in(window, async move |this, cx| {
16270            let rename_range = if let Some(range) = prepare_rename.await? {
16271                Some(range)
16272            } else {
16273                this.update(cx, |this, cx| {
16274                    let buffer = this.buffer.read(cx).snapshot(cx);
16275                    let mut buffer_highlights = this
16276                        .document_highlights_for_position(selection.head(), &buffer)
16277                        .filter(|highlight| {
16278                            highlight.start.excerpt_id == selection.head().excerpt_id
16279                                && highlight.end.excerpt_id == selection.head().excerpt_id
16280                        });
16281                    buffer_highlights
16282                        .next()
16283                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16284                })?
16285            };
16286            if let Some(rename_range) = rename_range {
16287                this.update_in(cx, |this, window, cx| {
16288                    let snapshot = cursor_buffer.read(cx).snapshot();
16289                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16290                    let cursor_offset_in_rename_range =
16291                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16292                    let cursor_offset_in_rename_range_end =
16293                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16294
16295                    this.take_rename(false, window, cx);
16296                    let buffer = this.buffer.read(cx).read(cx);
16297                    let cursor_offset = selection.head().to_offset(&buffer);
16298                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16299                    let rename_end = rename_start + rename_buffer_range.len();
16300                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16301                    let mut old_highlight_id = None;
16302                    let old_name: Arc<str> = buffer
16303                        .chunks(rename_start..rename_end, true)
16304                        .map(|chunk| {
16305                            if old_highlight_id.is_none() {
16306                                old_highlight_id = chunk.syntax_highlight_id;
16307                            }
16308                            chunk.text
16309                        })
16310                        .collect::<String>()
16311                        .into();
16312
16313                    drop(buffer);
16314
16315                    // Position the selection in the rename editor so that it matches the current selection.
16316                    this.show_local_selections = false;
16317                    let rename_editor = cx.new(|cx| {
16318                        let mut editor = Editor::single_line(window, cx);
16319                        editor.buffer.update(cx, |buffer, cx| {
16320                            buffer.edit([(0..0, old_name.clone())], None, cx)
16321                        });
16322                        let rename_selection_range = match cursor_offset_in_rename_range
16323                            .cmp(&cursor_offset_in_rename_range_end)
16324                        {
16325                            Ordering::Equal => {
16326                                editor.select_all(&SelectAll, window, cx);
16327                                return editor;
16328                            }
16329                            Ordering::Less => {
16330                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16331                            }
16332                            Ordering::Greater => {
16333                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16334                            }
16335                        };
16336                        if rename_selection_range.end > old_name.len() {
16337                            editor.select_all(&SelectAll, window, cx);
16338                        } else {
16339                            editor.change_selections(Default::default(), window, cx, |s| {
16340                                s.select_ranges([rename_selection_range]);
16341                            });
16342                        }
16343                        editor
16344                    });
16345                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16346                        if e == &EditorEvent::Focused {
16347                            cx.emit(EditorEvent::FocusedIn)
16348                        }
16349                    })
16350                    .detach();
16351
16352                    let write_highlights =
16353                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16354                    let read_highlights =
16355                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16356                    let ranges = write_highlights
16357                        .iter()
16358                        .flat_map(|(_, ranges)| ranges.iter())
16359                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16360                        .cloned()
16361                        .collect();
16362
16363                    this.highlight_text::<Rename>(
16364                        ranges,
16365                        HighlightStyle {
16366                            fade_out: Some(0.6),
16367                            ..Default::default()
16368                        },
16369                        cx,
16370                    );
16371                    let rename_focus_handle = rename_editor.focus_handle(cx);
16372                    window.focus(&rename_focus_handle);
16373                    let block_id = this.insert_blocks(
16374                        [BlockProperties {
16375                            style: BlockStyle::Flex,
16376                            placement: BlockPlacement::Below(range.start),
16377                            height: Some(1),
16378                            render: Arc::new({
16379                                let rename_editor = rename_editor.clone();
16380                                move |cx: &mut BlockContext| {
16381                                    let mut text_style = cx.editor_style.text.clone();
16382                                    if let Some(highlight_style) = old_highlight_id
16383                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16384                                    {
16385                                        text_style = text_style.highlight(highlight_style);
16386                                    }
16387                                    div()
16388                                        .block_mouse_except_scroll()
16389                                        .pl(cx.anchor_x)
16390                                        .child(EditorElement::new(
16391                                            &rename_editor,
16392                                            EditorStyle {
16393                                                background: cx.theme().system().transparent,
16394                                                local_player: cx.editor_style.local_player,
16395                                                text: text_style,
16396                                                scrollbar_width: cx.editor_style.scrollbar_width,
16397                                                syntax: cx.editor_style.syntax.clone(),
16398                                                status: cx.editor_style.status.clone(),
16399                                                inlay_hints_style: HighlightStyle {
16400                                                    font_weight: Some(FontWeight::BOLD),
16401                                                    ..make_inlay_hints_style(cx.app)
16402                                                },
16403                                                edit_prediction_styles: make_suggestion_styles(
16404                                                    cx.app,
16405                                                ),
16406                                                ..EditorStyle::default()
16407                                            },
16408                                        ))
16409                                        .into_any_element()
16410                                }
16411                            }),
16412                            priority: 0,
16413                        }],
16414                        Some(Autoscroll::fit()),
16415                        cx,
16416                    )[0];
16417                    this.pending_rename = Some(RenameState {
16418                        range,
16419                        old_name,
16420                        editor: rename_editor,
16421                        block_id,
16422                    });
16423                })?;
16424            }
16425
16426            Ok(())
16427        }))
16428    }
16429
16430    pub fn confirm_rename(
16431        &mut self,
16432        _: &ConfirmRename,
16433        window: &mut Window,
16434        cx: &mut Context<Self>,
16435    ) -> Option<Task<Result<()>>> {
16436        let rename = self.take_rename(false, window, cx)?;
16437        let workspace = self.workspace()?.downgrade();
16438        let (buffer, start) = self
16439            .buffer
16440            .read(cx)
16441            .text_anchor_for_position(rename.range.start, cx)?;
16442        let (end_buffer, _) = self
16443            .buffer
16444            .read(cx)
16445            .text_anchor_for_position(rename.range.end, cx)?;
16446        if buffer != end_buffer {
16447            return None;
16448        }
16449
16450        let old_name = rename.old_name;
16451        let new_name = rename.editor.read(cx).text(cx);
16452
16453        let rename = self.semantics_provider.as_ref()?.perform_rename(
16454            &buffer,
16455            start,
16456            new_name.clone(),
16457            cx,
16458        )?;
16459
16460        Some(cx.spawn_in(window, async move |editor, cx| {
16461            let project_transaction = rename.await?;
16462            Self::open_project_transaction(
16463                &editor,
16464                workspace,
16465                project_transaction,
16466                format!("Rename: {}{}", old_name, new_name),
16467                cx,
16468            )
16469            .await?;
16470
16471            editor.update(cx, |editor, cx| {
16472                editor.refresh_document_highlights(cx);
16473            })?;
16474            Ok(())
16475        }))
16476    }
16477
16478    fn take_rename(
16479        &mut self,
16480        moving_cursor: bool,
16481        window: &mut Window,
16482        cx: &mut Context<Self>,
16483    ) -> Option<RenameState> {
16484        let rename = self.pending_rename.take()?;
16485        if rename.editor.focus_handle(cx).is_focused(window) {
16486            window.focus(&self.focus_handle);
16487        }
16488
16489        self.remove_blocks(
16490            [rename.block_id].into_iter().collect(),
16491            Some(Autoscroll::fit()),
16492            cx,
16493        );
16494        self.clear_highlights::<Rename>(cx);
16495        self.show_local_selections = true;
16496
16497        if moving_cursor {
16498            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16499                editor.selections.newest::<usize>(cx).head()
16500            });
16501
16502            // Update the selection to match the position of the selection inside
16503            // the rename editor.
16504            let snapshot = self.buffer.read(cx).read(cx);
16505            let rename_range = rename.range.to_offset(&snapshot);
16506            let cursor_in_editor = snapshot
16507                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16508                .min(rename_range.end);
16509            drop(snapshot);
16510
16511            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16512                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16513            });
16514        } else {
16515            self.refresh_document_highlights(cx);
16516        }
16517
16518        Some(rename)
16519    }
16520
16521    pub fn pending_rename(&self) -> Option<&RenameState> {
16522        self.pending_rename.as_ref()
16523    }
16524
16525    fn format(
16526        &mut self,
16527        _: &Format,
16528        window: &mut Window,
16529        cx: &mut Context<Self>,
16530    ) -> Option<Task<Result<()>>> {
16531        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16532
16533        let project = match &self.project {
16534            Some(project) => project.clone(),
16535            None => return None,
16536        };
16537
16538        Some(self.perform_format(
16539            project,
16540            FormatTrigger::Manual,
16541            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16542            window,
16543            cx,
16544        ))
16545    }
16546
16547    fn format_selections(
16548        &mut self,
16549        _: &FormatSelections,
16550        window: &mut Window,
16551        cx: &mut Context<Self>,
16552    ) -> Option<Task<Result<()>>> {
16553        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16554
16555        let project = match &self.project {
16556            Some(project) => project.clone(),
16557            None => return None,
16558        };
16559
16560        let ranges = self
16561            .selections
16562            .all_adjusted(cx)
16563            .into_iter()
16564            .map(|selection| selection.range())
16565            .collect_vec();
16566
16567        Some(self.perform_format(
16568            project,
16569            FormatTrigger::Manual,
16570            FormatTarget::Ranges(ranges),
16571            window,
16572            cx,
16573        ))
16574    }
16575
16576    fn perform_format(
16577        &mut self,
16578        project: Entity<Project>,
16579        trigger: FormatTrigger,
16580        target: FormatTarget,
16581        window: &mut Window,
16582        cx: &mut Context<Self>,
16583    ) -> Task<Result<()>> {
16584        let buffer = self.buffer.clone();
16585        let (buffers, target) = match target {
16586            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16587            FormatTarget::Ranges(selection_ranges) => {
16588                let multi_buffer = buffer.read(cx);
16589                let snapshot = multi_buffer.read(cx);
16590                let mut buffers = HashSet::default();
16591                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16592                    BTreeMap::new();
16593                for selection_range in selection_ranges {
16594                    for (buffer, buffer_range, _) in
16595                        snapshot.range_to_buffer_ranges(selection_range)
16596                    {
16597                        let buffer_id = buffer.remote_id();
16598                        let start = buffer.anchor_before(buffer_range.start);
16599                        let end = buffer.anchor_after(buffer_range.end);
16600                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16601                        buffer_id_to_ranges
16602                            .entry(buffer_id)
16603                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16604                            .or_insert_with(|| vec![start..end]);
16605                    }
16606                }
16607                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16608            }
16609        };
16610
16611        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16612        let selections_prev = transaction_id_prev
16613            .and_then(|transaction_id_prev| {
16614                // default to selections as they were after the last edit, if we have them,
16615                // instead of how they are now.
16616                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16617                // will take you back to where you made the last edit, instead of staying where you scrolled
16618                self.selection_history
16619                    .transaction(transaction_id_prev)
16620                    .map(|t| t.0.clone())
16621            })
16622            .unwrap_or_else(|| self.selections.disjoint_anchors());
16623
16624        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16625        let format = project.update(cx, |project, cx| {
16626            project.format(buffers, target, true, trigger, cx)
16627        });
16628
16629        cx.spawn_in(window, async move |editor, cx| {
16630            let transaction = futures::select_biased! {
16631                transaction = format.log_err().fuse() => transaction,
16632                () = timeout => {
16633                    log::warn!("timed out waiting for formatting");
16634                    None
16635                }
16636            };
16637
16638            buffer
16639                .update(cx, |buffer, cx| {
16640                    if let Some(transaction) = transaction
16641                        && !buffer.is_singleton()
16642                    {
16643                        buffer.push_transaction(&transaction.0, cx);
16644                    }
16645                    cx.notify();
16646                })
16647                .ok();
16648
16649            if let Some(transaction_id_now) =
16650                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16651            {
16652                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16653                if has_new_transaction {
16654                    _ = editor.update(cx, |editor, _| {
16655                        editor
16656                            .selection_history
16657                            .insert_transaction(transaction_id_now, selections_prev);
16658                    });
16659                }
16660            }
16661
16662            Ok(())
16663        })
16664    }
16665
16666    fn organize_imports(
16667        &mut self,
16668        _: &OrganizeImports,
16669        window: &mut Window,
16670        cx: &mut Context<Self>,
16671    ) -> Option<Task<Result<()>>> {
16672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16673        let project = match &self.project {
16674            Some(project) => project.clone(),
16675            None => return None,
16676        };
16677        Some(self.perform_code_action_kind(
16678            project,
16679            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16680            window,
16681            cx,
16682        ))
16683    }
16684
16685    fn perform_code_action_kind(
16686        &mut self,
16687        project: Entity<Project>,
16688        kind: CodeActionKind,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) -> Task<Result<()>> {
16692        let buffer = self.buffer.clone();
16693        let buffers = buffer.read(cx).all_buffers();
16694        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16695        let apply_action = project.update(cx, |project, cx| {
16696            project.apply_code_action_kind(buffers, kind, true, cx)
16697        });
16698        cx.spawn_in(window, async move |_, cx| {
16699            let transaction = futures::select_biased! {
16700                () = timeout => {
16701                    log::warn!("timed out waiting for executing code action");
16702                    None
16703                }
16704                transaction = apply_action.log_err().fuse() => transaction,
16705            };
16706            buffer
16707                .update(cx, |buffer, cx| {
16708                    // check if we need this
16709                    if let Some(transaction) = transaction
16710                        && !buffer.is_singleton()
16711                    {
16712                        buffer.push_transaction(&transaction.0, cx);
16713                    }
16714                    cx.notify();
16715                })
16716                .ok();
16717            Ok(())
16718        })
16719    }
16720
16721    pub fn restart_language_server(
16722        &mut self,
16723        _: &RestartLanguageServer,
16724        _: &mut Window,
16725        cx: &mut Context<Self>,
16726    ) {
16727        if let Some(project) = self.project.clone() {
16728            self.buffer.update(cx, |multi_buffer, cx| {
16729                project.update(cx, |project, cx| {
16730                    project.restart_language_servers_for_buffers(
16731                        multi_buffer.all_buffers().into_iter().collect(),
16732                        HashSet::default(),
16733                        cx,
16734                    );
16735                });
16736            })
16737        }
16738    }
16739
16740    pub fn stop_language_server(
16741        &mut self,
16742        _: &StopLanguageServer,
16743        _: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) {
16746        if let Some(project) = self.project.clone() {
16747            self.buffer.update(cx, |multi_buffer, cx| {
16748                project.update(cx, |project, cx| {
16749                    project.stop_language_servers_for_buffers(
16750                        multi_buffer.all_buffers().into_iter().collect(),
16751                        HashSet::default(),
16752                        cx,
16753                    );
16754                    cx.emit(project::Event::RefreshInlayHints);
16755                });
16756            });
16757        }
16758    }
16759
16760    fn cancel_language_server_work(
16761        workspace: &mut Workspace,
16762        _: &actions::CancelLanguageServerWork,
16763        _: &mut Window,
16764        cx: &mut Context<Workspace>,
16765    ) {
16766        let project = workspace.project();
16767        let buffers = workspace
16768            .active_item(cx)
16769            .and_then(|item| item.act_as::<Editor>(cx))
16770            .map_or(HashSet::default(), |editor| {
16771                editor.read(cx).buffer.read(cx).all_buffers()
16772            });
16773        project.update(cx, |project, cx| {
16774            project.cancel_language_server_work_for_buffers(buffers, cx);
16775        });
16776    }
16777
16778    fn show_character_palette(
16779        &mut self,
16780        _: &ShowCharacterPalette,
16781        window: &mut Window,
16782        _: &mut Context<Self>,
16783    ) {
16784        window.show_character_palette();
16785    }
16786
16787    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16788        if !self.diagnostics_enabled() {
16789            return;
16790        }
16791
16792        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16793            let buffer = self.buffer.read(cx).snapshot(cx);
16794            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16795            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16796            let is_valid = buffer
16797                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16798                .any(|entry| {
16799                    entry.diagnostic.is_primary
16800                        && !entry.range.is_empty()
16801                        && entry.range.start == primary_range_start
16802                        && entry.diagnostic.message == active_diagnostics.active_message
16803                });
16804
16805            if !is_valid {
16806                self.dismiss_diagnostics(cx);
16807            }
16808        }
16809    }
16810
16811    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16812        match &self.active_diagnostics {
16813            ActiveDiagnostic::Group(group) => Some(group),
16814            _ => None,
16815        }
16816    }
16817
16818    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16819        if !self.diagnostics_enabled() {
16820            return;
16821        }
16822        self.dismiss_diagnostics(cx);
16823        self.active_diagnostics = ActiveDiagnostic::All;
16824    }
16825
16826    fn activate_diagnostics(
16827        &mut self,
16828        buffer_id: BufferId,
16829        diagnostic: DiagnosticEntry<usize>,
16830        window: &mut Window,
16831        cx: &mut Context<Self>,
16832    ) {
16833        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16834            return;
16835        }
16836        self.dismiss_diagnostics(cx);
16837        let snapshot = self.snapshot(window, cx);
16838        let buffer = self.buffer.read(cx).snapshot(cx);
16839        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16840            return;
16841        };
16842
16843        let diagnostic_group = buffer
16844            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16845            .collect::<Vec<_>>();
16846
16847        let blocks =
16848            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16849
16850        let blocks = self.display_map.update(cx, |display_map, cx| {
16851            display_map.insert_blocks(blocks, cx).into_iter().collect()
16852        });
16853        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16854            active_range: buffer.anchor_before(diagnostic.range.start)
16855                ..buffer.anchor_after(diagnostic.range.end),
16856            active_message: diagnostic.diagnostic.message.clone(),
16857            group_id: diagnostic.diagnostic.group_id,
16858            blocks,
16859        });
16860        cx.notify();
16861    }
16862
16863    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16864        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16865            return;
16866        };
16867
16868        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16869        if let ActiveDiagnostic::Group(group) = prev {
16870            self.display_map.update(cx, |display_map, cx| {
16871                display_map.remove_blocks(group.blocks, cx);
16872            });
16873            cx.notify();
16874        }
16875    }
16876
16877    /// Disable inline diagnostics rendering for this editor.
16878    pub fn disable_inline_diagnostics(&mut self) {
16879        self.inline_diagnostics_enabled = false;
16880        self.inline_diagnostics_update = Task::ready(());
16881        self.inline_diagnostics.clear();
16882    }
16883
16884    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16885        self.diagnostics_enabled = false;
16886        self.dismiss_diagnostics(cx);
16887        self.inline_diagnostics_update = Task::ready(());
16888        self.inline_diagnostics.clear();
16889    }
16890
16891    pub fn diagnostics_enabled(&self) -> bool {
16892        self.diagnostics_enabled && self.mode.is_full()
16893    }
16894
16895    pub fn inline_diagnostics_enabled(&self) -> bool {
16896        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16897    }
16898
16899    pub fn show_inline_diagnostics(&self) -> bool {
16900        self.show_inline_diagnostics
16901    }
16902
16903    pub fn toggle_inline_diagnostics(
16904        &mut self,
16905        _: &ToggleInlineDiagnostics,
16906        window: &mut Window,
16907        cx: &mut Context<Editor>,
16908    ) {
16909        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16910        self.refresh_inline_diagnostics(false, window, cx);
16911    }
16912
16913    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16914        self.diagnostics_max_severity = severity;
16915        self.display_map.update(cx, |display_map, _| {
16916            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16917        });
16918    }
16919
16920    pub fn toggle_diagnostics(
16921        &mut self,
16922        _: &ToggleDiagnostics,
16923        window: &mut Window,
16924        cx: &mut Context<Editor>,
16925    ) {
16926        if !self.diagnostics_enabled() {
16927            return;
16928        }
16929
16930        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16931            EditorSettings::get_global(cx)
16932                .diagnostics_max_severity
16933                .filter(|severity| severity != &DiagnosticSeverity::Off)
16934                .unwrap_or(DiagnosticSeverity::Hint)
16935        } else {
16936            DiagnosticSeverity::Off
16937        };
16938        self.set_max_diagnostics_severity(new_severity, cx);
16939        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16940            self.active_diagnostics = ActiveDiagnostic::None;
16941            self.inline_diagnostics_update = Task::ready(());
16942            self.inline_diagnostics.clear();
16943        } else {
16944            self.refresh_inline_diagnostics(false, window, cx);
16945        }
16946
16947        cx.notify();
16948    }
16949
16950    pub fn toggle_minimap(
16951        &mut self,
16952        _: &ToggleMinimap,
16953        window: &mut Window,
16954        cx: &mut Context<Editor>,
16955    ) {
16956        if self.supports_minimap(cx) {
16957            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16958        }
16959    }
16960
16961    fn refresh_inline_diagnostics(
16962        &mut self,
16963        debounce: bool,
16964        window: &mut Window,
16965        cx: &mut Context<Self>,
16966    ) {
16967        let max_severity = ProjectSettings::get_global(cx)
16968            .diagnostics
16969            .inline
16970            .max_severity
16971            .unwrap_or(self.diagnostics_max_severity);
16972
16973        if !self.inline_diagnostics_enabled()
16974            || !self.show_inline_diagnostics
16975            || max_severity == DiagnosticSeverity::Off
16976        {
16977            self.inline_diagnostics_update = Task::ready(());
16978            self.inline_diagnostics.clear();
16979            return;
16980        }
16981
16982        let debounce_ms = ProjectSettings::get_global(cx)
16983            .diagnostics
16984            .inline
16985            .update_debounce_ms;
16986        let debounce = if debounce && debounce_ms > 0 {
16987            Some(Duration::from_millis(debounce_ms))
16988        } else {
16989            None
16990        };
16991        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16992            if let Some(debounce) = debounce {
16993                cx.background_executor().timer(debounce).await;
16994            }
16995            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16996                editor
16997                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16998                    .ok()
16999            }) else {
17000                return;
17001            };
17002
17003            let new_inline_diagnostics = cx
17004                .background_spawn(async move {
17005                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17006                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17007                        let message = diagnostic_entry
17008                            .diagnostic
17009                            .message
17010                            .split_once('\n')
17011                            .map(|(line, _)| line)
17012                            .map(SharedString::new)
17013                            .unwrap_or_else(|| {
17014                                SharedString::from(diagnostic_entry.diagnostic.message)
17015                            });
17016                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17017                        let (Ok(i) | Err(i)) = inline_diagnostics
17018                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17019                        inline_diagnostics.insert(
17020                            i,
17021                            (
17022                                start_anchor,
17023                                InlineDiagnostic {
17024                                    message,
17025                                    group_id: diagnostic_entry.diagnostic.group_id,
17026                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17027                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17028                                    severity: diagnostic_entry.diagnostic.severity,
17029                                },
17030                            ),
17031                        );
17032                    }
17033                    inline_diagnostics
17034                })
17035                .await;
17036
17037            editor
17038                .update(cx, |editor, cx| {
17039                    editor.inline_diagnostics = new_inline_diagnostics;
17040                    cx.notify();
17041                })
17042                .ok();
17043        });
17044    }
17045
17046    fn pull_diagnostics(
17047        &mut self,
17048        buffer_id: Option<BufferId>,
17049        window: &Window,
17050        cx: &mut Context<Self>,
17051    ) -> Option<()> {
17052        if !self.mode().is_full() {
17053            return None;
17054        }
17055        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17056            .diagnostics
17057            .lsp_pull_diagnostics;
17058        if !pull_diagnostics_settings.enabled {
17059            return None;
17060        }
17061        let project = self.project()?.downgrade();
17062        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17063        let mut buffers = self.buffer.read(cx).all_buffers();
17064        if let Some(buffer_id) = buffer_id {
17065            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17066        }
17067
17068        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17069            cx.background_executor().timer(debounce).await;
17070
17071            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17072                buffers
17073                    .into_iter()
17074                    .filter_map(|buffer| {
17075                        project
17076                            .update(cx, |project, cx| {
17077                                project.lsp_store().update(cx, |lsp_store, cx| {
17078                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17079                                })
17080                            })
17081                            .ok()
17082                    })
17083                    .collect::<FuturesUnordered<_>>()
17084            }) else {
17085                return;
17086            };
17087
17088            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17089                match pull_task {
17090                    Ok(()) => {
17091                        if editor
17092                            .update_in(cx, |editor, window, cx| {
17093                                editor.update_diagnostics_state(window, cx);
17094                            })
17095                            .is_err()
17096                        {
17097                            return;
17098                        }
17099                    }
17100                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17101                }
17102            }
17103        });
17104
17105        Some(())
17106    }
17107
17108    pub fn set_selections_from_remote(
17109        &mut self,
17110        selections: Vec<Selection<Anchor>>,
17111        pending_selection: Option<Selection<Anchor>>,
17112        window: &mut Window,
17113        cx: &mut Context<Self>,
17114    ) {
17115        let old_cursor_position = self.selections.newest_anchor().head();
17116        self.selections.change_with(cx, |s| {
17117            s.select_anchors(selections);
17118            if let Some(pending_selection) = pending_selection {
17119                s.set_pending(pending_selection, SelectMode::Character);
17120            } else {
17121                s.clear_pending();
17122            }
17123        });
17124        self.selections_did_change(
17125            false,
17126            &old_cursor_position,
17127            SelectionEffects::default(),
17128            window,
17129            cx,
17130        );
17131    }
17132
17133    pub fn transact(
17134        &mut self,
17135        window: &mut Window,
17136        cx: &mut Context<Self>,
17137        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17138    ) -> Option<TransactionId> {
17139        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17140            this.start_transaction_at(Instant::now(), window, cx);
17141            update(this, window, cx);
17142            this.end_transaction_at(Instant::now(), cx)
17143        })
17144    }
17145
17146    pub fn start_transaction_at(
17147        &mut self,
17148        now: Instant,
17149        window: &mut Window,
17150        cx: &mut Context<Self>,
17151    ) -> Option<TransactionId> {
17152        self.end_selection(window, cx);
17153        if let Some(tx_id) = self
17154            .buffer
17155            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17156        {
17157            self.selection_history
17158                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17159            cx.emit(EditorEvent::TransactionBegun {
17160                transaction_id: tx_id,
17161            });
17162            Some(tx_id)
17163        } else {
17164            None
17165        }
17166    }
17167
17168    pub fn end_transaction_at(
17169        &mut self,
17170        now: Instant,
17171        cx: &mut Context<Self>,
17172    ) -> Option<TransactionId> {
17173        if let Some(transaction_id) = self
17174            .buffer
17175            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17176        {
17177            if let Some((_, end_selections)) =
17178                self.selection_history.transaction_mut(transaction_id)
17179            {
17180                *end_selections = Some(self.selections.disjoint_anchors());
17181            } else {
17182                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17183            }
17184
17185            cx.emit(EditorEvent::Edited { transaction_id });
17186            Some(transaction_id)
17187        } else {
17188            None
17189        }
17190    }
17191
17192    pub fn modify_transaction_selection_history(
17193        &mut self,
17194        transaction_id: TransactionId,
17195        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17196    ) -> bool {
17197        self.selection_history
17198            .transaction_mut(transaction_id)
17199            .map(modify)
17200            .is_some()
17201    }
17202
17203    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17204        if self.selection_mark_mode {
17205            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17206                s.move_with(|_, sel| {
17207                    sel.collapse_to(sel.head(), SelectionGoal::None);
17208                });
17209            })
17210        }
17211        self.selection_mark_mode = true;
17212        cx.notify();
17213    }
17214
17215    pub fn swap_selection_ends(
17216        &mut self,
17217        _: &actions::SwapSelectionEnds,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) {
17221        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17222            s.move_with(|_, sel| {
17223                if sel.start != sel.end {
17224                    sel.reversed = !sel.reversed
17225                }
17226            });
17227        });
17228        self.request_autoscroll(Autoscroll::newest(), cx);
17229        cx.notify();
17230    }
17231
17232    pub fn toggle_focus(
17233        workspace: &mut Workspace,
17234        _: &actions::ToggleFocus,
17235        window: &mut Window,
17236        cx: &mut Context<Workspace>,
17237    ) {
17238        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17239            return;
17240        };
17241        workspace.activate_item(&item, true, true, window, cx);
17242    }
17243
17244    pub fn toggle_fold(
17245        &mut self,
17246        _: &actions::ToggleFold,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) {
17250        if self.is_singleton(cx) {
17251            let selection = self.selections.newest::<Point>(cx);
17252
17253            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17254            let range = if selection.is_empty() {
17255                let point = selection.head().to_display_point(&display_map);
17256                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17257                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17258                    .to_point(&display_map);
17259                start..end
17260            } else {
17261                selection.range()
17262            };
17263            if display_map.folds_in_range(range).next().is_some() {
17264                self.unfold_lines(&Default::default(), window, cx)
17265            } else {
17266                self.fold(&Default::default(), window, cx)
17267            }
17268        } else {
17269            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17270            let buffer_ids: HashSet<_> = self
17271                .selections
17272                .disjoint_anchor_ranges()
17273                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17274                .collect();
17275
17276            let should_unfold = buffer_ids
17277                .iter()
17278                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17279
17280            for buffer_id in buffer_ids {
17281                if should_unfold {
17282                    self.unfold_buffer(buffer_id, cx);
17283                } else {
17284                    self.fold_buffer(buffer_id, cx);
17285                }
17286            }
17287        }
17288    }
17289
17290    pub fn toggle_fold_recursive(
17291        &mut self,
17292        _: &actions::ToggleFoldRecursive,
17293        window: &mut Window,
17294        cx: &mut Context<Self>,
17295    ) {
17296        let selection = self.selections.newest::<Point>(cx);
17297
17298        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17299        let range = if selection.is_empty() {
17300            let point = selection.head().to_display_point(&display_map);
17301            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17302            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17303                .to_point(&display_map);
17304            start..end
17305        } else {
17306            selection.range()
17307        };
17308        if display_map.folds_in_range(range).next().is_some() {
17309            self.unfold_recursive(&Default::default(), window, cx)
17310        } else {
17311            self.fold_recursive(&Default::default(), window, cx)
17312        }
17313    }
17314
17315    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17316        if self.is_singleton(cx) {
17317            let mut to_fold = Vec::new();
17318            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17319            let selections = self.selections.all_adjusted(cx);
17320
17321            for selection in selections {
17322                let range = selection.range().sorted();
17323                let buffer_start_row = range.start.row;
17324
17325                if range.start.row != range.end.row {
17326                    let mut found = false;
17327                    let mut row = range.start.row;
17328                    while row <= range.end.row {
17329                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17330                        {
17331                            found = true;
17332                            row = crease.range().end.row + 1;
17333                            to_fold.push(crease);
17334                        } else {
17335                            row += 1
17336                        }
17337                    }
17338                    if found {
17339                        continue;
17340                    }
17341                }
17342
17343                for row in (0..=range.start.row).rev() {
17344                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17345                        && crease.range().end.row >= buffer_start_row
17346                    {
17347                        to_fold.push(crease);
17348                        if row <= range.start.row {
17349                            break;
17350                        }
17351                    }
17352                }
17353            }
17354
17355            self.fold_creases(to_fold, true, window, cx);
17356        } else {
17357            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17358            let buffer_ids = self
17359                .selections
17360                .disjoint_anchor_ranges()
17361                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17362                .collect::<HashSet<_>>();
17363            for buffer_id in buffer_ids {
17364                self.fold_buffer(buffer_id, cx);
17365            }
17366        }
17367    }
17368
17369    pub fn toggle_fold_all(
17370        &mut self,
17371        _: &actions::ToggleFoldAll,
17372        window: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        if self.buffer.read(cx).is_singleton() {
17376            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17377            let has_folds = display_map
17378                .folds_in_range(0..display_map.buffer_snapshot.len())
17379                .next()
17380                .is_some();
17381
17382            if has_folds {
17383                self.unfold_all(&actions::UnfoldAll, window, cx);
17384            } else {
17385                self.fold_all(&actions::FoldAll, window, cx);
17386            }
17387        } else {
17388            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17389            let should_unfold = buffer_ids
17390                .iter()
17391                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17392
17393            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17394                editor
17395                    .update_in(cx, |editor, _, cx| {
17396                        for buffer_id in buffer_ids {
17397                            if should_unfold {
17398                                editor.unfold_buffer(buffer_id, cx);
17399                            } else {
17400                                editor.fold_buffer(buffer_id, cx);
17401                            }
17402                        }
17403                    })
17404                    .ok();
17405            });
17406        }
17407    }
17408
17409    fn fold_at_level(
17410        &mut self,
17411        fold_at: &FoldAtLevel,
17412        window: &mut Window,
17413        cx: &mut Context<Self>,
17414    ) {
17415        if !self.buffer.read(cx).is_singleton() {
17416            return;
17417        }
17418
17419        let fold_at_level = fold_at.0;
17420        let snapshot = self.buffer.read(cx).snapshot(cx);
17421        let mut to_fold = Vec::new();
17422        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17423
17424        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17425            while start_row < end_row {
17426                match self
17427                    .snapshot(window, cx)
17428                    .crease_for_buffer_row(MultiBufferRow(start_row))
17429                {
17430                    Some(crease) => {
17431                        let nested_start_row = crease.range().start.row + 1;
17432                        let nested_end_row = crease.range().end.row;
17433
17434                        if current_level < fold_at_level {
17435                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17436                        } else if current_level == fold_at_level {
17437                            to_fold.push(crease);
17438                        }
17439
17440                        start_row = nested_end_row + 1;
17441                    }
17442                    None => start_row += 1,
17443                }
17444            }
17445        }
17446
17447        self.fold_creases(to_fold, true, window, cx);
17448    }
17449
17450    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17451        if self.buffer.read(cx).is_singleton() {
17452            let mut fold_ranges = Vec::new();
17453            let snapshot = self.buffer.read(cx).snapshot(cx);
17454
17455            for row in 0..snapshot.max_row().0 {
17456                if let Some(foldable_range) = self
17457                    .snapshot(window, cx)
17458                    .crease_for_buffer_row(MultiBufferRow(row))
17459                {
17460                    fold_ranges.push(foldable_range);
17461                }
17462            }
17463
17464            self.fold_creases(fold_ranges, true, window, cx);
17465        } else {
17466            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17467                editor
17468                    .update_in(cx, |editor, _, cx| {
17469                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17470                            editor.fold_buffer(buffer_id, cx);
17471                        }
17472                    })
17473                    .ok();
17474            });
17475        }
17476    }
17477
17478    pub fn fold_function_bodies(
17479        &mut self,
17480        _: &actions::FoldFunctionBodies,
17481        window: &mut Window,
17482        cx: &mut Context<Self>,
17483    ) {
17484        let snapshot = self.buffer.read(cx).snapshot(cx);
17485
17486        let ranges = snapshot
17487            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17488            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17489            .collect::<Vec<_>>();
17490
17491        let creases = ranges
17492            .into_iter()
17493            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17494            .collect();
17495
17496        self.fold_creases(creases, true, window, cx);
17497    }
17498
17499    pub fn fold_recursive(
17500        &mut self,
17501        _: &actions::FoldRecursive,
17502        window: &mut Window,
17503        cx: &mut Context<Self>,
17504    ) {
17505        let mut to_fold = Vec::new();
17506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17507        let selections = self.selections.all_adjusted(cx);
17508
17509        for selection in selections {
17510            let range = selection.range().sorted();
17511            let buffer_start_row = range.start.row;
17512
17513            if range.start.row != range.end.row {
17514                let mut found = false;
17515                for row in range.start.row..=range.end.row {
17516                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17517                        found = true;
17518                        to_fold.push(crease);
17519                    }
17520                }
17521                if found {
17522                    continue;
17523                }
17524            }
17525
17526            for row in (0..=range.start.row).rev() {
17527                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17528                    if crease.range().end.row >= buffer_start_row {
17529                        to_fold.push(crease);
17530                    } else {
17531                        break;
17532                    }
17533                }
17534            }
17535        }
17536
17537        self.fold_creases(to_fold, true, window, cx);
17538    }
17539
17540    pub fn fold_at(
17541        &mut self,
17542        buffer_row: MultiBufferRow,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17547
17548        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17549            let autoscroll = self
17550                .selections
17551                .all::<Point>(cx)
17552                .iter()
17553                .any(|selection| crease.range().overlaps(&selection.range()));
17554
17555            self.fold_creases(vec![crease], autoscroll, window, cx);
17556        }
17557    }
17558
17559    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17560        if self.is_singleton(cx) {
17561            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17562            let buffer = &display_map.buffer_snapshot;
17563            let selections = self.selections.all::<Point>(cx);
17564            let ranges = selections
17565                .iter()
17566                .map(|s| {
17567                    let range = s.display_range(&display_map).sorted();
17568                    let mut start = range.start.to_point(&display_map);
17569                    let mut end = range.end.to_point(&display_map);
17570                    start.column = 0;
17571                    end.column = buffer.line_len(MultiBufferRow(end.row));
17572                    start..end
17573                })
17574                .collect::<Vec<_>>();
17575
17576            self.unfold_ranges(&ranges, true, true, cx);
17577        } else {
17578            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17579            let buffer_ids = self
17580                .selections
17581                .disjoint_anchor_ranges()
17582                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17583                .collect::<HashSet<_>>();
17584            for buffer_id in buffer_ids {
17585                self.unfold_buffer(buffer_id, cx);
17586            }
17587        }
17588    }
17589
17590    pub fn unfold_recursive(
17591        &mut self,
17592        _: &UnfoldRecursive,
17593        _window: &mut Window,
17594        cx: &mut Context<Self>,
17595    ) {
17596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17597        let selections = self.selections.all::<Point>(cx);
17598        let ranges = selections
17599            .iter()
17600            .map(|s| {
17601                let mut range = s.display_range(&display_map).sorted();
17602                *range.start.column_mut() = 0;
17603                *range.end.column_mut() = display_map.line_len(range.end.row());
17604                let start = range.start.to_point(&display_map);
17605                let end = range.end.to_point(&display_map);
17606                start..end
17607            })
17608            .collect::<Vec<_>>();
17609
17610        self.unfold_ranges(&ranges, true, true, cx);
17611    }
17612
17613    pub fn unfold_at(
17614        &mut self,
17615        buffer_row: MultiBufferRow,
17616        _window: &mut Window,
17617        cx: &mut Context<Self>,
17618    ) {
17619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17620
17621        let intersection_range = Point::new(buffer_row.0, 0)
17622            ..Point::new(
17623                buffer_row.0,
17624                display_map.buffer_snapshot.line_len(buffer_row),
17625            );
17626
17627        let autoscroll = self
17628            .selections
17629            .all::<Point>(cx)
17630            .iter()
17631            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17632
17633        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17634    }
17635
17636    pub fn unfold_all(
17637        &mut self,
17638        _: &actions::UnfoldAll,
17639        _window: &mut Window,
17640        cx: &mut Context<Self>,
17641    ) {
17642        if self.buffer.read(cx).is_singleton() {
17643            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17644            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17645        } else {
17646            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17647                editor
17648                    .update(cx, |editor, cx| {
17649                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17650                            editor.unfold_buffer(buffer_id, cx);
17651                        }
17652                    })
17653                    .ok();
17654            });
17655        }
17656    }
17657
17658    pub fn fold_selected_ranges(
17659        &mut self,
17660        _: &FoldSelectedRanges,
17661        window: &mut Window,
17662        cx: &mut Context<Self>,
17663    ) {
17664        let selections = self.selections.all_adjusted(cx);
17665        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17666        let ranges = selections
17667            .into_iter()
17668            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17669            .collect::<Vec<_>>();
17670        self.fold_creases(ranges, true, window, cx);
17671    }
17672
17673    pub fn fold_ranges<T: ToOffset + Clone>(
17674        &mut self,
17675        ranges: Vec<Range<T>>,
17676        auto_scroll: bool,
17677        window: &mut Window,
17678        cx: &mut Context<Self>,
17679    ) {
17680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17681        let ranges = ranges
17682            .into_iter()
17683            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17684            .collect::<Vec<_>>();
17685        self.fold_creases(ranges, auto_scroll, window, cx);
17686    }
17687
17688    pub fn fold_creases<T: ToOffset + Clone>(
17689        &mut self,
17690        creases: Vec<Crease<T>>,
17691        auto_scroll: bool,
17692        _window: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        if creases.is_empty() {
17696            return;
17697        }
17698
17699        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17700
17701        if auto_scroll {
17702            self.request_autoscroll(Autoscroll::fit(), cx);
17703        }
17704
17705        cx.notify();
17706
17707        self.scrollbar_marker_state.dirty = true;
17708        self.folds_did_change(cx);
17709    }
17710
17711    /// Removes any folds whose ranges intersect any of the given ranges.
17712    pub fn unfold_ranges<T: ToOffset + Clone>(
17713        &mut self,
17714        ranges: &[Range<T>],
17715        inclusive: bool,
17716        auto_scroll: bool,
17717        cx: &mut Context<Self>,
17718    ) {
17719        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17720            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17721        });
17722        self.folds_did_change(cx);
17723    }
17724
17725    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17726        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17727            return;
17728        }
17729        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17730        self.display_map.update(cx, |display_map, cx| {
17731            display_map.fold_buffers([buffer_id], cx)
17732        });
17733        cx.emit(EditorEvent::BufferFoldToggled {
17734            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17735            folded: true,
17736        });
17737        cx.notify();
17738    }
17739
17740    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17741        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17742            return;
17743        }
17744        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17745        self.display_map.update(cx, |display_map, cx| {
17746            display_map.unfold_buffers([buffer_id], cx);
17747        });
17748        cx.emit(EditorEvent::BufferFoldToggled {
17749            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17750            folded: false,
17751        });
17752        cx.notify();
17753    }
17754
17755    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17756        self.display_map.read(cx).is_buffer_folded(buffer)
17757    }
17758
17759    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17760        self.display_map.read(cx).folded_buffers()
17761    }
17762
17763    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17764        self.display_map.update(cx, |display_map, cx| {
17765            display_map.disable_header_for_buffer(buffer_id, cx);
17766        });
17767        cx.notify();
17768    }
17769
17770    /// Removes any folds with the given ranges.
17771    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17772        &mut self,
17773        ranges: &[Range<T>],
17774        type_id: TypeId,
17775        auto_scroll: bool,
17776        cx: &mut Context<Self>,
17777    ) {
17778        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17779            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17780        });
17781        self.folds_did_change(cx);
17782    }
17783
17784    fn remove_folds_with<T: ToOffset + Clone>(
17785        &mut self,
17786        ranges: &[Range<T>],
17787        auto_scroll: bool,
17788        cx: &mut Context<Self>,
17789        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17790    ) {
17791        if ranges.is_empty() {
17792            return;
17793        }
17794
17795        let mut buffers_affected = HashSet::default();
17796        let multi_buffer = self.buffer().read(cx);
17797        for range in ranges {
17798            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17799                buffers_affected.insert(buffer.read(cx).remote_id());
17800            };
17801        }
17802
17803        self.display_map.update(cx, update);
17804
17805        if auto_scroll {
17806            self.request_autoscroll(Autoscroll::fit(), cx);
17807        }
17808
17809        cx.notify();
17810        self.scrollbar_marker_state.dirty = true;
17811        self.active_indent_guides_state.dirty = true;
17812    }
17813
17814    pub fn update_renderer_widths(
17815        &mut self,
17816        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17817        cx: &mut Context<Self>,
17818    ) -> bool {
17819        self.display_map
17820            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17821    }
17822
17823    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17824        self.display_map.read(cx).fold_placeholder.clone()
17825    }
17826
17827    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17828        self.buffer.update(cx, |buffer, cx| {
17829            buffer.set_all_diff_hunks_expanded(cx);
17830        });
17831    }
17832
17833    pub fn expand_all_diff_hunks(
17834        &mut self,
17835        _: &ExpandAllDiffHunks,
17836        _window: &mut Window,
17837        cx: &mut Context<Self>,
17838    ) {
17839        self.buffer.update(cx, |buffer, cx| {
17840            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17841        });
17842    }
17843
17844    pub fn toggle_selected_diff_hunks(
17845        &mut self,
17846        _: &ToggleSelectedDiffHunks,
17847        _window: &mut Window,
17848        cx: &mut Context<Self>,
17849    ) {
17850        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17851        self.toggle_diff_hunks_in_ranges(ranges, cx);
17852    }
17853
17854    pub fn diff_hunks_in_ranges<'a>(
17855        &'a self,
17856        ranges: &'a [Range<Anchor>],
17857        buffer: &'a MultiBufferSnapshot,
17858    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17859        ranges.iter().flat_map(move |range| {
17860            let end_excerpt_id = range.end.excerpt_id;
17861            let range = range.to_point(buffer);
17862            let mut peek_end = range.end;
17863            if range.end.row < buffer.max_row().0 {
17864                peek_end = Point::new(range.end.row + 1, 0);
17865            }
17866            buffer
17867                .diff_hunks_in_range(range.start..peek_end)
17868                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17869        })
17870    }
17871
17872    pub fn has_stageable_diff_hunks_in_ranges(
17873        &self,
17874        ranges: &[Range<Anchor>],
17875        snapshot: &MultiBufferSnapshot,
17876    ) -> bool {
17877        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17878        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17879    }
17880
17881    pub fn toggle_staged_selected_diff_hunks(
17882        &mut self,
17883        _: &::git::ToggleStaged,
17884        _: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        let snapshot = self.buffer.read(cx).snapshot(cx);
17888        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17889        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17890        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17891    }
17892
17893    pub fn set_render_diff_hunk_controls(
17894        &mut self,
17895        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17896        cx: &mut Context<Self>,
17897    ) {
17898        self.render_diff_hunk_controls = render_diff_hunk_controls;
17899        cx.notify();
17900    }
17901
17902    pub fn stage_and_next(
17903        &mut self,
17904        _: &::git::StageAndNext,
17905        window: &mut Window,
17906        cx: &mut Context<Self>,
17907    ) {
17908        self.do_stage_or_unstage_and_next(true, window, cx);
17909    }
17910
17911    pub fn unstage_and_next(
17912        &mut self,
17913        _: &::git::UnstageAndNext,
17914        window: &mut Window,
17915        cx: &mut Context<Self>,
17916    ) {
17917        self.do_stage_or_unstage_and_next(false, window, cx);
17918    }
17919
17920    pub fn stage_or_unstage_diff_hunks(
17921        &mut self,
17922        stage: bool,
17923        ranges: Vec<Range<Anchor>>,
17924        cx: &mut Context<Self>,
17925    ) {
17926        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17927        cx.spawn(async move |this, cx| {
17928            task.await?;
17929            this.update(cx, |this, cx| {
17930                let snapshot = this.buffer.read(cx).snapshot(cx);
17931                let chunk_by = this
17932                    .diff_hunks_in_ranges(&ranges, &snapshot)
17933                    .chunk_by(|hunk| hunk.buffer_id);
17934                for (buffer_id, hunks) in &chunk_by {
17935                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17936                }
17937            })
17938        })
17939        .detach_and_log_err(cx);
17940    }
17941
17942    fn save_buffers_for_ranges_if_needed(
17943        &mut self,
17944        ranges: &[Range<Anchor>],
17945        cx: &mut Context<Editor>,
17946    ) -> Task<Result<()>> {
17947        let multibuffer = self.buffer.read(cx);
17948        let snapshot = multibuffer.read(cx);
17949        let buffer_ids: HashSet<_> = ranges
17950            .iter()
17951            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17952            .collect();
17953        drop(snapshot);
17954
17955        let mut buffers = HashSet::default();
17956        for buffer_id in buffer_ids {
17957            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17958                let buffer = buffer_entity.read(cx);
17959                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17960                {
17961                    buffers.insert(buffer_entity);
17962                }
17963            }
17964        }
17965
17966        if let Some(project) = &self.project {
17967            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17968        } else {
17969            Task::ready(Ok(()))
17970        }
17971    }
17972
17973    fn do_stage_or_unstage_and_next(
17974        &mut self,
17975        stage: bool,
17976        window: &mut Window,
17977        cx: &mut Context<Self>,
17978    ) {
17979        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17980
17981        if ranges.iter().any(|range| range.start != range.end) {
17982            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17983            return;
17984        }
17985
17986        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17987        let snapshot = self.snapshot(window, cx);
17988        let position = self.selections.newest::<Point>(cx).head();
17989        let mut row = snapshot
17990            .buffer_snapshot
17991            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17992            .find(|hunk| hunk.row_range.start.0 > position.row)
17993            .map(|hunk| hunk.row_range.start);
17994
17995        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17996        // Outside of the project diff editor, wrap around to the beginning.
17997        if !all_diff_hunks_expanded {
17998            row = row.or_else(|| {
17999                snapshot
18000                    .buffer_snapshot
18001                    .diff_hunks_in_range(Point::zero()..position)
18002                    .find(|hunk| hunk.row_range.end.0 < position.row)
18003                    .map(|hunk| hunk.row_range.start)
18004            });
18005        }
18006
18007        if let Some(row) = row {
18008            let destination = Point::new(row.0, 0);
18009            let autoscroll = Autoscroll::center();
18010
18011            self.unfold_ranges(&[destination..destination], false, false, cx);
18012            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18013                s.select_ranges([destination..destination]);
18014            });
18015        }
18016    }
18017
18018    fn do_stage_or_unstage(
18019        &self,
18020        stage: bool,
18021        buffer_id: BufferId,
18022        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18023        cx: &mut App,
18024    ) -> Option<()> {
18025        let project = self.project()?;
18026        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18027        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18028        let buffer_snapshot = buffer.read(cx).snapshot();
18029        let file_exists = buffer_snapshot
18030            .file()
18031            .is_some_and(|file| file.disk_state().exists());
18032        diff.update(cx, |diff, cx| {
18033            diff.stage_or_unstage_hunks(
18034                stage,
18035                &hunks
18036                    .map(|hunk| buffer_diff::DiffHunk {
18037                        buffer_range: hunk.buffer_range,
18038                        diff_base_byte_range: hunk.diff_base_byte_range,
18039                        secondary_status: hunk.secondary_status,
18040                        range: Point::zero()..Point::zero(), // unused
18041                    })
18042                    .collect::<Vec<_>>(),
18043                &buffer_snapshot,
18044                file_exists,
18045                cx,
18046            )
18047        });
18048        None
18049    }
18050
18051    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18052        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18053        self.buffer
18054            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18055    }
18056
18057    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18058        self.buffer.update(cx, |buffer, cx| {
18059            let ranges = vec![Anchor::min()..Anchor::max()];
18060            if !buffer.all_diff_hunks_expanded()
18061                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18062            {
18063                buffer.collapse_diff_hunks(ranges, cx);
18064                true
18065            } else {
18066                false
18067            }
18068        })
18069    }
18070
18071    fn toggle_diff_hunks_in_ranges(
18072        &mut self,
18073        ranges: Vec<Range<Anchor>>,
18074        cx: &mut Context<Editor>,
18075    ) {
18076        self.buffer.update(cx, |buffer, cx| {
18077            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18078            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18079        })
18080    }
18081
18082    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18083        self.buffer.update(cx, |buffer, cx| {
18084            let snapshot = buffer.snapshot(cx);
18085            let excerpt_id = range.end.excerpt_id;
18086            let point_range = range.to_point(&snapshot);
18087            let expand = !buffer.single_hunk_is_expanded(range, cx);
18088            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18089        })
18090    }
18091
18092    pub(crate) fn apply_all_diff_hunks(
18093        &mut self,
18094        _: &ApplyAllDiffHunks,
18095        window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18099
18100        let buffers = self.buffer.read(cx).all_buffers();
18101        for branch_buffer in buffers {
18102            branch_buffer.update(cx, |branch_buffer, cx| {
18103                branch_buffer.merge_into_base(Vec::new(), cx);
18104            });
18105        }
18106
18107        if let Some(project) = self.project.clone() {
18108            self.save(
18109                SaveOptions {
18110                    format: true,
18111                    autosave: false,
18112                },
18113                project,
18114                window,
18115                cx,
18116            )
18117            .detach_and_log_err(cx);
18118        }
18119    }
18120
18121    pub(crate) fn apply_selected_diff_hunks(
18122        &mut self,
18123        _: &ApplyDiffHunk,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18128        let snapshot = self.snapshot(window, cx);
18129        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18130        let mut ranges_by_buffer = HashMap::default();
18131        self.transact(window, cx, |editor, _window, cx| {
18132            for hunk in hunks {
18133                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18134                    ranges_by_buffer
18135                        .entry(buffer.clone())
18136                        .or_insert_with(Vec::new)
18137                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18138                }
18139            }
18140
18141            for (buffer, ranges) in ranges_by_buffer {
18142                buffer.update(cx, |buffer, cx| {
18143                    buffer.merge_into_base(ranges, cx);
18144                });
18145            }
18146        });
18147
18148        if let Some(project) = self.project.clone() {
18149            self.save(
18150                SaveOptions {
18151                    format: true,
18152                    autosave: false,
18153                },
18154                project,
18155                window,
18156                cx,
18157            )
18158            .detach_and_log_err(cx);
18159        }
18160    }
18161
18162    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18163        if hovered != self.gutter_hovered {
18164            self.gutter_hovered = hovered;
18165            cx.notify();
18166        }
18167    }
18168
18169    pub fn insert_blocks(
18170        &mut self,
18171        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18172        autoscroll: Option<Autoscroll>,
18173        cx: &mut Context<Self>,
18174    ) -> Vec<CustomBlockId> {
18175        let blocks = self
18176            .display_map
18177            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18178        if let Some(autoscroll) = autoscroll {
18179            self.request_autoscroll(autoscroll, cx);
18180        }
18181        cx.notify();
18182        blocks
18183    }
18184
18185    pub fn resize_blocks(
18186        &mut self,
18187        heights: HashMap<CustomBlockId, u32>,
18188        autoscroll: Option<Autoscroll>,
18189        cx: &mut Context<Self>,
18190    ) {
18191        self.display_map
18192            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18193        if let Some(autoscroll) = autoscroll {
18194            self.request_autoscroll(autoscroll, cx);
18195        }
18196        cx.notify();
18197    }
18198
18199    pub fn replace_blocks(
18200        &mut self,
18201        renderers: HashMap<CustomBlockId, RenderBlock>,
18202        autoscroll: Option<Autoscroll>,
18203        cx: &mut Context<Self>,
18204    ) {
18205        self.display_map
18206            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18207        if let Some(autoscroll) = autoscroll {
18208            self.request_autoscroll(autoscroll, cx);
18209        }
18210        cx.notify();
18211    }
18212
18213    pub fn remove_blocks(
18214        &mut self,
18215        block_ids: HashSet<CustomBlockId>,
18216        autoscroll: Option<Autoscroll>,
18217        cx: &mut Context<Self>,
18218    ) {
18219        self.display_map.update(cx, |display_map, cx| {
18220            display_map.remove_blocks(block_ids, cx)
18221        });
18222        if let Some(autoscroll) = autoscroll {
18223            self.request_autoscroll(autoscroll, cx);
18224        }
18225        cx.notify();
18226    }
18227
18228    pub fn row_for_block(
18229        &self,
18230        block_id: CustomBlockId,
18231        cx: &mut Context<Self>,
18232    ) -> Option<DisplayRow> {
18233        self.display_map
18234            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18235    }
18236
18237    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18238        self.focused_block = Some(focused_block);
18239    }
18240
18241    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18242        self.focused_block.take()
18243    }
18244
18245    pub fn insert_creases(
18246        &mut self,
18247        creases: impl IntoIterator<Item = Crease<Anchor>>,
18248        cx: &mut Context<Self>,
18249    ) -> Vec<CreaseId> {
18250        self.display_map
18251            .update(cx, |map, cx| map.insert_creases(creases, cx))
18252    }
18253
18254    pub fn remove_creases(
18255        &mut self,
18256        ids: impl IntoIterator<Item = CreaseId>,
18257        cx: &mut Context<Self>,
18258    ) -> Vec<(CreaseId, Range<Anchor>)> {
18259        self.display_map
18260            .update(cx, |map, cx| map.remove_creases(ids, cx))
18261    }
18262
18263    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18264        self.display_map
18265            .update(cx, |map, cx| map.snapshot(cx))
18266            .longest_row()
18267    }
18268
18269    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18270        self.display_map
18271            .update(cx, |map, cx| map.snapshot(cx))
18272            .max_point()
18273    }
18274
18275    pub fn text(&self, cx: &App) -> String {
18276        self.buffer.read(cx).read(cx).text()
18277    }
18278
18279    pub fn is_empty(&self, cx: &App) -> bool {
18280        self.buffer.read(cx).read(cx).is_empty()
18281    }
18282
18283    pub fn text_option(&self, cx: &App) -> Option<String> {
18284        let text = self.text(cx);
18285        let text = text.trim();
18286
18287        if text.is_empty() {
18288            return None;
18289        }
18290
18291        Some(text.to_string())
18292    }
18293
18294    pub fn set_text(
18295        &mut self,
18296        text: impl Into<Arc<str>>,
18297        window: &mut Window,
18298        cx: &mut Context<Self>,
18299    ) {
18300        self.transact(window, cx, |this, _, cx| {
18301            this.buffer
18302                .read(cx)
18303                .as_singleton()
18304                .expect("you can only call set_text on editors for singleton buffers")
18305                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18306        });
18307    }
18308
18309    pub fn display_text(&self, cx: &mut App) -> String {
18310        self.display_map
18311            .update(cx, |map, cx| map.snapshot(cx))
18312            .text()
18313    }
18314
18315    fn create_minimap(
18316        &self,
18317        minimap_settings: MinimapSettings,
18318        window: &mut Window,
18319        cx: &mut Context<Self>,
18320    ) -> Option<Entity<Self>> {
18321        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18322            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18323    }
18324
18325    fn initialize_new_minimap(
18326        &self,
18327        minimap_settings: MinimapSettings,
18328        window: &mut Window,
18329        cx: &mut Context<Self>,
18330    ) -> Entity<Self> {
18331        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18332
18333        let mut minimap = Editor::new_internal(
18334            EditorMode::Minimap {
18335                parent: cx.weak_entity(),
18336            },
18337            self.buffer.clone(),
18338            None,
18339            Some(self.display_map.clone()),
18340            window,
18341            cx,
18342        );
18343        minimap.scroll_manager.clone_state(&self.scroll_manager);
18344        minimap.set_text_style_refinement(TextStyleRefinement {
18345            font_size: Some(MINIMAP_FONT_SIZE),
18346            font_weight: Some(MINIMAP_FONT_WEIGHT),
18347            ..Default::default()
18348        });
18349        minimap.update_minimap_configuration(minimap_settings, cx);
18350        cx.new(|_| minimap)
18351    }
18352
18353    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18354        let current_line_highlight = minimap_settings
18355            .current_line_highlight
18356            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18357        self.set_current_line_highlight(Some(current_line_highlight));
18358    }
18359
18360    pub fn minimap(&self) -> Option<&Entity<Self>> {
18361        self.minimap
18362            .as_ref()
18363            .filter(|_| self.minimap_visibility.visible())
18364    }
18365
18366    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18367        let mut wrap_guides = smallvec![];
18368
18369        if self.show_wrap_guides == Some(false) {
18370            return wrap_guides;
18371        }
18372
18373        let settings = self.buffer.read(cx).language_settings(cx);
18374        if settings.show_wrap_guides {
18375            match self.soft_wrap_mode(cx) {
18376                SoftWrap::Column(soft_wrap) => {
18377                    wrap_guides.push((soft_wrap as usize, true));
18378                }
18379                SoftWrap::Bounded(soft_wrap) => {
18380                    wrap_guides.push((soft_wrap as usize, true));
18381                }
18382                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18383            }
18384            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18385        }
18386
18387        wrap_guides
18388    }
18389
18390    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18391        let settings = self.buffer.read(cx).language_settings(cx);
18392        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18393        match mode {
18394            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18395                SoftWrap::None
18396            }
18397            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18398            language_settings::SoftWrap::PreferredLineLength => {
18399                SoftWrap::Column(settings.preferred_line_length)
18400            }
18401            language_settings::SoftWrap::Bounded => {
18402                SoftWrap::Bounded(settings.preferred_line_length)
18403            }
18404        }
18405    }
18406
18407    pub fn set_soft_wrap_mode(
18408        &mut self,
18409        mode: language_settings::SoftWrap,
18410
18411        cx: &mut Context<Self>,
18412    ) {
18413        self.soft_wrap_mode_override = Some(mode);
18414        cx.notify();
18415    }
18416
18417    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18418        self.hard_wrap = hard_wrap;
18419        cx.notify();
18420    }
18421
18422    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18423        self.text_style_refinement = Some(style);
18424    }
18425
18426    /// called by the Element so we know what style we were most recently rendered with.
18427    pub(crate) fn set_style(
18428        &mut self,
18429        style: EditorStyle,
18430        window: &mut Window,
18431        cx: &mut Context<Self>,
18432    ) {
18433        // We intentionally do not inform the display map about the minimap style
18434        // so that wrapping is not recalculated and stays consistent for the editor
18435        // and its linked minimap.
18436        if !self.mode.is_minimap() {
18437            let rem_size = window.rem_size();
18438            self.display_map.update(cx, |map, cx| {
18439                map.set_font(
18440                    style.text.font(),
18441                    style.text.font_size.to_pixels(rem_size),
18442                    cx,
18443                )
18444            });
18445        }
18446        self.style = Some(style);
18447    }
18448
18449    pub fn style(&self) -> Option<&EditorStyle> {
18450        self.style.as_ref()
18451    }
18452
18453    // Called by the element. This method is not designed to be called outside of the editor
18454    // element's layout code because it does not notify when rewrapping is computed synchronously.
18455    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18456        self.display_map
18457            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18458    }
18459
18460    pub fn set_soft_wrap(&mut self) {
18461        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18462    }
18463
18464    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18465        if self.soft_wrap_mode_override.is_some() {
18466            self.soft_wrap_mode_override.take();
18467        } else {
18468            let soft_wrap = match self.soft_wrap_mode(cx) {
18469                SoftWrap::GitDiff => return,
18470                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18471                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18472                    language_settings::SoftWrap::None
18473                }
18474            };
18475            self.soft_wrap_mode_override = Some(soft_wrap);
18476        }
18477        cx.notify();
18478    }
18479
18480    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18481        let Some(workspace) = self.workspace() else {
18482            return;
18483        };
18484        let fs = workspace.read(cx).app_state().fs.clone();
18485        let current_show = TabBarSettings::get_global(cx).show;
18486        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18487            setting.show = Some(!current_show);
18488        });
18489    }
18490
18491    pub fn toggle_indent_guides(
18492        &mut self,
18493        _: &ToggleIndentGuides,
18494        _: &mut Window,
18495        cx: &mut Context<Self>,
18496    ) {
18497        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18498            self.buffer
18499                .read(cx)
18500                .language_settings(cx)
18501                .indent_guides
18502                .enabled
18503        });
18504        self.show_indent_guides = Some(!currently_enabled);
18505        cx.notify();
18506    }
18507
18508    fn should_show_indent_guides(&self) -> Option<bool> {
18509        self.show_indent_guides
18510    }
18511
18512    pub fn toggle_line_numbers(
18513        &mut self,
18514        _: &ToggleLineNumbers,
18515        _: &mut Window,
18516        cx: &mut Context<Self>,
18517    ) {
18518        let mut editor_settings = EditorSettings::get_global(cx).clone();
18519        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18520        EditorSettings::override_global(editor_settings, cx);
18521    }
18522
18523    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18524        if let Some(show_line_numbers) = self.show_line_numbers {
18525            return show_line_numbers;
18526        }
18527        EditorSettings::get_global(cx).gutter.line_numbers
18528    }
18529
18530    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18531        self.use_relative_line_numbers
18532            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18533    }
18534
18535    pub fn toggle_relative_line_numbers(
18536        &mut self,
18537        _: &ToggleRelativeLineNumbers,
18538        _: &mut Window,
18539        cx: &mut Context<Self>,
18540    ) {
18541        let is_relative = self.should_use_relative_line_numbers(cx);
18542        self.set_relative_line_number(Some(!is_relative), cx)
18543    }
18544
18545    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18546        self.use_relative_line_numbers = is_relative;
18547        cx.notify();
18548    }
18549
18550    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18551        self.show_gutter = show_gutter;
18552        cx.notify();
18553    }
18554
18555    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18556        self.show_scrollbars = ScrollbarAxes {
18557            horizontal: show,
18558            vertical: show,
18559        };
18560        cx.notify();
18561    }
18562
18563    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18564        self.show_scrollbars.vertical = show;
18565        cx.notify();
18566    }
18567
18568    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18569        self.show_scrollbars.horizontal = show;
18570        cx.notify();
18571    }
18572
18573    pub fn set_minimap_visibility(
18574        &mut self,
18575        minimap_visibility: MinimapVisibility,
18576        window: &mut Window,
18577        cx: &mut Context<Self>,
18578    ) {
18579        if self.minimap_visibility != minimap_visibility {
18580            if minimap_visibility.visible() && self.minimap.is_none() {
18581                let minimap_settings = EditorSettings::get_global(cx).minimap;
18582                self.minimap =
18583                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18584            }
18585            self.minimap_visibility = minimap_visibility;
18586            cx.notify();
18587        }
18588    }
18589
18590    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18591        self.set_show_scrollbars(false, cx);
18592        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18593    }
18594
18595    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18596        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18597    }
18598
18599    /// Normally the text in full mode and auto height editors is padded on the
18600    /// left side by roughly half a character width for improved hit testing.
18601    ///
18602    /// Use this method to disable this for cases where this is not wanted (e.g.
18603    /// if you want to align the editor text with some other text above or below)
18604    /// or if you want to add this padding to single-line editors.
18605    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18606        self.offset_content = offset_content;
18607        cx.notify();
18608    }
18609
18610    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18611        self.show_line_numbers = Some(show_line_numbers);
18612        cx.notify();
18613    }
18614
18615    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18616        self.disable_expand_excerpt_buttons = true;
18617        cx.notify();
18618    }
18619
18620    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18621        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18622        cx.notify();
18623    }
18624
18625    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18626        self.show_code_actions = Some(show_code_actions);
18627        cx.notify();
18628    }
18629
18630    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18631        self.show_runnables = Some(show_runnables);
18632        cx.notify();
18633    }
18634
18635    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18636        self.show_breakpoints = Some(show_breakpoints);
18637        cx.notify();
18638    }
18639
18640    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18641        if self.display_map.read(cx).masked != masked {
18642            self.display_map.update(cx, |map, _| map.masked = masked);
18643        }
18644        cx.notify()
18645    }
18646
18647    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18648        self.show_wrap_guides = Some(show_wrap_guides);
18649        cx.notify();
18650    }
18651
18652    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18653        self.show_indent_guides = Some(show_indent_guides);
18654        cx.notify();
18655    }
18656
18657    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18658        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18659            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18660                && let Some(dir) = file.abs_path(cx).parent()
18661            {
18662                return Some(dir.to_owned());
18663            }
18664
18665            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18666                return Some(project_path.path.to_path_buf());
18667            }
18668        }
18669
18670        None
18671    }
18672
18673    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18674        self.active_excerpt(cx)?
18675            .1
18676            .read(cx)
18677            .file()
18678            .and_then(|f| f.as_local())
18679    }
18680
18681    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18682        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18683            let buffer = buffer.read(cx);
18684            if let Some(project_path) = buffer.project_path(cx) {
18685                let project = self.project()?.read(cx);
18686                project.absolute_path(&project_path, cx)
18687            } else {
18688                buffer
18689                    .file()
18690                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18691            }
18692        })
18693    }
18694
18695    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18696        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18697            let project_path = buffer.read(cx).project_path(cx)?;
18698            let project = self.project()?.read(cx);
18699            let entry = project.entry_for_path(&project_path, cx)?;
18700            let path = entry.path.to_path_buf();
18701            Some(path)
18702        })
18703    }
18704
18705    pub fn reveal_in_finder(
18706        &mut self,
18707        _: &RevealInFileManager,
18708        _window: &mut Window,
18709        cx: &mut Context<Self>,
18710    ) {
18711        if let Some(target) = self.target_file(cx) {
18712            cx.reveal_path(&target.abs_path(cx));
18713        }
18714    }
18715
18716    pub fn copy_path(
18717        &mut self,
18718        _: &zed_actions::workspace::CopyPath,
18719        _window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        if let Some(path) = self.target_file_abs_path(cx)
18723            && let Some(path) = path.to_str()
18724        {
18725            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18726        }
18727    }
18728
18729    pub fn copy_relative_path(
18730        &mut self,
18731        _: &zed_actions::workspace::CopyRelativePath,
18732        _window: &mut Window,
18733        cx: &mut Context<Self>,
18734    ) {
18735        if let Some(path) = self.target_file_path(cx)
18736            && let Some(path) = path.to_str()
18737        {
18738            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18739        }
18740    }
18741
18742    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18743        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18744            buffer.read(cx).project_path(cx)
18745        } else {
18746            None
18747        }
18748    }
18749
18750    // Returns true if the editor handled a go-to-line request
18751    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18752        maybe!({
18753            let breakpoint_store = self.breakpoint_store.as_ref()?;
18754
18755            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18756            else {
18757                self.clear_row_highlights::<ActiveDebugLine>();
18758                return None;
18759            };
18760
18761            let position = active_stack_frame.position;
18762            let buffer_id = position.buffer_id?;
18763            let snapshot = self
18764                .project
18765                .as_ref()?
18766                .read(cx)
18767                .buffer_for_id(buffer_id, cx)?
18768                .read(cx)
18769                .snapshot();
18770
18771            let mut handled = false;
18772            for (id, ExcerptRange { context, .. }) in
18773                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18774            {
18775                if context.start.cmp(&position, &snapshot).is_ge()
18776                    || context.end.cmp(&position, &snapshot).is_lt()
18777                {
18778                    continue;
18779                }
18780                let snapshot = self.buffer.read(cx).snapshot(cx);
18781                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18782
18783                handled = true;
18784                self.clear_row_highlights::<ActiveDebugLine>();
18785
18786                self.go_to_line::<ActiveDebugLine>(
18787                    multibuffer_anchor,
18788                    Some(cx.theme().colors().editor_debugger_active_line_background),
18789                    window,
18790                    cx,
18791                );
18792
18793                cx.notify();
18794            }
18795
18796            handled.then_some(())
18797        })
18798        .is_some()
18799    }
18800
18801    pub fn copy_file_name_without_extension(
18802        &mut self,
18803        _: &CopyFileNameWithoutExtension,
18804        _: &mut Window,
18805        cx: &mut Context<Self>,
18806    ) {
18807        if let Some(file) = self.target_file(cx)
18808            && let Some(file_stem) = file.path().file_stem()
18809            && let Some(name) = file_stem.to_str()
18810        {
18811            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18812        }
18813    }
18814
18815    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18816        if let Some(file) = self.target_file(cx)
18817            && let Some(file_name) = file.path().file_name()
18818            && let Some(name) = file_name.to_str()
18819        {
18820            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18821        }
18822    }
18823
18824    pub fn toggle_git_blame(
18825        &mut self,
18826        _: &::git::Blame,
18827        window: &mut Window,
18828        cx: &mut Context<Self>,
18829    ) {
18830        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18831
18832        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18833            self.start_git_blame(true, window, cx);
18834        }
18835
18836        cx.notify();
18837    }
18838
18839    pub fn toggle_git_blame_inline(
18840        &mut self,
18841        _: &ToggleGitBlameInline,
18842        window: &mut Window,
18843        cx: &mut Context<Self>,
18844    ) {
18845        self.toggle_git_blame_inline_internal(true, window, cx);
18846        cx.notify();
18847    }
18848
18849    pub fn open_git_blame_commit(
18850        &mut self,
18851        _: &OpenGitBlameCommit,
18852        window: &mut Window,
18853        cx: &mut Context<Self>,
18854    ) {
18855        self.open_git_blame_commit_internal(window, cx);
18856    }
18857
18858    fn open_git_blame_commit_internal(
18859        &mut self,
18860        window: &mut Window,
18861        cx: &mut Context<Self>,
18862    ) -> Option<()> {
18863        let blame = self.blame.as_ref()?;
18864        let snapshot = self.snapshot(window, cx);
18865        let cursor = self.selections.newest::<Point>(cx).head();
18866        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18867        let blame_entry = blame
18868            .update(cx, |blame, cx| {
18869                blame
18870                    .blame_for_rows(
18871                        &[RowInfo {
18872                            buffer_id: Some(buffer.remote_id()),
18873                            buffer_row: Some(point.row),
18874                            ..Default::default()
18875                        }],
18876                        cx,
18877                    )
18878                    .next()
18879            })
18880            .flatten()?;
18881        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18882        let repo = blame.read(cx).repository(cx)?;
18883        let workspace = self.workspace()?.downgrade();
18884        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18885        None
18886    }
18887
18888    pub fn git_blame_inline_enabled(&self) -> bool {
18889        self.git_blame_inline_enabled
18890    }
18891
18892    pub fn toggle_selection_menu(
18893        &mut self,
18894        _: &ToggleSelectionMenu,
18895        _: &mut Window,
18896        cx: &mut Context<Self>,
18897    ) {
18898        self.show_selection_menu = self
18899            .show_selection_menu
18900            .map(|show_selections_menu| !show_selections_menu)
18901            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18902
18903        cx.notify();
18904    }
18905
18906    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18907        self.show_selection_menu
18908            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18909    }
18910
18911    fn start_git_blame(
18912        &mut self,
18913        user_triggered: bool,
18914        window: &mut Window,
18915        cx: &mut Context<Self>,
18916    ) {
18917        if let Some(project) = self.project() {
18918            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18919                return;
18920            };
18921
18922            if buffer.read(cx).file().is_none() {
18923                return;
18924            }
18925
18926            let focused = self.focus_handle(cx).contains_focused(window, cx);
18927
18928            let project = project.clone();
18929            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18930            self.blame_subscription =
18931                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18932            self.blame = Some(blame);
18933        }
18934    }
18935
18936    fn toggle_git_blame_inline_internal(
18937        &mut self,
18938        user_triggered: bool,
18939        window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) {
18942        if self.git_blame_inline_enabled {
18943            self.git_blame_inline_enabled = false;
18944            self.show_git_blame_inline = false;
18945            self.show_git_blame_inline_delay_task.take();
18946        } else {
18947            self.git_blame_inline_enabled = true;
18948            self.start_git_blame_inline(user_triggered, window, cx);
18949        }
18950
18951        cx.notify();
18952    }
18953
18954    fn start_git_blame_inline(
18955        &mut self,
18956        user_triggered: bool,
18957        window: &mut Window,
18958        cx: &mut Context<Self>,
18959    ) {
18960        self.start_git_blame(user_triggered, window, cx);
18961
18962        if ProjectSettings::get_global(cx)
18963            .git
18964            .inline_blame_delay()
18965            .is_some()
18966        {
18967            self.start_inline_blame_timer(window, cx);
18968        } else {
18969            self.show_git_blame_inline = true
18970        }
18971    }
18972
18973    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18974        self.blame.as_ref()
18975    }
18976
18977    pub fn show_git_blame_gutter(&self) -> bool {
18978        self.show_git_blame_gutter
18979    }
18980
18981    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18982        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18983    }
18984
18985    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18986        self.show_git_blame_inline
18987            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18988            && !self.newest_selection_head_on_empty_line(cx)
18989            && self.has_blame_entries(cx)
18990    }
18991
18992    fn has_blame_entries(&self, cx: &App) -> bool {
18993        self.blame()
18994            .is_some_and(|blame| blame.read(cx).has_generated_entries())
18995    }
18996
18997    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18998        let cursor_anchor = self.selections.newest_anchor().head();
18999
19000        let snapshot = self.buffer.read(cx).snapshot(cx);
19001        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19002
19003        snapshot.line_len(buffer_row) == 0
19004    }
19005
19006    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19007        let buffer_and_selection = maybe!({
19008            let selection = self.selections.newest::<Point>(cx);
19009            let selection_range = selection.range();
19010
19011            let multi_buffer = self.buffer().read(cx);
19012            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19013            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19014
19015            let (buffer, range, _) = if selection.reversed {
19016                buffer_ranges.first()
19017            } else {
19018                buffer_ranges.last()
19019            }?;
19020
19021            let selection = text::ToPoint::to_point(&range.start, buffer).row
19022                ..text::ToPoint::to_point(&range.end, buffer).row;
19023            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19024        });
19025
19026        let Some((buffer, selection)) = buffer_and_selection else {
19027            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19028        };
19029
19030        let Some(project) = self.project() else {
19031            return Task::ready(Err(anyhow!("editor does not have project")));
19032        };
19033
19034        project.update(cx, |project, cx| {
19035            project.get_permalink_to_line(&buffer, selection, cx)
19036        })
19037    }
19038
19039    pub fn copy_permalink_to_line(
19040        &mut self,
19041        _: &CopyPermalinkToLine,
19042        window: &mut Window,
19043        cx: &mut Context<Self>,
19044    ) {
19045        let permalink_task = self.get_permalink_to_line(cx);
19046        let workspace = self.workspace();
19047
19048        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19049            Ok(permalink) => {
19050                cx.update(|_, cx| {
19051                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19052                })
19053                .ok();
19054            }
19055            Err(err) => {
19056                let message = format!("Failed to copy permalink: {err}");
19057
19058                anyhow::Result::<()>::Err(err).log_err();
19059
19060                if let Some(workspace) = workspace {
19061                    workspace
19062                        .update_in(cx, |workspace, _, cx| {
19063                            struct CopyPermalinkToLine;
19064
19065                            workspace.show_toast(
19066                                Toast::new(
19067                                    NotificationId::unique::<CopyPermalinkToLine>(),
19068                                    message,
19069                                ),
19070                                cx,
19071                            )
19072                        })
19073                        .ok();
19074                }
19075            }
19076        })
19077        .detach();
19078    }
19079
19080    pub fn copy_file_location(
19081        &mut self,
19082        _: &CopyFileLocation,
19083        _: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19087        if let Some(file) = self.target_file(cx)
19088            && let Some(path) = file.path().to_str()
19089        {
19090            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19091        }
19092    }
19093
19094    pub fn open_permalink_to_line(
19095        &mut self,
19096        _: &OpenPermalinkToLine,
19097        window: &mut Window,
19098        cx: &mut Context<Self>,
19099    ) {
19100        let permalink_task = self.get_permalink_to_line(cx);
19101        let workspace = self.workspace();
19102
19103        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19104            Ok(permalink) => {
19105                cx.update(|_, cx| {
19106                    cx.open_url(permalink.as_ref());
19107                })
19108                .ok();
19109            }
19110            Err(err) => {
19111                let message = format!("Failed to open permalink: {err}");
19112
19113                anyhow::Result::<()>::Err(err).log_err();
19114
19115                if let Some(workspace) = workspace {
19116                    workspace
19117                        .update(cx, |workspace, cx| {
19118                            struct OpenPermalinkToLine;
19119
19120                            workspace.show_toast(
19121                                Toast::new(
19122                                    NotificationId::unique::<OpenPermalinkToLine>(),
19123                                    message,
19124                                ),
19125                                cx,
19126                            )
19127                        })
19128                        .ok();
19129                }
19130            }
19131        })
19132        .detach();
19133    }
19134
19135    pub fn insert_uuid_v4(
19136        &mut self,
19137        _: &InsertUuidV4,
19138        window: &mut Window,
19139        cx: &mut Context<Self>,
19140    ) {
19141        self.insert_uuid(UuidVersion::V4, window, cx);
19142    }
19143
19144    pub fn insert_uuid_v7(
19145        &mut self,
19146        _: &InsertUuidV7,
19147        window: &mut Window,
19148        cx: &mut Context<Self>,
19149    ) {
19150        self.insert_uuid(UuidVersion::V7, window, cx);
19151    }
19152
19153    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19154        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19155        self.transact(window, cx, |this, window, cx| {
19156            let edits = this
19157                .selections
19158                .all::<Point>(cx)
19159                .into_iter()
19160                .map(|selection| {
19161                    let uuid = match version {
19162                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19163                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19164                    };
19165
19166                    (selection.range(), uuid.to_string())
19167                });
19168            this.edit(edits, cx);
19169            this.refresh_edit_prediction(true, false, window, cx);
19170        });
19171    }
19172
19173    pub fn open_selections_in_multibuffer(
19174        &mut self,
19175        _: &OpenSelectionsInMultibuffer,
19176        window: &mut Window,
19177        cx: &mut Context<Self>,
19178    ) {
19179        let multibuffer = self.buffer.read(cx);
19180
19181        let Some(buffer) = multibuffer.as_singleton() else {
19182            return;
19183        };
19184
19185        let Some(workspace) = self.workspace() else {
19186            return;
19187        };
19188
19189        let title = multibuffer.title(cx).to_string();
19190
19191        let locations = self
19192            .selections
19193            .all_anchors(cx)
19194            .iter()
19195            .map(|selection| Location {
19196                buffer: buffer.clone(),
19197                range: selection.start.text_anchor..selection.end.text_anchor,
19198            })
19199            .collect::<Vec<_>>();
19200
19201        cx.spawn_in(window, async move |_, cx| {
19202            workspace.update_in(cx, |workspace, window, cx| {
19203                Self::open_locations_in_multibuffer(
19204                    workspace,
19205                    locations,
19206                    format!("Selections for '{title}'"),
19207                    false,
19208                    MultibufferSelectionMode::All,
19209                    window,
19210                    cx,
19211                );
19212            })
19213        })
19214        .detach();
19215    }
19216
19217    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19218    /// last highlight added will be used.
19219    ///
19220    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19221    pub fn highlight_rows<T: 'static>(
19222        &mut self,
19223        range: Range<Anchor>,
19224        color: Hsla,
19225        options: RowHighlightOptions,
19226        cx: &mut Context<Self>,
19227    ) {
19228        let snapshot = self.buffer().read(cx).snapshot(cx);
19229        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19230        let ix = row_highlights.binary_search_by(|highlight| {
19231            Ordering::Equal
19232                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19233                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19234        });
19235
19236        if let Err(mut ix) = ix {
19237            let index = post_inc(&mut self.highlight_order);
19238
19239            // If this range intersects with the preceding highlight, then merge it with
19240            // the preceding highlight. Otherwise insert a new highlight.
19241            let mut merged = false;
19242            if ix > 0 {
19243                let prev_highlight = &mut row_highlights[ix - 1];
19244                if prev_highlight
19245                    .range
19246                    .end
19247                    .cmp(&range.start, &snapshot)
19248                    .is_ge()
19249                {
19250                    ix -= 1;
19251                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19252                        prev_highlight.range.end = range.end;
19253                    }
19254                    merged = true;
19255                    prev_highlight.index = index;
19256                    prev_highlight.color = color;
19257                    prev_highlight.options = options;
19258                }
19259            }
19260
19261            if !merged {
19262                row_highlights.insert(
19263                    ix,
19264                    RowHighlight {
19265                        range,
19266                        index,
19267                        color,
19268                        options,
19269                        type_id: TypeId::of::<T>(),
19270                    },
19271                );
19272            }
19273
19274            // If any of the following highlights intersect with this one, merge them.
19275            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19276                let highlight = &row_highlights[ix];
19277                if next_highlight
19278                    .range
19279                    .start
19280                    .cmp(&highlight.range.end, &snapshot)
19281                    .is_le()
19282                {
19283                    if next_highlight
19284                        .range
19285                        .end
19286                        .cmp(&highlight.range.end, &snapshot)
19287                        .is_gt()
19288                    {
19289                        row_highlights[ix].range.end = next_highlight.range.end;
19290                    }
19291                    row_highlights.remove(ix + 1);
19292                } else {
19293                    break;
19294                }
19295            }
19296        }
19297    }
19298
19299    /// Remove any highlighted row ranges of the given type that intersect the
19300    /// given ranges.
19301    pub fn remove_highlighted_rows<T: 'static>(
19302        &mut self,
19303        ranges_to_remove: Vec<Range<Anchor>>,
19304        cx: &mut Context<Self>,
19305    ) {
19306        let snapshot = self.buffer().read(cx).snapshot(cx);
19307        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19308        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19309        row_highlights.retain(|highlight| {
19310            while let Some(range_to_remove) = ranges_to_remove.peek() {
19311                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19312                    Ordering::Less | Ordering::Equal => {
19313                        ranges_to_remove.next();
19314                    }
19315                    Ordering::Greater => {
19316                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19317                            Ordering::Less | Ordering::Equal => {
19318                                return false;
19319                            }
19320                            Ordering::Greater => break,
19321                        }
19322                    }
19323                }
19324            }
19325
19326            true
19327        })
19328    }
19329
19330    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19331    pub fn clear_row_highlights<T: 'static>(&mut self) {
19332        self.highlighted_rows.remove(&TypeId::of::<T>());
19333    }
19334
19335    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19336    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19337        self.highlighted_rows
19338            .get(&TypeId::of::<T>())
19339            .map_or(&[] as &[_], |vec| vec.as_slice())
19340            .iter()
19341            .map(|highlight| (highlight.range.clone(), highlight.color))
19342    }
19343
19344    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19345    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19346    /// Allows to ignore certain kinds of highlights.
19347    pub fn highlighted_display_rows(
19348        &self,
19349        window: &mut Window,
19350        cx: &mut App,
19351    ) -> BTreeMap<DisplayRow, LineHighlight> {
19352        let snapshot = self.snapshot(window, cx);
19353        let mut used_highlight_orders = HashMap::default();
19354        self.highlighted_rows
19355            .iter()
19356            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19357            .fold(
19358                BTreeMap::<DisplayRow, LineHighlight>::new(),
19359                |mut unique_rows, highlight| {
19360                    let start = highlight.range.start.to_display_point(&snapshot);
19361                    let end = highlight.range.end.to_display_point(&snapshot);
19362                    let start_row = start.row().0;
19363                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19364                        && end.column() == 0
19365                    {
19366                        end.row().0.saturating_sub(1)
19367                    } else {
19368                        end.row().0
19369                    };
19370                    for row in start_row..=end_row {
19371                        let used_index =
19372                            used_highlight_orders.entry(row).or_insert(highlight.index);
19373                        if highlight.index >= *used_index {
19374                            *used_index = highlight.index;
19375                            unique_rows.insert(
19376                                DisplayRow(row),
19377                                LineHighlight {
19378                                    include_gutter: highlight.options.include_gutter,
19379                                    border: None,
19380                                    background: highlight.color.into(),
19381                                    type_id: Some(highlight.type_id),
19382                                },
19383                            );
19384                        }
19385                    }
19386                    unique_rows
19387                },
19388            )
19389    }
19390
19391    pub fn highlighted_display_row_for_autoscroll(
19392        &self,
19393        snapshot: &DisplaySnapshot,
19394    ) -> Option<DisplayRow> {
19395        self.highlighted_rows
19396            .values()
19397            .flat_map(|highlighted_rows| highlighted_rows.iter())
19398            .filter_map(|highlight| {
19399                if highlight.options.autoscroll {
19400                    Some(highlight.range.start.to_display_point(snapshot).row())
19401                } else {
19402                    None
19403                }
19404            })
19405            .min()
19406    }
19407
19408    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19409        self.highlight_background::<SearchWithinRange>(
19410            ranges,
19411            |colors| colors.colors().editor_document_highlight_read_background,
19412            cx,
19413        )
19414    }
19415
19416    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19417        self.breadcrumb_header = Some(new_header);
19418    }
19419
19420    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19421        self.clear_background_highlights::<SearchWithinRange>(cx);
19422    }
19423
19424    pub fn highlight_background<T: 'static>(
19425        &mut self,
19426        ranges: &[Range<Anchor>],
19427        color_fetcher: fn(&Theme) -> Hsla,
19428        cx: &mut Context<Self>,
19429    ) {
19430        self.background_highlights.insert(
19431            HighlightKey::Type(TypeId::of::<T>()),
19432            (color_fetcher, Arc::from(ranges)),
19433        );
19434        self.scrollbar_marker_state.dirty = true;
19435        cx.notify();
19436    }
19437
19438    pub fn highlight_background_key<T: 'static>(
19439        &mut self,
19440        key: usize,
19441        ranges: &[Range<Anchor>],
19442        color_fetcher: fn(&Theme) -> Hsla,
19443        cx: &mut Context<Self>,
19444    ) {
19445        self.background_highlights.insert(
19446            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19447            (color_fetcher, Arc::from(ranges)),
19448        );
19449        self.scrollbar_marker_state.dirty = true;
19450        cx.notify();
19451    }
19452
19453    pub fn clear_background_highlights<T: 'static>(
19454        &mut self,
19455        cx: &mut Context<Self>,
19456    ) -> Option<BackgroundHighlight> {
19457        let text_highlights = self
19458            .background_highlights
19459            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19460        if !text_highlights.1.is_empty() {
19461            self.scrollbar_marker_state.dirty = true;
19462            cx.notify();
19463        }
19464        Some(text_highlights)
19465    }
19466
19467    pub fn highlight_gutter<T: 'static>(
19468        &mut self,
19469        ranges: impl Into<Vec<Range<Anchor>>>,
19470        color_fetcher: fn(&App) -> Hsla,
19471        cx: &mut Context<Self>,
19472    ) {
19473        self.gutter_highlights
19474            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19475        cx.notify();
19476    }
19477
19478    pub fn clear_gutter_highlights<T: 'static>(
19479        &mut self,
19480        cx: &mut Context<Self>,
19481    ) -> Option<GutterHighlight> {
19482        cx.notify();
19483        self.gutter_highlights.remove(&TypeId::of::<T>())
19484    }
19485
19486    pub fn insert_gutter_highlight<T: 'static>(
19487        &mut self,
19488        range: Range<Anchor>,
19489        color_fetcher: fn(&App) -> Hsla,
19490        cx: &mut Context<Self>,
19491    ) {
19492        let snapshot = self.buffer().read(cx).snapshot(cx);
19493        let mut highlights = self
19494            .gutter_highlights
19495            .remove(&TypeId::of::<T>())
19496            .map(|(_, highlights)| highlights)
19497            .unwrap_or_default();
19498        let ix = highlights.binary_search_by(|highlight| {
19499            Ordering::Equal
19500                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19501                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19502        });
19503        if let Err(ix) = ix {
19504            highlights.insert(ix, range);
19505        }
19506        self.gutter_highlights
19507            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19508    }
19509
19510    pub fn remove_gutter_highlights<T: 'static>(
19511        &mut self,
19512        ranges_to_remove: Vec<Range<Anchor>>,
19513        cx: &mut Context<Self>,
19514    ) {
19515        let snapshot = self.buffer().read(cx).snapshot(cx);
19516        let Some((color_fetcher, mut gutter_highlights)) =
19517            self.gutter_highlights.remove(&TypeId::of::<T>())
19518        else {
19519            return;
19520        };
19521        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19522        gutter_highlights.retain(|highlight| {
19523            while let Some(range_to_remove) = ranges_to_remove.peek() {
19524                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19525                    Ordering::Less | Ordering::Equal => {
19526                        ranges_to_remove.next();
19527                    }
19528                    Ordering::Greater => {
19529                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19530                            Ordering::Less | Ordering::Equal => {
19531                                return false;
19532                            }
19533                            Ordering::Greater => break,
19534                        }
19535                    }
19536                }
19537            }
19538
19539            true
19540        });
19541        self.gutter_highlights
19542            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19543    }
19544
19545    #[cfg(feature = "test-support")]
19546    pub fn all_text_highlights(
19547        &self,
19548        window: &mut Window,
19549        cx: &mut Context<Self>,
19550    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19551        let snapshot = self.snapshot(window, cx);
19552        self.display_map.update(cx, |display_map, _| {
19553            display_map
19554                .all_text_highlights()
19555                .map(|highlight| {
19556                    let (style, ranges) = highlight.as_ref();
19557                    (
19558                        *style,
19559                        ranges
19560                            .iter()
19561                            .map(|range| range.clone().to_display_points(&snapshot))
19562                            .collect(),
19563                    )
19564                })
19565                .collect()
19566        })
19567    }
19568
19569    #[cfg(feature = "test-support")]
19570    pub fn all_text_background_highlights(
19571        &self,
19572        window: &mut Window,
19573        cx: &mut Context<Self>,
19574    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19575        let snapshot = self.snapshot(window, cx);
19576        let buffer = &snapshot.buffer_snapshot;
19577        let start = buffer.anchor_before(0);
19578        let end = buffer.anchor_after(buffer.len());
19579        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19580    }
19581
19582    #[cfg(feature = "test-support")]
19583    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19584        let snapshot = self.buffer().read(cx).snapshot(cx);
19585
19586        let highlights = self
19587            .background_highlights
19588            .get(&HighlightKey::Type(TypeId::of::<
19589                items::BufferSearchHighlights,
19590            >()));
19591
19592        if let Some((_color, ranges)) = highlights {
19593            ranges
19594                .iter()
19595                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19596                .collect_vec()
19597        } else {
19598            vec![]
19599        }
19600    }
19601
19602    fn document_highlights_for_position<'a>(
19603        &'a self,
19604        position: Anchor,
19605        buffer: &'a MultiBufferSnapshot,
19606    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19607        let read_highlights = self
19608            .background_highlights
19609            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19610            .map(|h| &h.1);
19611        let write_highlights = self
19612            .background_highlights
19613            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19614            .map(|h| &h.1);
19615        let left_position = position.bias_left(buffer);
19616        let right_position = position.bias_right(buffer);
19617        read_highlights
19618            .into_iter()
19619            .chain(write_highlights)
19620            .flat_map(move |ranges| {
19621                let start_ix = match ranges.binary_search_by(|probe| {
19622                    let cmp = probe.end.cmp(&left_position, buffer);
19623                    if cmp.is_ge() {
19624                        Ordering::Greater
19625                    } else {
19626                        Ordering::Less
19627                    }
19628                }) {
19629                    Ok(i) | Err(i) => i,
19630                };
19631
19632                ranges[start_ix..]
19633                    .iter()
19634                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19635            })
19636    }
19637
19638    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19639        self.background_highlights
19640            .get(&HighlightKey::Type(TypeId::of::<T>()))
19641            .is_some_and(|(_, highlights)| !highlights.is_empty())
19642    }
19643
19644    pub fn background_highlights_in_range(
19645        &self,
19646        search_range: Range<Anchor>,
19647        display_snapshot: &DisplaySnapshot,
19648        theme: &Theme,
19649    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19650        let mut results = Vec::new();
19651        for (color_fetcher, ranges) in self.background_highlights.values() {
19652            let color = color_fetcher(theme);
19653            let start_ix = match ranges.binary_search_by(|probe| {
19654                let cmp = probe
19655                    .end
19656                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19657                if cmp.is_gt() {
19658                    Ordering::Greater
19659                } else {
19660                    Ordering::Less
19661                }
19662            }) {
19663                Ok(i) | Err(i) => i,
19664            };
19665            for range in &ranges[start_ix..] {
19666                if range
19667                    .start
19668                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19669                    .is_ge()
19670                {
19671                    break;
19672                }
19673
19674                let start = range.start.to_display_point(display_snapshot);
19675                let end = range.end.to_display_point(display_snapshot);
19676                results.push((start..end, color))
19677            }
19678        }
19679        results
19680    }
19681
19682    pub fn background_highlight_row_ranges<T: 'static>(
19683        &self,
19684        search_range: Range<Anchor>,
19685        display_snapshot: &DisplaySnapshot,
19686        count: usize,
19687    ) -> Vec<RangeInclusive<DisplayPoint>> {
19688        let mut results = Vec::new();
19689        let Some((_, ranges)) = self
19690            .background_highlights
19691            .get(&HighlightKey::Type(TypeId::of::<T>()))
19692        else {
19693            return vec![];
19694        };
19695
19696        let start_ix = match ranges.binary_search_by(|probe| {
19697            let cmp = probe
19698                .end
19699                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19700            if cmp.is_gt() {
19701                Ordering::Greater
19702            } else {
19703                Ordering::Less
19704            }
19705        }) {
19706            Ok(i) | Err(i) => i,
19707        };
19708        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19709            if let (Some(start_display), Some(end_display)) = (start, end) {
19710                results.push(
19711                    start_display.to_display_point(display_snapshot)
19712                        ..=end_display.to_display_point(display_snapshot),
19713                );
19714            }
19715        };
19716        let mut start_row: Option<Point> = None;
19717        let mut end_row: Option<Point> = None;
19718        if ranges.len() > count {
19719            return Vec::new();
19720        }
19721        for range in &ranges[start_ix..] {
19722            if range
19723                .start
19724                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19725                .is_ge()
19726            {
19727                break;
19728            }
19729            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19730            if let Some(current_row) = &end_row
19731                && end.row == current_row.row
19732            {
19733                continue;
19734            }
19735            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19736            if start_row.is_none() {
19737                assert_eq!(end_row, None);
19738                start_row = Some(start);
19739                end_row = Some(end);
19740                continue;
19741            }
19742            if let Some(current_end) = end_row.as_mut() {
19743                if start.row > current_end.row + 1 {
19744                    push_region(start_row, end_row);
19745                    start_row = Some(start);
19746                    end_row = Some(end);
19747                } else {
19748                    // Merge two hunks.
19749                    *current_end = end;
19750                }
19751            } else {
19752                unreachable!();
19753            }
19754        }
19755        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19756        push_region(start_row, end_row);
19757        results
19758    }
19759
19760    pub fn gutter_highlights_in_range(
19761        &self,
19762        search_range: Range<Anchor>,
19763        display_snapshot: &DisplaySnapshot,
19764        cx: &App,
19765    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19766        let mut results = Vec::new();
19767        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19768            let color = color_fetcher(cx);
19769            let start_ix = match ranges.binary_search_by(|probe| {
19770                let cmp = probe
19771                    .end
19772                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19773                if cmp.is_gt() {
19774                    Ordering::Greater
19775                } else {
19776                    Ordering::Less
19777                }
19778            }) {
19779                Ok(i) | Err(i) => i,
19780            };
19781            for range in &ranges[start_ix..] {
19782                if range
19783                    .start
19784                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19785                    .is_ge()
19786                {
19787                    break;
19788                }
19789
19790                let start = range.start.to_display_point(display_snapshot);
19791                let end = range.end.to_display_point(display_snapshot);
19792                results.push((start..end, color))
19793            }
19794        }
19795        results
19796    }
19797
19798    /// Get the text ranges corresponding to the redaction query
19799    pub fn redacted_ranges(
19800        &self,
19801        search_range: Range<Anchor>,
19802        display_snapshot: &DisplaySnapshot,
19803        cx: &App,
19804    ) -> Vec<Range<DisplayPoint>> {
19805        display_snapshot
19806            .buffer_snapshot
19807            .redacted_ranges(search_range, |file| {
19808                if let Some(file) = file {
19809                    file.is_private()
19810                        && EditorSettings::get(
19811                            Some(SettingsLocation {
19812                                worktree_id: file.worktree_id(cx),
19813                                path: file.path().as_ref(),
19814                            }),
19815                            cx,
19816                        )
19817                        .redact_private_values
19818                } else {
19819                    false
19820                }
19821            })
19822            .map(|range| {
19823                range.start.to_display_point(display_snapshot)
19824                    ..range.end.to_display_point(display_snapshot)
19825            })
19826            .collect()
19827    }
19828
19829    pub fn highlight_text_key<T: 'static>(
19830        &mut self,
19831        key: usize,
19832        ranges: Vec<Range<Anchor>>,
19833        style: HighlightStyle,
19834        cx: &mut Context<Self>,
19835    ) {
19836        self.display_map.update(cx, |map, _| {
19837            map.highlight_text(
19838                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19839                ranges,
19840                style,
19841            );
19842        });
19843        cx.notify();
19844    }
19845
19846    pub fn highlight_text<T: 'static>(
19847        &mut self,
19848        ranges: Vec<Range<Anchor>>,
19849        style: HighlightStyle,
19850        cx: &mut Context<Self>,
19851    ) {
19852        self.display_map.update(cx, |map, _| {
19853            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19854        });
19855        cx.notify();
19856    }
19857
19858    pub(crate) fn highlight_inlays<T: 'static>(
19859        &mut self,
19860        highlights: Vec<InlayHighlight>,
19861        style: HighlightStyle,
19862        cx: &mut Context<Self>,
19863    ) {
19864        self.display_map.update(cx, |map, _| {
19865            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19866        });
19867        cx.notify();
19868    }
19869
19870    pub fn text_highlights<'a, T: 'static>(
19871        &'a self,
19872        cx: &'a App,
19873    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19874        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19875    }
19876
19877    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19878        let cleared = self
19879            .display_map
19880            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19881        if cleared {
19882            cx.notify();
19883        }
19884    }
19885
19886    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19887        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19888            && self.focus_handle.is_focused(window)
19889    }
19890
19891    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19892        self.show_cursor_when_unfocused = is_enabled;
19893        cx.notify();
19894    }
19895
19896    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19897        cx.notify();
19898    }
19899
19900    fn on_debug_session_event(
19901        &mut self,
19902        _session: Entity<Session>,
19903        event: &SessionEvent,
19904        cx: &mut Context<Self>,
19905    ) {
19906        if let SessionEvent::InvalidateInlineValue = event {
19907            self.refresh_inline_values(cx);
19908        }
19909    }
19910
19911    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19912        let Some(project) = self.project.clone() else {
19913            return;
19914        };
19915
19916        if !self.inline_value_cache.enabled {
19917            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19918            self.splice_inlays(&inlays, Vec::new(), cx);
19919            return;
19920        }
19921
19922        let current_execution_position = self
19923            .highlighted_rows
19924            .get(&TypeId::of::<ActiveDebugLine>())
19925            .and_then(|lines| lines.last().map(|line| line.range.end));
19926
19927        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19928            let inline_values = editor
19929                .update(cx, |editor, cx| {
19930                    let Some(current_execution_position) = current_execution_position else {
19931                        return Some(Task::ready(Ok(Vec::new())));
19932                    };
19933
19934                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19935                        let snapshot = buffer.snapshot(cx);
19936
19937                        let excerpt = snapshot.excerpt_containing(
19938                            current_execution_position..current_execution_position,
19939                        )?;
19940
19941                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19942                    })?;
19943
19944                    let range =
19945                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19946
19947                    project.inline_values(buffer, range, cx)
19948                })
19949                .ok()
19950                .flatten()?
19951                .await
19952                .context("refreshing debugger inlays")
19953                .log_err()?;
19954
19955            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19956
19957            for (buffer_id, inline_value) in inline_values
19958                .into_iter()
19959                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19960            {
19961                buffer_inline_values
19962                    .entry(buffer_id)
19963                    .or_default()
19964                    .push(inline_value);
19965            }
19966
19967            editor
19968                .update(cx, |editor, cx| {
19969                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19970                    let mut new_inlays = Vec::default();
19971
19972                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19973                        let buffer_id = buffer_snapshot.remote_id();
19974                        buffer_inline_values
19975                            .get(&buffer_id)
19976                            .into_iter()
19977                            .flatten()
19978                            .for_each(|hint| {
19979                                let inlay = Inlay::debugger(
19980                                    post_inc(&mut editor.next_inlay_id),
19981                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19982                                    hint.text(),
19983                                );
19984                                if !inlay.text.chars().contains(&'\n') {
19985                                    new_inlays.push(inlay);
19986                                }
19987                            });
19988                    }
19989
19990                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19991                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19992
19993                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19994                })
19995                .ok()?;
19996            Some(())
19997        });
19998    }
19999
20000    fn on_buffer_event(
20001        &mut self,
20002        multibuffer: &Entity<MultiBuffer>,
20003        event: &multi_buffer::Event,
20004        window: &mut Window,
20005        cx: &mut Context<Self>,
20006    ) {
20007        match event {
20008            multi_buffer::Event::Edited {
20009                singleton_buffer_edited,
20010                edited_buffer,
20011            } => {
20012                self.scrollbar_marker_state.dirty = true;
20013                self.active_indent_guides_state.dirty = true;
20014                self.refresh_active_diagnostics(cx);
20015                self.refresh_code_actions(window, cx);
20016                self.refresh_selected_text_highlights(true, window, cx);
20017                self.refresh_single_line_folds(window, cx);
20018                refresh_matching_bracket_highlights(self, window, cx);
20019                if self.has_active_edit_prediction() {
20020                    self.update_visible_edit_prediction(window, cx);
20021                }
20022                if let Some(project) = self.project.as_ref()
20023                    && let Some(edited_buffer) = edited_buffer
20024                {
20025                    project.update(cx, |project, cx| {
20026                        self.registered_buffers
20027                            .entry(edited_buffer.read(cx).remote_id())
20028                            .or_insert_with(|| {
20029                                project.register_buffer_with_language_servers(edited_buffer, cx)
20030                            });
20031                    });
20032                }
20033                cx.emit(EditorEvent::BufferEdited);
20034                cx.emit(SearchEvent::MatchesInvalidated);
20035
20036                if let Some(buffer) = edited_buffer {
20037                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20038                }
20039
20040                if *singleton_buffer_edited {
20041                    if let Some(buffer) = edited_buffer
20042                        && buffer.read(cx).file().is_none()
20043                    {
20044                        cx.emit(EditorEvent::TitleChanged);
20045                    }
20046                    if let Some(project) = &self.project {
20047                        #[allow(clippy::mutable_key_type)]
20048                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20049                            multibuffer
20050                                .all_buffers()
20051                                .into_iter()
20052                                .filter_map(|buffer| {
20053                                    buffer.update(cx, |buffer, cx| {
20054                                        let language = buffer.language()?;
20055                                        let should_discard = project.update(cx, |project, cx| {
20056                                            project.is_local()
20057                                                && !project.has_language_servers_for(buffer, cx)
20058                                        });
20059                                        should_discard.not().then_some(language.clone())
20060                                    })
20061                                })
20062                                .collect::<HashSet<_>>()
20063                        });
20064                        if !languages_affected.is_empty() {
20065                            self.refresh_inlay_hints(
20066                                InlayHintRefreshReason::BufferEdited(languages_affected),
20067                                cx,
20068                            );
20069                        }
20070                    }
20071                }
20072
20073                let Some(project) = &self.project else { return };
20074                let (telemetry, is_via_ssh) = {
20075                    let project = project.read(cx);
20076                    let telemetry = project.client().telemetry().clone();
20077                    let is_via_ssh = project.is_via_ssh();
20078                    (telemetry, is_via_ssh)
20079                };
20080                refresh_linked_ranges(self, window, cx);
20081                telemetry.log_edit_event("editor", is_via_ssh);
20082            }
20083            multi_buffer::Event::ExcerptsAdded {
20084                buffer,
20085                predecessor,
20086                excerpts,
20087            } => {
20088                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20089                let buffer_id = buffer.read(cx).remote_id();
20090                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20091                    && let Some(project) = &self.project
20092                {
20093                    update_uncommitted_diff_for_buffer(
20094                        cx.entity(),
20095                        project,
20096                        [buffer.clone()],
20097                        self.buffer.clone(),
20098                        cx,
20099                    )
20100                    .detach();
20101                }
20102                self.update_lsp_data(false, Some(buffer_id), window, cx);
20103                cx.emit(EditorEvent::ExcerptsAdded {
20104                    buffer: buffer.clone(),
20105                    predecessor: *predecessor,
20106                    excerpts: excerpts.clone(),
20107                });
20108                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20109            }
20110            multi_buffer::Event::ExcerptsRemoved {
20111                ids,
20112                removed_buffer_ids,
20113            } => {
20114                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20115                let buffer = self.buffer.read(cx);
20116                self.registered_buffers
20117                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20118                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20119                cx.emit(EditorEvent::ExcerptsRemoved {
20120                    ids: ids.clone(),
20121                    removed_buffer_ids: removed_buffer_ids.clone(),
20122                });
20123            }
20124            multi_buffer::Event::ExcerptsEdited {
20125                excerpt_ids,
20126                buffer_ids,
20127            } => {
20128                self.display_map.update(cx, |map, cx| {
20129                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20130                });
20131                cx.emit(EditorEvent::ExcerptsEdited {
20132                    ids: excerpt_ids.clone(),
20133                });
20134            }
20135            multi_buffer::Event::ExcerptsExpanded { ids } => {
20136                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20137                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20138            }
20139            multi_buffer::Event::Reparsed(buffer_id) => {
20140                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20141                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20142
20143                cx.emit(EditorEvent::Reparsed(*buffer_id));
20144            }
20145            multi_buffer::Event::DiffHunksToggled => {
20146                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20147            }
20148            multi_buffer::Event::LanguageChanged(buffer_id) => {
20149                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20150                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20151                cx.emit(EditorEvent::Reparsed(*buffer_id));
20152                cx.notify();
20153            }
20154            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20155            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20156            multi_buffer::Event::FileHandleChanged
20157            | multi_buffer::Event::Reloaded
20158            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20159            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20160            multi_buffer::Event::DiagnosticsUpdated => {
20161                self.update_diagnostics_state(window, cx);
20162            }
20163            _ => {}
20164        };
20165    }
20166
20167    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20168        if !self.diagnostics_enabled() {
20169            return;
20170        }
20171        self.refresh_active_diagnostics(cx);
20172        self.refresh_inline_diagnostics(true, window, cx);
20173        self.scrollbar_marker_state.dirty = true;
20174        cx.notify();
20175    }
20176
20177    pub fn start_temporary_diff_override(&mut self) {
20178        self.load_diff_task.take();
20179        self.temporary_diff_override = true;
20180    }
20181
20182    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20183        self.temporary_diff_override = false;
20184        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20185        self.buffer.update(cx, |buffer, cx| {
20186            buffer.set_all_diff_hunks_collapsed(cx);
20187        });
20188
20189        if let Some(project) = self.project.clone() {
20190            self.load_diff_task = Some(
20191                update_uncommitted_diff_for_buffer(
20192                    cx.entity(),
20193                    &project,
20194                    self.buffer.read(cx).all_buffers(),
20195                    self.buffer.clone(),
20196                    cx,
20197                )
20198                .shared(),
20199            );
20200        }
20201    }
20202
20203    fn on_display_map_changed(
20204        &mut self,
20205        _: Entity<DisplayMap>,
20206        _: &mut Window,
20207        cx: &mut Context<Self>,
20208    ) {
20209        cx.notify();
20210    }
20211
20212    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20213        if self.diagnostics_enabled() {
20214            let new_severity = EditorSettings::get_global(cx)
20215                .diagnostics_max_severity
20216                .unwrap_or(DiagnosticSeverity::Hint);
20217            self.set_max_diagnostics_severity(new_severity, cx);
20218        }
20219        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20220        self.update_edit_prediction_settings(cx);
20221        self.refresh_edit_prediction(true, false, window, cx);
20222        self.refresh_inline_values(cx);
20223        self.refresh_inlay_hints(
20224            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20225                self.selections.newest_anchor().head(),
20226                &self.buffer.read(cx).snapshot(cx),
20227                cx,
20228            )),
20229            cx,
20230        );
20231
20232        let old_cursor_shape = self.cursor_shape;
20233        let old_show_breadcrumbs = self.show_breadcrumbs;
20234
20235        {
20236            let editor_settings = EditorSettings::get_global(cx);
20237            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20238            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20239            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20240            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20241        }
20242
20243        if old_cursor_shape != self.cursor_shape {
20244            cx.emit(EditorEvent::CursorShapeChanged);
20245        }
20246
20247        if old_show_breadcrumbs != self.show_breadcrumbs {
20248            cx.emit(EditorEvent::BreadcrumbsChanged);
20249        }
20250
20251        let project_settings = ProjectSettings::get_global(cx);
20252        self.serialize_dirty_buffers =
20253            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20254
20255        if self.mode.is_full() {
20256            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20257            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20258            if self.show_inline_diagnostics != show_inline_diagnostics {
20259                self.show_inline_diagnostics = show_inline_diagnostics;
20260                self.refresh_inline_diagnostics(false, window, cx);
20261            }
20262
20263            if self.git_blame_inline_enabled != inline_blame_enabled {
20264                self.toggle_git_blame_inline_internal(false, window, cx);
20265            }
20266
20267            let minimap_settings = EditorSettings::get_global(cx).minimap;
20268            if self.minimap_visibility != MinimapVisibility::Disabled {
20269                if self.minimap_visibility.settings_visibility()
20270                    != minimap_settings.minimap_enabled()
20271                {
20272                    self.set_minimap_visibility(
20273                        MinimapVisibility::for_mode(self.mode(), cx),
20274                        window,
20275                        cx,
20276                    );
20277                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20278                    minimap_entity.update(cx, |minimap_editor, cx| {
20279                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20280                    })
20281                }
20282            }
20283        }
20284
20285        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20286            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20287        }) {
20288            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20289                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20290            }
20291            self.refresh_colors(false, None, window, cx);
20292        }
20293
20294        cx.notify();
20295    }
20296
20297    pub fn set_searchable(&mut self, searchable: bool) {
20298        self.searchable = searchable;
20299    }
20300
20301    pub fn searchable(&self) -> bool {
20302        self.searchable
20303    }
20304
20305    fn open_proposed_changes_editor(
20306        &mut self,
20307        _: &OpenProposedChangesEditor,
20308        window: &mut Window,
20309        cx: &mut Context<Self>,
20310    ) {
20311        let Some(workspace) = self.workspace() else {
20312            cx.propagate();
20313            return;
20314        };
20315
20316        let selections = self.selections.all::<usize>(cx);
20317        let multi_buffer = self.buffer.read(cx);
20318        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20319        let mut new_selections_by_buffer = HashMap::default();
20320        for selection in selections {
20321            for (buffer, range, _) in
20322                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20323            {
20324                let mut range = range.to_point(buffer);
20325                range.start.column = 0;
20326                range.end.column = buffer.line_len(range.end.row);
20327                new_selections_by_buffer
20328                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20329                    .or_insert(Vec::new())
20330                    .push(range)
20331            }
20332        }
20333
20334        let proposed_changes_buffers = new_selections_by_buffer
20335            .into_iter()
20336            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20337            .collect::<Vec<_>>();
20338        let proposed_changes_editor = cx.new(|cx| {
20339            ProposedChangesEditor::new(
20340                "Proposed changes",
20341                proposed_changes_buffers,
20342                self.project.clone(),
20343                window,
20344                cx,
20345            )
20346        });
20347
20348        window.defer(cx, move |window, cx| {
20349            workspace.update(cx, |workspace, cx| {
20350                workspace.active_pane().update(cx, |pane, cx| {
20351                    pane.add_item(
20352                        Box::new(proposed_changes_editor),
20353                        true,
20354                        true,
20355                        None,
20356                        window,
20357                        cx,
20358                    );
20359                });
20360            });
20361        });
20362    }
20363
20364    pub fn open_excerpts_in_split(
20365        &mut self,
20366        _: &OpenExcerptsSplit,
20367        window: &mut Window,
20368        cx: &mut Context<Self>,
20369    ) {
20370        self.open_excerpts_common(None, true, window, cx)
20371    }
20372
20373    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20374        self.open_excerpts_common(None, false, window, cx)
20375    }
20376
20377    fn open_excerpts_common(
20378        &mut self,
20379        jump_data: Option<JumpData>,
20380        split: bool,
20381        window: &mut Window,
20382        cx: &mut Context<Self>,
20383    ) {
20384        let Some(workspace) = self.workspace() else {
20385            cx.propagate();
20386            return;
20387        };
20388
20389        if self.buffer.read(cx).is_singleton() {
20390            cx.propagate();
20391            return;
20392        }
20393
20394        let mut new_selections_by_buffer = HashMap::default();
20395        match &jump_data {
20396            Some(JumpData::MultiBufferPoint {
20397                excerpt_id,
20398                position,
20399                anchor,
20400                line_offset_from_top,
20401            }) => {
20402                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20403                if let Some(buffer) = multi_buffer_snapshot
20404                    .buffer_id_for_excerpt(*excerpt_id)
20405                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20406                {
20407                    let buffer_snapshot = buffer.read(cx).snapshot();
20408                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20409                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20410                    } else {
20411                        buffer_snapshot.clip_point(*position, Bias::Left)
20412                    };
20413                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20414                    new_selections_by_buffer.insert(
20415                        buffer,
20416                        (
20417                            vec![jump_to_offset..jump_to_offset],
20418                            Some(*line_offset_from_top),
20419                        ),
20420                    );
20421                }
20422            }
20423            Some(JumpData::MultiBufferRow {
20424                row,
20425                line_offset_from_top,
20426            }) => {
20427                let point = MultiBufferPoint::new(row.0, 0);
20428                if let Some((buffer, buffer_point, _)) =
20429                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20430                {
20431                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20432                    new_selections_by_buffer
20433                        .entry(buffer)
20434                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20435                        .0
20436                        .push(buffer_offset..buffer_offset)
20437                }
20438            }
20439            None => {
20440                let selections = self.selections.all::<usize>(cx);
20441                let multi_buffer = self.buffer.read(cx);
20442                for selection in selections {
20443                    for (snapshot, range, _, anchor) in multi_buffer
20444                        .snapshot(cx)
20445                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20446                    {
20447                        if let Some(anchor) = anchor {
20448                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20449                            else {
20450                                continue;
20451                            };
20452                            let offset = text::ToOffset::to_offset(
20453                                &anchor.text_anchor,
20454                                &buffer_handle.read(cx).snapshot(),
20455                            );
20456                            let range = offset..offset;
20457                            new_selections_by_buffer
20458                                .entry(buffer_handle)
20459                                .or_insert((Vec::new(), None))
20460                                .0
20461                                .push(range)
20462                        } else {
20463                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20464                            else {
20465                                continue;
20466                            };
20467                            new_selections_by_buffer
20468                                .entry(buffer_handle)
20469                                .or_insert((Vec::new(), None))
20470                                .0
20471                                .push(range)
20472                        }
20473                    }
20474                }
20475            }
20476        }
20477
20478        new_selections_by_buffer
20479            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20480
20481        if new_selections_by_buffer.is_empty() {
20482            return;
20483        }
20484
20485        // We defer the pane interaction because we ourselves are a workspace item
20486        // and activating a new item causes the pane to call a method on us reentrantly,
20487        // which panics if we're on the stack.
20488        window.defer(cx, move |window, cx| {
20489            workspace.update(cx, |workspace, cx| {
20490                let pane = if split {
20491                    workspace.adjacent_pane(window, cx)
20492                } else {
20493                    workspace.active_pane().clone()
20494                };
20495
20496                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20497                    let editor = buffer
20498                        .read(cx)
20499                        .file()
20500                        .is_none()
20501                        .then(|| {
20502                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20503                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20504                            // Instead, we try to activate the existing editor in the pane first.
20505                            let (editor, pane_item_index) =
20506                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20507                                    let editor = item.downcast::<Editor>()?;
20508                                    let singleton_buffer =
20509                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20510                                    if singleton_buffer == buffer {
20511                                        Some((editor, i))
20512                                    } else {
20513                                        None
20514                                    }
20515                                })?;
20516                            pane.update(cx, |pane, cx| {
20517                                pane.activate_item(pane_item_index, true, true, window, cx)
20518                            });
20519                            Some(editor)
20520                        })
20521                        .flatten()
20522                        .unwrap_or_else(|| {
20523                            workspace.open_project_item::<Self>(
20524                                pane.clone(),
20525                                buffer,
20526                                true,
20527                                true,
20528                                window,
20529                                cx,
20530                            )
20531                        });
20532
20533                    editor.update(cx, |editor, cx| {
20534                        let autoscroll = match scroll_offset {
20535                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20536                            None => Autoscroll::newest(),
20537                        };
20538                        let nav_history = editor.nav_history.take();
20539                        editor.change_selections(
20540                            SelectionEffects::scroll(autoscroll),
20541                            window,
20542                            cx,
20543                            |s| {
20544                                s.select_ranges(ranges);
20545                            },
20546                        );
20547                        editor.nav_history = nav_history;
20548                    });
20549                }
20550            })
20551        });
20552    }
20553
20554    // For now, don't allow opening excerpts in buffers that aren't backed by
20555    // regular project files.
20556    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20557        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20558    }
20559
20560    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20561        let snapshot = self.buffer.read(cx).read(cx);
20562        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20563        Some(
20564            ranges
20565                .iter()
20566                .map(move |range| {
20567                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20568                })
20569                .collect(),
20570        )
20571    }
20572
20573    fn selection_replacement_ranges(
20574        &self,
20575        range: Range<OffsetUtf16>,
20576        cx: &mut App,
20577    ) -> Vec<Range<OffsetUtf16>> {
20578        let selections = self.selections.all::<OffsetUtf16>(cx);
20579        let newest_selection = selections
20580            .iter()
20581            .max_by_key(|selection| selection.id)
20582            .unwrap();
20583        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20584        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20585        let snapshot = self.buffer.read(cx).read(cx);
20586        selections
20587            .into_iter()
20588            .map(|mut selection| {
20589                selection.start.0 =
20590                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20591                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20592                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20593                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20594            })
20595            .collect()
20596    }
20597
20598    fn report_editor_event(
20599        &self,
20600        reported_event: ReportEditorEvent,
20601        file_extension: Option<String>,
20602        cx: &App,
20603    ) {
20604        if cfg!(any(test, feature = "test-support")) {
20605            return;
20606        }
20607
20608        let Some(project) = &self.project else { return };
20609
20610        // If None, we are in a file without an extension
20611        let file = self
20612            .buffer
20613            .read(cx)
20614            .as_singleton()
20615            .and_then(|b| b.read(cx).file());
20616        let file_extension = file_extension.or(file
20617            .as_ref()
20618            .and_then(|file| Path::new(file.file_name(cx)).extension())
20619            .and_then(|e| e.to_str())
20620            .map(|a| a.to_string()));
20621
20622        let vim_mode = vim_enabled(cx);
20623
20624        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20625        let copilot_enabled = edit_predictions_provider
20626            == language::language_settings::EditPredictionProvider::Copilot;
20627        let copilot_enabled_for_language = self
20628            .buffer
20629            .read(cx)
20630            .language_settings(cx)
20631            .show_edit_predictions;
20632
20633        let project = project.read(cx);
20634        let event_type = reported_event.event_type();
20635
20636        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20637            telemetry::event!(
20638                event_type,
20639                type = if auto_saved {"autosave"} else {"manual"},
20640                file_extension,
20641                vim_mode,
20642                copilot_enabled,
20643                copilot_enabled_for_language,
20644                edit_predictions_provider,
20645                is_via_ssh = project.is_via_ssh(),
20646            );
20647        } else {
20648            telemetry::event!(
20649                event_type,
20650                file_extension,
20651                vim_mode,
20652                copilot_enabled,
20653                copilot_enabled_for_language,
20654                edit_predictions_provider,
20655                is_via_ssh = project.is_via_ssh(),
20656            );
20657        };
20658    }
20659
20660    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20661    /// with each line being an array of {text, highlight} objects.
20662    fn copy_highlight_json(
20663        &mut self,
20664        _: &CopyHighlightJson,
20665        window: &mut Window,
20666        cx: &mut Context<Self>,
20667    ) {
20668        #[derive(Serialize)]
20669        struct Chunk<'a> {
20670            text: String,
20671            highlight: Option<&'a str>,
20672        }
20673
20674        let snapshot = self.buffer.read(cx).snapshot(cx);
20675        let range = self
20676            .selected_text_range(false, window, cx)
20677            .and_then(|selection| {
20678                if selection.range.is_empty() {
20679                    None
20680                } else {
20681                    Some(selection.range)
20682                }
20683            })
20684            .unwrap_or_else(|| 0..snapshot.len());
20685
20686        let chunks = snapshot.chunks(range, true);
20687        let mut lines = Vec::new();
20688        let mut line: VecDeque<Chunk> = VecDeque::new();
20689
20690        let Some(style) = self.style.as_ref() else {
20691            return;
20692        };
20693
20694        for chunk in chunks {
20695            let highlight = chunk
20696                .syntax_highlight_id
20697                .and_then(|id| id.name(&style.syntax));
20698            let mut chunk_lines = chunk.text.split('\n').peekable();
20699            while let Some(text) = chunk_lines.next() {
20700                let mut merged_with_last_token = false;
20701                if let Some(last_token) = line.back_mut()
20702                    && last_token.highlight == highlight
20703                {
20704                    last_token.text.push_str(text);
20705                    merged_with_last_token = true;
20706                }
20707
20708                if !merged_with_last_token {
20709                    line.push_back(Chunk {
20710                        text: text.into(),
20711                        highlight,
20712                    });
20713                }
20714
20715                if chunk_lines.peek().is_some() {
20716                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20717                        line.pop_front();
20718                    }
20719                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20720                        line.pop_back();
20721                    }
20722
20723                    lines.push(mem::take(&mut line));
20724                }
20725            }
20726        }
20727
20728        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20729            return;
20730        };
20731        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20732    }
20733
20734    pub fn open_context_menu(
20735        &mut self,
20736        _: &OpenContextMenu,
20737        window: &mut Window,
20738        cx: &mut Context<Self>,
20739    ) {
20740        self.request_autoscroll(Autoscroll::newest(), cx);
20741        let position = self.selections.newest_display(cx).start;
20742        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20743    }
20744
20745    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20746        &self.inlay_hint_cache
20747    }
20748
20749    pub fn replay_insert_event(
20750        &mut self,
20751        text: &str,
20752        relative_utf16_range: Option<Range<isize>>,
20753        window: &mut Window,
20754        cx: &mut Context<Self>,
20755    ) {
20756        if !self.input_enabled {
20757            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20758            return;
20759        }
20760        if let Some(relative_utf16_range) = relative_utf16_range {
20761            let selections = self.selections.all::<OffsetUtf16>(cx);
20762            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20763                let new_ranges = selections.into_iter().map(|range| {
20764                    let start = OffsetUtf16(
20765                        range
20766                            .head()
20767                            .0
20768                            .saturating_add_signed(relative_utf16_range.start),
20769                    );
20770                    let end = OffsetUtf16(
20771                        range
20772                            .head()
20773                            .0
20774                            .saturating_add_signed(relative_utf16_range.end),
20775                    );
20776                    start..end
20777                });
20778                s.select_ranges(new_ranges);
20779            });
20780        }
20781
20782        self.handle_input(text, window, cx);
20783    }
20784
20785    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20786        let Some(provider) = self.semantics_provider.as_ref() else {
20787            return false;
20788        };
20789
20790        let mut supports = false;
20791        self.buffer().update(cx, |this, cx| {
20792            this.for_each_buffer(|buffer| {
20793                supports |= provider.supports_inlay_hints(buffer, cx);
20794            });
20795        });
20796
20797        supports
20798    }
20799
20800    pub fn is_focused(&self, window: &Window) -> bool {
20801        self.focus_handle.is_focused(window)
20802    }
20803
20804    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20805        cx.emit(EditorEvent::Focused);
20806
20807        if let Some(descendant) = self
20808            .last_focused_descendant
20809            .take()
20810            .and_then(|descendant| descendant.upgrade())
20811        {
20812            window.focus(&descendant);
20813        } else {
20814            if let Some(blame) = self.blame.as_ref() {
20815                blame.update(cx, GitBlame::focus)
20816            }
20817
20818            self.blink_manager.update(cx, BlinkManager::enable);
20819            self.show_cursor_names(window, cx);
20820            self.buffer.update(cx, |buffer, cx| {
20821                buffer.finalize_last_transaction(cx);
20822                if self.leader_id.is_none() {
20823                    buffer.set_active_selections(
20824                        &self.selections.disjoint_anchors(),
20825                        self.selections.line_mode,
20826                        self.cursor_shape,
20827                        cx,
20828                    );
20829                }
20830            });
20831        }
20832    }
20833
20834    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20835        cx.emit(EditorEvent::FocusedIn)
20836    }
20837
20838    fn handle_focus_out(
20839        &mut self,
20840        event: FocusOutEvent,
20841        _window: &mut Window,
20842        cx: &mut Context<Self>,
20843    ) {
20844        if event.blurred != self.focus_handle {
20845            self.last_focused_descendant = Some(event.blurred);
20846        }
20847        self.selection_drag_state = SelectionDragState::None;
20848        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20849    }
20850
20851    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20852        self.blink_manager.update(cx, BlinkManager::disable);
20853        self.buffer
20854            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20855
20856        if let Some(blame) = self.blame.as_ref() {
20857            blame.update(cx, GitBlame::blur)
20858        }
20859        if !self.hover_state.focused(window, cx) {
20860            hide_hover(self, cx);
20861        }
20862        if !self
20863            .context_menu
20864            .borrow()
20865            .as_ref()
20866            .is_some_and(|context_menu| context_menu.focused(window, cx))
20867        {
20868            self.hide_context_menu(window, cx);
20869        }
20870        self.discard_edit_prediction(false, cx);
20871        cx.emit(EditorEvent::Blurred);
20872        cx.notify();
20873    }
20874
20875    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20876        let mut pending: String = window
20877            .pending_input_keystrokes()
20878            .into_iter()
20879            .flatten()
20880            .filter_map(|keystroke| {
20881                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20882                    keystroke.key_char.clone()
20883                } else {
20884                    None
20885                }
20886            })
20887            .collect();
20888
20889        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20890            pending = "".to_string();
20891        }
20892
20893        let existing_pending = self
20894            .text_highlights::<PendingInput>(cx)
20895            .map(|(_, ranges)| ranges.to_vec());
20896        if existing_pending.is_none() && pending.is_empty() {
20897            return;
20898        }
20899        let transaction =
20900            self.transact(window, cx, |this, window, cx| {
20901                let selections = this.selections.all::<usize>(cx);
20902                let edits = selections
20903                    .iter()
20904                    .map(|selection| (selection.end..selection.end, pending.clone()));
20905                this.edit(edits, cx);
20906                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20907                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20908                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20909                    }));
20910                });
20911                if let Some(existing_ranges) = existing_pending {
20912                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20913                    this.edit(edits, cx);
20914                }
20915            });
20916
20917        let snapshot = self.snapshot(window, cx);
20918        let ranges = self
20919            .selections
20920            .all::<usize>(cx)
20921            .into_iter()
20922            .map(|selection| {
20923                snapshot.buffer_snapshot.anchor_after(selection.end)
20924                    ..snapshot
20925                        .buffer_snapshot
20926                        .anchor_before(selection.end + pending.len())
20927            })
20928            .collect();
20929
20930        if pending.is_empty() {
20931            self.clear_highlights::<PendingInput>(cx);
20932        } else {
20933            self.highlight_text::<PendingInput>(
20934                ranges,
20935                HighlightStyle {
20936                    underline: Some(UnderlineStyle {
20937                        thickness: px(1.),
20938                        color: None,
20939                        wavy: false,
20940                    }),
20941                    ..Default::default()
20942                },
20943                cx,
20944            );
20945        }
20946
20947        self.ime_transaction = self.ime_transaction.or(transaction);
20948        if let Some(transaction) = self.ime_transaction {
20949            self.buffer.update(cx, |buffer, cx| {
20950                buffer.group_until_transaction(transaction, cx);
20951            });
20952        }
20953
20954        if self.text_highlights::<PendingInput>(cx).is_none() {
20955            self.ime_transaction.take();
20956        }
20957    }
20958
20959    pub fn register_action_renderer(
20960        &mut self,
20961        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20962    ) -> Subscription {
20963        let id = self.next_editor_action_id.post_inc();
20964        self.editor_actions
20965            .borrow_mut()
20966            .insert(id, Box::new(listener));
20967
20968        let editor_actions = self.editor_actions.clone();
20969        Subscription::new(move || {
20970            editor_actions.borrow_mut().remove(&id);
20971        })
20972    }
20973
20974    pub fn register_action<A: Action>(
20975        &mut self,
20976        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20977    ) -> Subscription {
20978        let id = self.next_editor_action_id.post_inc();
20979        let listener = Arc::new(listener);
20980        self.editor_actions.borrow_mut().insert(
20981            id,
20982            Box::new(move |_, window, _| {
20983                let listener = listener.clone();
20984                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20985                    let action = action.downcast_ref().unwrap();
20986                    if phase == DispatchPhase::Bubble {
20987                        listener(action, window, cx)
20988                    }
20989                })
20990            }),
20991        );
20992
20993        let editor_actions = self.editor_actions.clone();
20994        Subscription::new(move || {
20995            editor_actions.borrow_mut().remove(&id);
20996        })
20997    }
20998
20999    pub fn file_header_size(&self) -> u32 {
21000        FILE_HEADER_HEIGHT
21001    }
21002
21003    pub fn restore(
21004        &mut self,
21005        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21006        window: &mut Window,
21007        cx: &mut Context<Self>,
21008    ) {
21009        let workspace = self.workspace();
21010        let project = self.project();
21011        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21012            let mut tasks = Vec::new();
21013            for (buffer_id, changes) in revert_changes {
21014                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21015                    buffer.update(cx, |buffer, cx| {
21016                        buffer.edit(
21017                            changes
21018                                .into_iter()
21019                                .map(|(range, text)| (range, text.to_string())),
21020                            None,
21021                            cx,
21022                        );
21023                    });
21024
21025                    if let Some(project) =
21026                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21027                    {
21028                        project.update(cx, |project, cx| {
21029                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21030                        })
21031                    }
21032                }
21033            }
21034            tasks
21035        });
21036        cx.spawn_in(window, async move |_, cx| {
21037            for (buffer, task) in save_tasks {
21038                let result = task.await;
21039                if result.is_err() {
21040                    let Some(path) = buffer
21041                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21042                        .ok()
21043                    else {
21044                        continue;
21045                    };
21046                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21047                        let Some(task) = cx
21048                            .update_window_entity(workspace, |workspace, window, cx| {
21049                                workspace
21050                                    .open_path_preview(path, None, false, false, false, window, cx)
21051                            })
21052                            .ok()
21053                        else {
21054                            continue;
21055                        };
21056                        task.await.log_err();
21057                    }
21058                }
21059            }
21060        })
21061        .detach();
21062        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21063            selections.refresh()
21064        });
21065    }
21066
21067    pub fn to_pixel_point(
21068        &self,
21069        source: multi_buffer::Anchor,
21070        editor_snapshot: &EditorSnapshot,
21071        window: &mut Window,
21072    ) -> Option<gpui::Point<Pixels>> {
21073        let source_point = source.to_display_point(editor_snapshot);
21074        self.display_to_pixel_point(source_point, editor_snapshot, window)
21075    }
21076
21077    pub fn display_to_pixel_point(
21078        &self,
21079        source: DisplayPoint,
21080        editor_snapshot: &EditorSnapshot,
21081        window: &mut Window,
21082    ) -> Option<gpui::Point<Pixels>> {
21083        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21084        let text_layout_details = self.text_layout_details(window);
21085        let scroll_top = text_layout_details
21086            .scroll_anchor
21087            .scroll_position(editor_snapshot)
21088            .y;
21089
21090        if source.row().as_f32() < scroll_top.floor() {
21091            return None;
21092        }
21093        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21094        let source_y = line_height * (source.row().as_f32() - scroll_top);
21095        Some(gpui::Point::new(source_x, source_y))
21096    }
21097
21098    pub fn has_visible_completions_menu(&self) -> bool {
21099        !self.edit_prediction_preview_is_active()
21100            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21101                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21102            })
21103    }
21104
21105    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21106        if self.mode.is_minimap() {
21107            return;
21108        }
21109        self.addons
21110            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21111    }
21112
21113    pub fn unregister_addon<T: Addon>(&mut self) {
21114        self.addons.remove(&std::any::TypeId::of::<T>());
21115    }
21116
21117    pub fn addon<T: Addon>(&self) -> Option<&T> {
21118        let type_id = std::any::TypeId::of::<T>();
21119        self.addons
21120            .get(&type_id)
21121            .and_then(|item| item.to_any().downcast_ref::<T>())
21122    }
21123
21124    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21125        let type_id = std::any::TypeId::of::<T>();
21126        self.addons
21127            .get_mut(&type_id)
21128            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21129    }
21130
21131    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21132        let text_layout_details = self.text_layout_details(window);
21133        let style = &text_layout_details.editor_style;
21134        let font_id = window.text_system().resolve_font(&style.text.font());
21135        let font_size = style.text.font_size.to_pixels(window.rem_size());
21136        let line_height = style.text.line_height_in_pixels(window.rem_size());
21137        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21138        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21139
21140        CharacterDimensions {
21141            em_width,
21142            em_advance,
21143            line_height,
21144        }
21145    }
21146
21147    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21148        self.load_diff_task.clone()
21149    }
21150
21151    fn read_metadata_from_db(
21152        &mut self,
21153        item_id: u64,
21154        workspace_id: WorkspaceId,
21155        window: &mut Window,
21156        cx: &mut Context<Editor>,
21157    ) {
21158        if self.is_singleton(cx)
21159            && !self.mode.is_minimap()
21160            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21161        {
21162            let buffer_snapshot = OnceCell::new();
21163
21164            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21165                && !folds.is_empty()
21166            {
21167                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21168                self.fold_ranges(
21169                    folds
21170                        .into_iter()
21171                        .map(|(start, end)| {
21172                            snapshot.clip_offset(start, Bias::Left)
21173                                ..snapshot.clip_offset(end, Bias::Right)
21174                        })
21175                        .collect(),
21176                    false,
21177                    window,
21178                    cx,
21179                );
21180            }
21181
21182            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21183                && !selections.is_empty()
21184            {
21185                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21186                // skip adding the initial selection to selection history
21187                self.selection_history.mode = SelectionHistoryMode::Skipping;
21188                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21189                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21190                        snapshot.clip_offset(start, Bias::Left)
21191                            ..snapshot.clip_offset(end, Bias::Right)
21192                    }));
21193                });
21194                self.selection_history.mode = SelectionHistoryMode::Normal;
21195            };
21196        }
21197
21198        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21199    }
21200
21201    fn update_lsp_data(
21202        &mut self,
21203        ignore_cache: bool,
21204        for_buffer: Option<BufferId>,
21205        window: &mut Window,
21206        cx: &mut Context<'_, Self>,
21207    ) {
21208        self.pull_diagnostics(for_buffer, window, cx);
21209        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21210    }
21211}
21212
21213fn vim_enabled(cx: &App) -> bool {
21214    cx.global::<SettingsStore>()
21215        .raw_user_settings()
21216        .get("vim_mode")
21217        == Some(&serde_json::Value::Bool(true))
21218}
21219
21220fn process_completion_for_edit(
21221    completion: &Completion,
21222    intent: CompletionIntent,
21223    buffer: &Entity<Buffer>,
21224    cursor_position: &text::Anchor,
21225    cx: &mut Context<Editor>,
21226) -> CompletionEdit {
21227    let buffer = buffer.read(cx);
21228    let buffer_snapshot = buffer.snapshot();
21229    let (snippet, new_text) = if completion.is_snippet() {
21230        // Workaround for typescript language server issues so that methods don't expand within
21231        // strings and functions with type expressions. The previous point is used because the query
21232        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21233        let mut snippet_source = completion.new_text.clone();
21234        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21235        previous_point.column = previous_point.column.saturating_sub(1);
21236        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21237            && scope.prefers_label_for_snippet_in_completion()
21238            && let Some(label) = completion.label()
21239            && matches!(
21240                completion.kind(),
21241                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21242            )
21243        {
21244            snippet_source = label;
21245        }
21246        match Snippet::parse(&snippet_source).log_err() {
21247            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21248            None => (None, completion.new_text.clone()),
21249        }
21250    } else {
21251        (None, completion.new_text.clone())
21252    };
21253
21254    let mut range_to_replace = {
21255        let replace_range = &completion.replace_range;
21256        if let CompletionSource::Lsp {
21257            insert_range: Some(insert_range),
21258            ..
21259        } = &completion.source
21260        {
21261            debug_assert_eq!(
21262                insert_range.start, replace_range.start,
21263                "insert_range and replace_range should start at the same position"
21264            );
21265            debug_assert!(
21266                insert_range
21267                    .start
21268                    .cmp(cursor_position, &buffer_snapshot)
21269                    .is_le(),
21270                "insert_range should start before or at cursor position"
21271            );
21272            debug_assert!(
21273                replace_range
21274                    .start
21275                    .cmp(cursor_position, &buffer_snapshot)
21276                    .is_le(),
21277                "replace_range should start before or at cursor position"
21278            );
21279
21280            let should_replace = match intent {
21281                CompletionIntent::CompleteWithInsert => false,
21282                CompletionIntent::CompleteWithReplace => true,
21283                CompletionIntent::Complete | CompletionIntent::Compose => {
21284                    let insert_mode =
21285                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21286                            .completions
21287                            .lsp_insert_mode;
21288                    match insert_mode {
21289                        LspInsertMode::Insert => false,
21290                        LspInsertMode::Replace => true,
21291                        LspInsertMode::ReplaceSubsequence => {
21292                            let mut text_to_replace = buffer.chars_for_range(
21293                                buffer.anchor_before(replace_range.start)
21294                                    ..buffer.anchor_after(replace_range.end),
21295                            );
21296                            let mut current_needle = text_to_replace.next();
21297                            for haystack_ch in completion.label.text.chars() {
21298                                if let Some(needle_ch) = current_needle
21299                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21300                                {
21301                                    current_needle = text_to_replace.next();
21302                                }
21303                            }
21304                            current_needle.is_none()
21305                        }
21306                        LspInsertMode::ReplaceSuffix => {
21307                            if replace_range
21308                                .end
21309                                .cmp(cursor_position, &buffer_snapshot)
21310                                .is_gt()
21311                            {
21312                                let range_after_cursor = *cursor_position..replace_range.end;
21313                                let text_after_cursor = buffer
21314                                    .text_for_range(
21315                                        buffer.anchor_before(range_after_cursor.start)
21316                                            ..buffer.anchor_after(range_after_cursor.end),
21317                                    )
21318                                    .collect::<String>()
21319                                    .to_ascii_lowercase();
21320                                completion
21321                                    .label
21322                                    .text
21323                                    .to_ascii_lowercase()
21324                                    .ends_with(&text_after_cursor)
21325                            } else {
21326                                true
21327                            }
21328                        }
21329                    }
21330                }
21331            };
21332
21333            if should_replace {
21334                replace_range.clone()
21335            } else {
21336                insert_range.clone()
21337            }
21338        } else {
21339            replace_range.clone()
21340        }
21341    };
21342
21343    if range_to_replace
21344        .end
21345        .cmp(cursor_position, &buffer_snapshot)
21346        .is_lt()
21347    {
21348        range_to_replace.end = *cursor_position;
21349    }
21350
21351    CompletionEdit {
21352        new_text,
21353        replace_range: range_to_replace.to_offset(buffer),
21354        snippet,
21355    }
21356}
21357
21358struct CompletionEdit {
21359    new_text: String,
21360    replace_range: Range<usize>,
21361    snippet: Option<Snippet>,
21362}
21363
21364fn insert_extra_newline_brackets(
21365    buffer: &MultiBufferSnapshot,
21366    range: Range<usize>,
21367    language: &language::LanguageScope,
21368) -> bool {
21369    let leading_whitespace_len = buffer
21370        .reversed_chars_at(range.start)
21371        .take_while(|c| c.is_whitespace() && *c != '\n')
21372        .map(|c| c.len_utf8())
21373        .sum::<usize>();
21374    let trailing_whitespace_len = buffer
21375        .chars_at(range.end)
21376        .take_while(|c| c.is_whitespace() && *c != '\n')
21377        .map(|c| c.len_utf8())
21378        .sum::<usize>();
21379    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21380
21381    language.brackets().any(|(pair, enabled)| {
21382        let pair_start = pair.start.trim_end();
21383        let pair_end = pair.end.trim_start();
21384
21385        enabled
21386            && pair.newline
21387            && buffer.contains_str_at(range.end, pair_end)
21388            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21389    })
21390}
21391
21392fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21393    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21394        [(buffer, range, _)] => (*buffer, range.clone()),
21395        _ => return false,
21396    };
21397    let pair = {
21398        let mut result: Option<BracketMatch> = None;
21399
21400        for pair in buffer
21401            .all_bracket_ranges(range.clone())
21402            .filter(move |pair| {
21403                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21404            })
21405        {
21406            let len = pair.close_range.end - pair.open_range.start;
21407
21408            if let Some(existing) = &result {
21409                let existing_len = existing.close_range.end - existing.open_range.start;
21410                if len > existing_len {
21411                    continue;
21412                }
21413            }
21414
21415            result = Some(pair);
21416        }
21417
21418        result
21419    };
21420    let Some(pair) = pair else {
21421        return false;
21422    };
21423    pair.newline_only
21424        && buffer
21425            .chars_for_range(pair.open_range.end..range.start)
21426            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21427            .all(|c| c.is_whitespace() && c != '\n')
21428}
21429
21430fn update_uncommitted_diff_for_buffer(
21431    editor: Entity<Editor>,
21432    project: &Entity<Project>,
21433    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21434    buffer: Entity<MultiBuffer>,
21435    cx: &mut App,
21436) -> Task<()> {
21437    let mut tasks = Vec::new();
21438    project.update(cx, |project, cx| {
21439        for buffer in buffers {
21440            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21441                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21442            }
21443        }
21444    });
21445    cx.spawn(async move |cx| {
21446        let diffs = future::join_all(tasks).await;
21447        if editor
21448            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21449            .unwrap_or(false)
21450        {
21451            return;
21452        }
21453
21454        buffer
21455            .update(cx, |buffer, cx| {
21456                for diff in diffs.into_iter().flatten() {
21457                    buffer.add_diff(diff, cx);
21458                }
21459            })
21460            .ok();
21461    })
21462}
21463
21464fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21465    let tab_size = tab_size.get() as usize;
21466    let mut width = offset;
21467
21468    for ch in text.chars() {
21469        width += if ch == '\t' {
21470            tab_size - (width % tab_size)
21471        } else {
21472            1
21473        };
21474    }
21475
21476    width - offset
21477}
21478
21479#[cfg(test)]
21480mod tests {
21481    use super::*;
21482
21483    #[test]
21484    fn test_string_size_with_expanded_tabs() {
21485        let nz = |val| NonZeroU32::new(val).unwrap();
21486        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21487        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21488        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21489        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21490        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21491        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21492        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21493        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21494    }
21495}
21496
21497/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21498struct WordBreakingTokenizer<'a> {
21499    input: &'a str,
21500}
21501
21502impl<'a> WordBreakingTokenizer<'a> {
21503    fn new(input: &'a str) -> Self {
21504        Self { input }
21505    }
21506}
21507
21508fn is_char_ideographic(ch: char) -> bool {
21509    use unicode_script::Script::*;
21510    use unicode_script::UnicodeScript;
21511    matches!(ch.script(), Han | Tangut | Yi)
21512}
21513
21514fn is_grapheme_ideographic(text: &str) -> bool {
21515    text.chars().any(is_char_ideographic)
21516}
21517
21518fn is_grapheme_whitespace(text: &str) -> bool {
21519    text.chars().any(|x| x.is_whitespace())
21520}
21521
21522fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21523    text.chars()
21524        .next()
21525        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21526}
21527
21528#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21529enum WordBreakToken<'a> {
21530    Word { token: &'a str, grapheme_len: usize },
21531    InlineWhitespace { token: &'a str, grapheme_len: usize },
21532    Newline,
21533}
21534
21535impl<'a> Iterator for WordBreakingTokenizer<'a> {
21536    /// Yields a span, the count of graphemes in the token, and whether it was
21537    /// whitespace. Note that it also breaks at word boundaries.
21538    type Item = WordBreakToken<'a>;
21539
21540    fn next(&mut self) -> Option<Self::Item> {
21541        use unicode_segmentation::UnicodeSegmentation;
21542        if self.input.is_empty() {
21543            return None;
21544        }
21545
21546        let mut iter = self.input.graphemes(true).peekable();
21547        let mut offset = 0;
21548        let mut grapheme_len = 0;
21549        if let Some(first_grapheme) = iter.next() {
21550            let is_newline = first_grapheme == "\n";
21551            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21552            offset += first_grapheme.len();
21553            grapheme_len += 1;
21554            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21555                if let Some(grapheme) = iter.peek().copied()
21556                    && should_stay_with_preceding_ideograph(grapheme)
21557                {
21558                    offset += grapheme.len();
21559                    grapheme_len += 1;
21560                }
21561            } else {
21562                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21563                let mut next_word_bound = words.peek().copied();
21564                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21565                    next_word_bound = words.next();
21566                }
21567                while let Some(grapheme) = iter.peek().copied() {
21568                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21569                        break;
21570                    };
21571                    if is_grapheme_whitespace(grapheme) != is_whitespace
21572                        || (grapheme == "\n") != is_newline
21573                    {
21574                        break;
21575                    };
21576                    offset += grapheme.len();
21577                    grapheme_len += 1;
21578                    iter.next();
21579                }
21580            }
21581            let token = &self.input[..offset];
21582            self.input = &self.input[offset..];
21583            if token == "\n" {
21584                Some(WordBreakToken::Newline)
21585            } else if is_whitespace {
21586                Some(WordBreakToken::InlineWhitespace {
21587                    token,
21588                    grapheme_len,
21589                })
21590            } else {
21591                Some(WordBreakToken::Word {
21592                    token,
21593                    grapheme_len,
21594                })
21595            }
21596        } else {
21597            None
21598        }
21599    }
21600}
21601
21602#[test]
21603fn test_word_breaking_tokenizer() {
21604    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21605        ("", &[]),
21606        ("  ", &[whitespace("  ", 2)]),
21607        ("Ʒ", &[word("Ʒ", 1)]),
21608        ("Ǽ", &[word("Ǽ", 1)]),
21609        ("", &[word("", 1)]),
21610        ("⋑⋑", &[word("⋑⋑", 2)]),
21611        (
21612            "原理,进而",
21613            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21614        ),
21615        (
21616            "hello world",
21617            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21618        ),
21619        (
21620            "hello, world",
21621            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21622        ),
21623        (
21624            "  hello world",
21625            &[
21626                whitespace("  ", 2),
21627                word("hello", 5),
21628                whitespace(" ", 1),
21629                word("world", 5),
21630            ],
21631        ),
21632        (
21633            "这是什么 \n 钢笔",
21634            &[
21635                word("", 1),
21636                word("", 1),
21637                word("", 1),
21638                word("", 1),
21639                whitespace(" ", 1),
21640                newline(),
21641                whitespace(" ", 1),
21642                word("", 1),
21643                word("", 1),
21644            ],
21645        ),
21646        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21647    ];
21648
21649    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21650        WordBreakToken::Word {
21651            token,
21652            grapheme_len,
21653        }
21654    }
21655
21656    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21657        WordBreakToken::InlineWhitespace {
21658            token,
21659            grapheme_len,
21660        }
21661    }
21662
21663    fn newline() -> WordBreakToken<'static> {
21664        WordBreakToken::Newline
21665    }
21666
21667    for (input, result) in tests {
21668        assert_eq!(
21669            WordBreakingTokenizer::new(input)
21670                .collect::<Vec<_>>()
21671                .as_slice(),
21672            *result,
21673        );
21674    }
21675}
21676
21677fn wrap_with_prefix(
21678    first_line_prefix: String,
21679    subsequent_lines_prefix: String,
21680    unwrapped_text: String,
21681    wrap_column: usize,
21682    tab_size: NonZeroU32,
21683    preserve_existing_whitespace: bool,
21684) -> String {
21685    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21686    let subsequent_lines_prefix_len =
21687        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21688    let mut wrapped_text = String::new();
21689    let mut current_line = first_line_prefix;
21690    let mut is_first_line = true;
21691
21692    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21693    let mut current_line_len = first_line_prefix_len;
21694    let mut in_whitespace = false;
21695    for token in tokenizer {
21696        let have_preceding_whitespace = in_whitespace;
21697        match token {
21698            WordBreakToken::Word {
21699                token,
21700                grapheme_len,
21701            } => {
21702                in_whitespace = false;
21703                let current_prefix_len = if is_first_line {
21704                    first_line_prefix_len
21705                } else {
21706                    subsequent_lines_prefix_len
21707                };
21708                if current_line_len + grapheme_len > wrap_column
21709                    && current_line_len != current_prefix_len
21710                {
21711                    wrapped_text.push_str(current_line.trim_end());
21712                    wrapped_text.push('\n');
21713                    is_first_line = false;
21714                    current_line = subsequent_lines_prefix.clone();
21715                    current_line_len = subsequent_lines_prefix_len;
21716                }
21717                current_line.push_str(token);
21718                current_line_len += grapheme_len;
21719            }
21720            WordBreakToken::InlineWhitespace {
21721                mut token,
21722                mut grapheme_len,
21723            } => {
21724                in_whitespace = true;
21725                if have_preceding_whitespace && !preserve_existing_whitespace {
21726                    continue;
21727                }
21728                if !preserve_existing_whitespace {
21729                    token = " ";
21730                    grapheme_len = 1;
21731                }
21732                let current_prefix_len = if is_first_line {
21733                    first_line_prefix_len
21734                } else {
21735                    subsequent_lines_prefix_len
21736                };
21737                if current_line_len + grapheme_len > wrap_column {
21738                    wrapped_text.push_str(current_line.trim_end());
21739                    wrapped_text.push('\n');
21740                    is_first_line = false;
21741                    current_line = subsequent_lines_prefix.clone();
21742                    current_line_len = subsequent_lines_prefix_len;
21743                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21744                    current_line.push_str(token);
21745                    current_line_len += grapheme_len;
21746                }
21747            }
21748            WordBreakToken::Newline => {
21749                in_whitespace = true;
21750                let current_prefix_len = if is_first_line {
21751                    first_line_prefix_len
21752                } else {
21753                    subsequent_lines_prefix_len
21754                };
21755                if preserve_existing_whitespace {
21756                    wrapped_text.push_str(current_line.trim_end());
21757                    wrapped_text.push('\n');
21758                    is_first_line = false;
21759                    current_line = subsequent_lines_prefix.clone();
21760                    current_line_len = subsequent_lines_prefix_len;
21761                } else if have_preceding_whitespace {
21762                    continue;
21763                } else if current_line_len + 1 > wrap_column
21764                    && current_line_len != current_prefix_len
21765                {
21766                    wrapped_text.push_str(current_line.trim_end());
21767                    wrapped_text.push('\n');
21768                    is_first_line = false;
21769                    current_line = subsequent_lines_prefix.clone();
21770                    current_line_len = subsequent_lines_prefix_len;
21771                } else if current_line_len != current_prefix_len {
21772                    current_line.push(' ');
21773                    current_line_len += 1;
21774                }
21775            }
21776        }
21777    }
21778
21779    if !current_line.is_empty() {
21780        wrapped_text.push_str(&current_line);
21781    }
21782    wrapped_text
21783}
21784
21785#[test]
21786fn test_wrap_with_prefix() {
21787    assert_eq!(
21788        wrap_with_prefix(
21789            "# ".to_string(),
21790            "# ".to_string(),
21791            "abcdefg".to_string(),
21792            4,
21793            NonZeroU32::new(4).unwrap(),
21794            false,
21795        ),
21796        "# abcdefg"
21797    );
21798    assert_eq!(
21799        wrap_with_prefix(
21800            "".to_string(),
21801            "".to_string(),
21802            "\thello world".to_string(),
21803            8,
21804            NonZeroU32::new(4).unwrap(),
21805            false,
21806        ),
21807        "hello\nworld"
21808    );
21809    assert_eq!(
21810        wrap_with_prefix(
21811            "// ".to_string(),
21812            "// ".to_string(),
21813            "xx \nyy zz aa bb cc".to_string(),
21814            12,
21815            NonZeroU32::new(4).unwrap(),
21816            false,
21817        ),
21818        "// xx yy zz\n// aa bb cc"
21819    );
21820    assert_eq!(
21821        wrap_with_prefix(
21822            String::new(),
21823            String::new(),
21824            "这是什么 \n 钢笔".to_string(),
21825            3,
21826            NonZeroU32::new(4).unwrap(),
21827            false,
21828        ),
21829        "这是什\n么 钢\n"
21830    );
21831}
21832
21833pub trait CollaborationHub {
21834    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21835    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21836    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21837}
21838
21839impl CollaborationHub for Entity<Project> {
21840    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21841        self.read(cx).collaborators()
21842    }
21843
21844    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21845        self.read(cx).user_store().read(cx).participant_indices()
21846    }
21847
21848    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21849        let this = self.read(cx);
21850        let user_ids = this.collaborators().values().map(|c| c.user_id);
21851        this.user_store().read(cx).participant_names(user_ids, cx)
21852    }
21853}
21854
21855pub trait SemanticsProvider {
21856    fn hover(
21857        &self,
21858        buffer: &Entity<Buffer>,
21859        position: text::Anchor,
21860        cx: &mut App,
21861    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21862
21863    fn inline_values(
21864        &self,
21865        buffer_handle: Entity<Buffer>,
21866        range: Range<text::Anchor>,
21867        cx: &mut App,
21868    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21869
21870    fn inlay_hints(
21871        &self,
21872        buffer_handle: Entity<Buffer>,
21873        range: Range<text::Anchor>,
21874        cx: &mut App,
21875    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21876
21877    fn resolve_inlay_hint(
21878        &self,
21879        hint: InlayHint,
21880        buffer_handle: Entity<Buffer>,
21881        server_id: LanguageServerId,
21882        cx: &mut App,
21883    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21884
21885    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21886
21887    fn document_highlights(
21888        &self,
21889        buffer: &Entity<Buffer>,
21890        position: text::Anchor,
21891        cx: &mut App,
21892    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21893
21894    fn definitions(
21895        &self,
21896        buffer: &Entity<Buffer>,
21897        position: text::Anchor,
21898        kind: GotoDefinitionKind,
21899        cx: &mut App,
21900    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21901
21902    fn range_for_rename(
21903        &self,
21904        buffer: &Entity<Buffer>,
21905        position: text::Anchor,
21906        cx: &mut App,
21907    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21908
21909    fn perform_rename(
21910        &self,
21911        buffer: &Entity<Buffer>,
21912        position: text::Anchor,
21913        new_name: String,
21914        cx: &mut App,
21915    ) -> Option<Task<Result<ProjectTransaction>>>;
21916}
21917
21918pub trait CompletionProvider {
21919    fn completions(
21920        &self,
21921        excerpt_id: ExcerptId,
21922        buffer: &Entity<Buffer>,
21923        buffer_position: text::Anchor,
21924        trigger: CompletionContext,
21925        window: &mut Window,
21926        cx: &mut Context<Editor>,
21927    ) -> Task<Result<Vec<CompletionResponse>>>;
21928
21929    fn resolve_completions(
21930        &self,
21931        _buffer: Entity<Buffer>,
21932        _completion_indices: Vec<usize>,
21933        _completions: Rc<RefCell<Box<[Completion]>>>,
21934        _cx: &mut Context<Editor>,
21935    ) -> Task<Result<bool>> {
21936        Task::ready(Ok(false))
21937    }
21938
21939    fn apply_additional_edits_for_completion(
21940        &self,
21941        _buffer: Entity<Buffer>,
21942        _completions: Rc<RefCell<Box<[Completion]>>>,
21943        _completion_index: usize,
21944        _push_to_history: bool,
21945        _cx: &mut Context<Editor>,
21946    ) -> Task<Result<Option<language::Transaction>>> {
21947        Task::ready(Ok(None))
21948    }
21949
21950    fn is_completion_trigger(
21951        &self,
21952        buffer: &Entity<Buffer>,
21953        position: language::Anchor,
21954        text: &str,
21955        trigger_in_words: bool,
21956        menu_is_open: bool,
21957        cx: &mut Context<Editor>,
21958    ) -> bool;
21959
21960    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21961
21962    fn sort_completions(&self) -> bool {
21963        true
21964    }
21965
21966    fn filter_completions(&self) -> bool {
21967        true
21968    }
21969}
21970
21971pub trait CodeActionProvider {
21972    fn id(&self) -> Arc<str>;
21973
21974    fn code_actions(
21975        &self,
21976        buffer: &Entity<Buffer>,
21977        range: Range<text::Anchor>,
21978        window: &mut Window,
21979        cx: &mut App,
21980    ) -> Task<Result<Vec<CodeAction>>>;
21981
21982    fn apply_code_action(
21983        &self,
21984        buffer_handle: Entity<Buffer>,
21985        action: CodeAction,
21986        excerpt_id: ExcerptId,
21987        push_to_history: bool,
21988        window: &mut Window,
21989        cx: &mut App,
21990    ) -> Task<Result<ProjectTransaction>>;
21991}
21992
21993impl CodeActionProvider for Entity<Project> {
21994    fn id(&self) -> Arc<str> {
21995        "project".into()
21996    }
21997
21998    fn code_actions(
21999        &self,
22000        buffer: &Entity<Buffer>,
22001        range: Range<text::Anchor>,
22002        _window: &mut Window,
22003        cx: &mut App,
22004    ) -> Task<Result<Vec<CodeAction>>> {
22005        self.update(cx, |project, cx| {
22006            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22007            let code_actions = project.code_actions(buffer, range, None, cx);
22008            cx.background_spawn(async move {
22009                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22010                Ok(code_lens_actions
22011                    .context("code lens fetch")?
22012                    .into_iter()
22013                    .flatten()
22014                    .chain(
22015                        code_actions
22016                            .context("code action fetch")?
22017                            .into_iter()
22018                            .flatten(),
22019                    )
22020                    .collect())
22021            })
22022        })
22023    }
22024
22025    fn apply_code_action(
22026        &self,
22027        buffer_handle: Entity<Buffer>,
22028        action: CodeAction,
22029        _excerpt_id: ExcerptId,
22030        push_to_history: bool,
22031        _window: &mut Window,
22032        cx: &mut App,
22033    ) -> Task<Result<ProjectTransaction>> {
22034        self.update(cx, |project, cx| {
22035            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22036        })
22037    }
22038}
22039
22040fn snippet_completions(
22041    project: &Project,
22042    buffer: &Entity<Buffer>,
22043    buffer_position: text::Anchor,
22044    cx: &mut App,
22045) -> Task<Result<CompletionResponse>> {
22046    let languages = buffer.read(cx).languages_at(buffer_position);
22047    let snippet_store = project.snippets().read(cx);
22048
22049    let scopes: Vec<_> = languages
22050        .iter()
22051        .filter_map(|language| {
22052            let language_name = language.lsp_id();
22053            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22054
22055            if snippets.is_empty() {
22056                None
22057            } else {
22058                Some((language.default_scope(), snippets))
22059            }
22060        })
22061        .collect();
22062
22063    if scopes.is_empty() {
22064        return Task::ready(Ok(CompletionResponse {
22065            completions: vec![],
22066            is_incomplete: false,
22067        }));
22068    }
22069
22070    let snapshot = buffer.read(cx).text_snapshot();
22071    let chars: String = snapshot
22072        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22073        .collect();
22074    let executor = cx.background_executor().clone();
22075
22076    cx.background_spawn(async move {
22077        let mut is_incomplete = false;
22078        let mut completions: Vec<Completion> = Vec::new();
22079        for (scope, snippets) in scopes.into_iter() {
22080            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22081            let mut last_word = chars
22082                .chars()
22083                .take_while(|c| classifier.is_word(*c))
22084                .collect::<String>();
22085            last_word = last_word.chars().rev().collect();
22086
22087            if last_word.is_empty() {
22088                return Ok(CompletionResponse {
22089                    completions: vec![],
22090                    is_incomplete: true,
22091                });
22092            }
22093
22094            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22095            let to_lsp = |point: &text::Anchor| {
22096                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22097                point_to_lsp(end)
22098            };
22099            let lsp_end = to_lsp(&buffer_position);
22100
22101            let candidates = snippets
22102                .iter()
22103                .enumerate()
22104                .flat_map(|(ix, snippet)| {
22105                    snippet
22106                        .prefix
22107                        .iter()
22108                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22109                })
22110                .collect::<Vec<StringMatchCandidate>>();
22111
22112            const MAX_RESULTS: usize = 100;
22113            let mut matches = fuzzy::match_strings(
22114                &candidates,
22115                &last_word,
22116                last_word.chars().any(|c| c.is_uppercase()),
22117                true,
22118                MAX_RESULTS,
22119                &Default::default(),
22120                executor.clone(),
22121            )
22122            .await;
22123
22124            if matches.len() >= MAX_RESULTS {
22125                is_incomplete = true;
22126            }
22127
22128            // Remove all candidates where the query's start does not match the start of any word in the candidate
22129            if let Some(query_start) = last_word.chars().next() {
22130                matches.retain(|string_match| {
22131                    split_words(&string_match.string).any(|word| {
22132                        // Check that the first codepoint of the word as lowercase matches the first
22133                        // codepoint of the query as lowercase
22134                        word.chars()
22135                            .flat_map(|codepoint| codepoint.to_lowercase())
22136                            .zip(query_start.to_lowercase())
22137                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22138                    })
22139                });
22140            }
22141
22142            let matched_strings = matches
22143                .into_iter()
22144                .map(|m| m.string)
22145                .collect::<HashSet<_>>();
22146
22147            completions.extend(snippets.iter().filter_map(|snippet| {
22148                let matching_prefix = snippet
22149                    .prefix
22150                    .iter()
22151                    .find(|prefix| matched_strings.contains(*prefix))?;
22152                let start = as_offset - last_word.len();
22153                let start = snapshot.anchor_before(start);
22154                let range = start..buffer_position;
22155                let lsp_start = to_lsp(&start);
22156                let lsp_range = lsp::Range {
22157                    start: lsp_start,
22158                    end: lsp_end,
22159                };
22160                Some(Completion {
22161                    replace_range: range,
22162                    new_text: snippet.body.clone(),
22163                    source: CompletionSource::Lsp {
22164                        insert_range: None,
22165                        server_id: LanguageServerId(usize::MAX),
22166                        resolved: true,
22167                        lsp_completion: Box::new(lsp::CompletionItem {
22168                            label: snippet.prefix.first().unwrap().clone(),
22169                            kind: Some(CompletionItemKind::SNIPPET),
22170                            label_details: snippet.description.as_ref().map(|description| {
22171                                lsp::CompletionItemLabelDetails {
22172                                    detail: Some(description.clone()),
22173                                    description: None,
22174                                }
22175                            }),
22176                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22177                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22178                                lsp::InsertReplaceEdit {
22179                                    new_text: snippet.body.clone(),
22180                                    insert: lsp_range,
22181                                    replace: lsp_range,
22182                                },
22183                            )),
22184                            filter_text: Some(snippet.body.clone()),
22185                            sort_text: Some(char::MAX.to_string()),
22186                            ..lsp::CompletionItem::default()
22187                        }),
22188                        lsp_defaults: None,
22189                    },
22190                    label: CodeLabel {
22191                        text: matching_prefix.clone(),
22192                        runs: Vec::new(),
22193                        filter_range: 0..matching_prefix.len(),
22194                    },
22195                    icon_path: None,
22196                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22197                        single_line: snippet.name.clone().into(),
22198                        plain_text: snippet
22199                            .description
22200                            .clone()
22201                            .map(|description| description.into()),
22202                    }),
22203                    insert_text_mode: None,
22204                    confirm: None,
22205                })
22206            }))
22207        }
22208
22209        Ok(CompletionResponse {
22210            completions,
22211            is_incomplete,
22212        })
22213    })
22214}
22215
22216impl CompletionProvider for Entity<Project> {
22217    fn completions(
22218        &self,
22219        _excerpt_id: ExcerptId,
22220        buffer: &Entity<Buffer>,
22221        buffer_position: text::Anchor,
22222        options: CompletionContext,
22223        _window: &mut Window,
22224        cx: &mut Context<Editor>,
22225    ) -> Task<Result<Vec<CompletionResponse>>> {
22226        self.update(cx, |project, cx| {
22227            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22228            let project_completions = project.completions(buffer, buffer_position, options, cx);
22229            cx.background_spawn(async move {
22230                let mut responses = project_completions.await?;
22231                let snippets = snippets.await?;
22232                if !snippets.completions.is_empty() {
22233                    responses.push(snippets);
22234                }
22235                Ok(responses)
22236            })
22237        })
22238    }
22239
22240    fn resolve_completions(
22241        &self,
22242        buffer: Entity<Buffer>,
22243        completion_indices: Vec<usize>,
22244        completions: Rc<RefCell<Box<[Completion]>>>,
22245        cx: &mut Context<Editor>,
22246    ) -> Task<Result<bool>> {
22247        self.update(cx, |project, cx| {
22248            project.lsp_store().update(cx, |lsp_store, cx| {
22249                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22250            })
22251        })
22252    }
22253
22254    fn apply_additional_edits_for_completion(
22255        &self,
22256        buffer: Entity<Buffer>,
22257        completions: Rc<RefCell<Box<[Completion]>>>,
22258        completion_index: usize,
22259        push_to_history: bool,
22260        cx: &mut Context<Editor>,
22261    ) -> Task<Result<Option<language::Transaction>>> {
22262        self.update(cx, |project, cx| {
22263            project.lsp_store().update(cx, |lsp_store, cx| {
22264                lsp_store.apply_additional_edits_for_completion(
22265                    buffer,
22266                    completions,
22267                    completion_index,
22268                    push_to_history,
22269                    cx,
22270                )
22271            })
22272        })
22273    }
22274
22275    fn is_completion_trigger(
22276        &self,
22277        buffer: &Entity<Buffer>,
22278        position: language::Anchor,
22279        text: &str,
22280        trigger_in_words: bool,
22281        menu_is_open: bool,
22282        cx: &mut Context<Editor>,
22283    ) -> bool {
22284        let mut chars = text.chars();
22285        let char = if let Some(char) = chars.next() {
22286            char
22287        } else {
22288            return false;
22289        };
22290        if chars.next().is_some() {
22291            return false;
22292        }
22293
22294        let buffer = buffer.read(cx);
22295        let snapshot = buffer.snapshot();
22296        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22297            return false;
22298        }
22299        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22300        if trigger_in_words && classifier.is_word(char) {
22301            return true;
22302        }
22303
22304        buffer.completion_triggers().contains(text)
22305    }
22306}
22307
22308impl SemanticsProvider for Entity<Project> {
22309    fn hover(
22310        &self,
22311        buffer: &Entity<Buffer>,
22312        position: text::Anchor,
22313        cx: &mut App,
22314    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22315        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22316    }
22317
22318    fn document_highlights(
22319        &self,
22320        buffer: &Entity<Buffer>,
22321        position: text::Anchor,
22322        cx: &mut App,
22323    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22324        Some(self.update(cx, |project, cx| {
22325            project.document_highlights(buffer, position, cx)
22326        }))
22327    }
22328
22329    fn definitions(
22330        &self,
22331        buffer: &Entity<Buffer>,
22332        position: text::Anchor,
22333        kind: GotoDefinitionKind,
22334        cx: &mut App,
22335    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22336        Some(self.update(cx, |project, cx| match kind {
22337            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22338            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22339            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22340            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22341        }))
22342    }
22343
22344    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22345        self.update(cx, |project, cx| {
22346            if project
22347                .active_debug_session(cx)
22348                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22349            {
22350                return true;
22351            }
22352
22353            buffer.update(cx, |buffer, cx| {
22354                project.any_language_server_supports_inlay_hints(buffer, cx)
22355            })
22356        })
22357    }
22358
22359    fn inline_values(
22360        &self,
22361        buffer_handle: Entity<Buffer>,
22362        range: Range<text::Anchor>,
22363        cx: &mut App,
22364    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22365        self.update(cx, |project, cx| {
22366            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22367
22368            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22369        })
22370    }
22371
22372    fn inlay_hints(
22373        &self,
22374        buffer_handle: Entity<Buffer>,
22375        range: Range<text::Anchor>,
22376        cx: &mut App,
22377    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22378        Some(self.update(cx, |project, cx| {
22379            project.inlay_hints(buffer_handle, range, cx)
22380        }))
22381    }
22382
22383    fn resolve_inlay_hint(
22384        &self,
22385        hint: InlayHint,
22386        buffer_handle: Entity<Buffer>,
22387        server_id: LanguageServerId,
22388        cx: &mut App,
22389    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22390        Some(self.update(cx, |project, cx| {
22391            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22392        }))
22393    }
22394
22395    fn range_for_rename(
22396        &self,
22397        buffer: &Entity<Buffer>,
22398        position: text::Anchor,
22399        cx: &mut App,
22400    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22401        Some(self.update(cx, |project, cx| {
22402            let buffer = buffer.clone();
22403            let task = project.prepare_rename(buffer.clone(), position, cx);
22404            cx.spawn(async move |_, cx| {
22405                Ok(match task.await? {
22406                    PrepareRenameResponse::Success(range) => Some(range),
22407                    PrepareRenameResponse::InvalidPosition => None,
22408                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22409                        // Fallback on using TreeSitter info to determine identifier range
22410                        buffer.read_with(cx, |buffer, _| {
22411                            let snapshot = buffer.snapshot();
22412                            let (range, kind) = snapshot.surrounding_word(position, false);
22413                            if kind != Some(CharKind::Word) {
22414                                return None;
22415                            }
22416                            Some(
22417                                snapshot.anchor_before(range.start)
22418                                    ..snapshot.anchor_after(range.end),
22419                            )
22420                        })?
22421                    }
22422                })
22423            })
22424        }))
22425    }
22426
22427    fn perform_rename(
22428        &self,
22429        buffer: &Entity<Buffer>,
22430        position: text::Anchor,
22431        new_name: String,
22432        cx: &mut App,
22433    ) -> Option<Task<Result<ProjectTransaction>>> {
22434        Some(self.update(cx, |project, cx| {
22435            project.perform_rename(buffer.clone(), position, new_name, cx)
22436        }))
22437    }
22438}
22439
22440fn inlay_hint_settings(
22441    location: Anchor,
22442    snapshot: &MultiBufferSnapshot,
22443    cx: &mut Context<Editor>,
22444) -> InlayHintSettings {
22445    let file = snapshot.file_at(location);
22446    let language = snapshot.language_at(location).map(|l| l.name());
22447    language_settings(language, file, cx).inlay_hints
22448}
22449
22450fn consume_contiguous_rows(
22451    contiguous_row_selections: &mut Vec<Selection<Point>>,
22452    selection: &Selection<Point>,
22453    display_map: &DisplaySnapshot,
22454    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22455) -> (MultiBufferRow, MultiBufferRow) {
22456    contiguous_row_selections.push(selection.clone());
22457    let start_row = starting_row(selection, display_map);
22458    let mut end_row = ending_row(selection, display_map);
22459
22460    while let Some(next_selection) = selections.peek() {
22461        if next_selection.start.row <= end_row.0 {
22462            end_row = ending_row(next_selection, display_map);
22463            contiguous_row_selections.push(selections.next().unwrap().clone());
22464        } else {
22465            break;
22466        }
22467    }
22468    (start_row, end_row)
22469}
22470
22471fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22472    if selection.start.column > 0 {
22473        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22474    } else {
22475        MultiBufferRow(selection.start.row)
22476    }
22477}
22478
22479fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22480    if next_selection.end.column > 0 || next_selection.is_empty() {
22481        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22482    } else {
22483        MultiBufferRow(next_selection.end.row)
22484    }
22485}
22486
22487impl EditorSnapshot {
22488    pub fn remote_selections_in_range<'a>(
22489        &'a self,
22490        range: &'a Range<Anchor>,
22491        collaboration_hub: &dyn CollaborationHub,
22492        cx: &'a App,
22493    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22494        let participant_names = collaboration_hub.user_names(cx);
22495        let participant_indices = collaboration_hub.user_participant_indices(cx);
22496        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22497        let collaborators_by_replica_id = collaborators_by_peer_id
22498            .values()
22499            .map(|collaborator| (collaborator.replica_id, collaborator))
22500            .collect::<HashMap<_, _>>();
22501        self.buffer_snapshot
22502            .selections_in_range(range, false)
22503            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22504                if replica_id == AGENT_REPLICA_ID {
22505                    Some(RemoteSelection {
22506                        replica_id,
22507                        selection,
22508                        cursor_shape,
22509                        line_mode,
22510                        collaborator_id: CollaboratorId::Agent,
22511                        user_name: Some("Agent".into()),
22512                        color: cx.theme().players().agent(),
22513                    })
22514                } else {
22515                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22516                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22517                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22518                    Some(RemoteSelection {
22519                        replica_id,
22520                        selection,
22521                        cursor_shape,
22522                        line_mode,
22523                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22524                        user_name,
22525                        color: if let Some(index) = participant_index {
22526                            cx.theme().players().color_for_participant(index.0)
22527                        } else {
22528                            cx.theme().players().absent()
22529                        },
22530                    })
22531                }
22532            })
22533    }
22534
22535    pub fn hunks_for_ranges(
22536        &self,
22537        ranges: impl IntoIterator<Item = Range<Point>>,
22538    ) -> Vec<MultiBufferDiffHunk> {
22539        let mut hunks = Vec::new();
22540        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22541            HashMap::default();
22542        for query_range in ranges {
22543            let query_rows =
22544                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22545            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22546                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22547            ) {
22548                // Include deleted hunks that are adjacent to the query range, because
22549                // otherwise they would be missed.
22550                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22551                if hunk.status().is_deleted() {
22552                    intersects_range |= hunk.row_range.start == query_rows.end;
22553                    intersects_range |= hunk.row_range.end == query_rows.start;
22554                }
22555                if intersects_range {
22556                    if !processed_buffer_rows
22557                        .entry(hunk.buffer_id)
22558                        .or_default()
22559                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22560                    {
22561                        continue;
22562                    }
22563                    hunks.push(hunk);
22564                }
22565            }
22566        }
22567
22568        hunks
22569    }
22570
22571    fn display_diff_hunks_for_rows<'a>(
22572        &'a self,
22573        display_rows: Range<DisplayRow>,
22574        folded_buffers: &'a HashSet<BufferId>,
22575    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22576        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22577        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22578
22579        self.buffer_snapshot
22580            .diff_hunks_in_range(buffer_start..buffer_end)
22581            .filter_map(|hunk| {
22582                if folded_buffers.contains(&hunk.buffer_id) {
22583                    return None;
22584                }
22585
22586                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22587                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22588
22589                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22590                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22591
22592                let display_hunk = if hunk_display_start.column() != 0 {
22593                    DisplayDiffHunk::Folded {
22594                        display_row: hunk_display_start.row(),
22595                    }
22596                } else {
22597                    let mut end_row = hunk_display_end.row();
22598                    if hunk_display_end.column() > 0 {
22599                        end_row.0 += 1;
22600                    }
22601                    let is_created_file = hunk.is_created_file();
22602                    DisplayDiffHunk::Unfolded {
22603                        status: hunk.status(),
22604                        diff_base_byte_range: hunk.diff_base_byte_range,
22605                        display_row_range: hunk_display_start.row()..end_row,
22606                        multi_buffer_range: Anchor::range_in_buffer(
22607                            hunk.excerpt_id,
22608                            hunk.buffer_id,
22609                            hunk.buffer_range,
22610                        ),
22611                        is_created_file,
22612                    }
22613                };
22614
22615                Some(display_hunk)
22616            })
22617    }
22618
22619    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22620        self.display_snapshot.buffer_snapshot.language_at(position)
22621    }
22622
22623    pub fn is_focused(&self) -> bool {
22624        self.is_focused
22625    }
22626
22627    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22628        self.placeholder_text.as_ref()
22629    }
22630
22631    pub fn scroll_position(&self) -> gpui::Point<f32> {
22632        self.scroll_anchor.scroll_position(&self.display_snapshot)
22633    }
22634
22635    fn gutter_dimensions(
22636        &self,
22637        font_id: FontId,
22638        font_size: Pixels,
22639        max_line_number_width: Pixels,
22640        cx: &App,
22641    ) -> Option<GutterDimensions> {
22642        if !self.show_gutter {
22643            return None;
22644        }
22645
22646        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22647        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22648
22649        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22650            matches!(
22651                ProjectSettings::get_global(cx).git.git_gutter,
22652                Some(GitGutterSetting::TrackedFiles)
22653            )
22654        });
22655        let gutter_settings = EditorSettings::get_global(cx).gutter;
22656        let show_line_numbers = self
22657            .show_line_numbers
22658            .unwrap_or(gutter_settings.line_numbers);
22659        let line_gutter_width = if show_line_numbers {
22660            // Avoid flicker-like gutter resizes when the line number gains another digit by
22661            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22662            let min_width_for_number_on_gutter =
22663                ch_advance * gutter_settings.min_line_number_digits as f32;
22664            max_line_number_width.max(min_width_for_number_on_gutter)
22665        } else {
22666            0.0.into()
22667        };
22668
22669        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22670        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22671
22672        let git_blame_entries_width =
22673            self.git_blame_gutter_max_author_length
22674                .map(|max_author_length| {
22675                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22676                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22677
22678                    /// The number of characters to dedicate to gaps and margins.
22679                    const SPACING_WIDTH: usize = 4;
22680
22681                    let max_char_count = max_author_length.min(renderer.max_author_length())
22682                        + ::git::SHORT_SHA_LENGTH
22683                        + MAX_RELATIVE_TIMESTAMP.len()
22684                        + SPACING_WIDTH;
22685
22686                    ch_advance * max_char_count
22687                });
22688
22689        let is_singleton = self.buffer_snapshot.is_singleton();
22690
22691        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22692        left_padding += if !is_singleton {
22693            ch_width * 4.0
22694        } else if show_runnables || show_breakpoints {
22695            ch_width * 3.0
22696        } else if show_git_gutter && show_line_numbers {
22697            ch_width * 2.0
22698        } else if show_git_gutter || show_line_numbers {
22699            ch_width
22700        } else {
22701            px(0.)
22702        };
22703
22704        let shows_folds = is_singleton && gutter_settings.folds;
22705
22706        let right_padding = if shows_folds && show_line_numbers {
22707            ch_width * 4.0
22708        } else if shows_folds || (!is_singleton && show_line_numbers) {
22709            ch_width * 3.0
22710        } else if show_line_numbers {
22711            ch_width
22712        } else {
22713            px(0.)
22714        };
22715
22716        Some(GutterDimensions {
22717            left_padding,
22718            right_padding,
22719            width: line_gutter_width + left_padding + right_padding,
22720            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22721            git_blame_entries_width,
22722        })
22723    }
22724
22725    pub fn render_crease_toggle(
22726        &self,
22727        buffer_row: MultiBufferRow,
22728        row_contains_cursor: bool,
22729        editor: Entity<Editor>,
22730        window: &mut Window,
22731        cx: &mut App,
22732    ) -> Option<AnyElement> {
22733        let folded = self.is_line_folded(buffer_row);
22734        let mut is_foldable = false;
22735
22736        if let Some(crease) = self
22737            .crease_snapshot
22738            .query_row(buffer_row, &self.buffer_snapshot)
22739        {
22740            is_foldable = true;
22741            match crease {
22742                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22743                    if let Some(render_toggle) = render_toggle {
22744                        let toggle_callback =
22745                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22746                                if folded {
22747                                    editor.update(cx, |editor, cx| {
22748                                        editor.fold_at(buffer_row, window, cx)
22749                                    });
22750                                } else {
22751                                    editor.update(cx, |editor, cx| {
22752                                        editor.unfold_at(buffer_row, window, cx)
22753                                    });
22754                                }
22755                            });
22756                        return Some((render_toggle)(
22757                            buffer_row,
22758                            folded,
22759                            toggle_callback,
22760                            window,
22761                            cx,
22762                        ));
22763                    }
22764                }
22765            }
22766        }
22767
22768        is_foldable |= self.starts_indent(buffer_row);
22769
22770        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22771            Some(
22772                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22773                    .toggle_state(folded)
22774                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22775                        if folded {
22776                            this.unfold_at(buffer_row, window, cx);
22777                        } else {
22778                            this.fold_at(buffer_row, window, cx);
22779                        }
22780                    }))
22781                    .into_any_element(),
22782            )
22783        } else {
22784            None
22785        }
22786    }
22787
22788    pub fn render_crease_trailer(
22789        &self,
22790        buffer_row: MultiBufferRow,
22791        window: &mut Window,
22792        cx: &mut App,
22793    ) -> Option<AnyElement> {
22794        let folded = self.is_line_folded(buffer_row);
22795        if let Crease::Inline { render_trailer, .. } = self
22796            .crease_snapshot
22797            .query_row(buffer_row, &self.buffer_snapshot)?
22798        {
22799            let render_trailer = render_trailer.as_ref()?;
22800            Some(render_trailer(buffer_row, folded, window, cx))
22801        } else {
22802            None
22803        }
22804    }
22805}
22806
22807impl Deref for EditorSnapshot {
22808    type Target = DisplaySnapshot;
22809
22810    fn deref(&self) -> &Self::Target {
22811        &self.display_snapshot
22812    }
22813}
22814
22815#[derive(Clone, Debug, PartialEq, Eq)]
22816pub enum EditorEvent {
22817    InputIgnored {
22818        text: Arc<str>,
22819    },
22820    InputHandled {
22821        utf16_range_to_replace: Option<Range<isize>>,
22822        text: Arc<str>,
22823    },
22824    ExcerptsAdded {
22825        buffer: Entity<Buffer>,
22826        predecessor: ExcerptId,
22827        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22828    },
22829    ExcerptsRemoved {
22830        ids: Vec<ExcerptId>,
22831        removed_buffer_ids: Vec<BufferId>,
22832    },
22833    BufferFoldToggled {
22834        ids: Vec<ExcerptId>,
22835        folded: bool,
22836    },
22837    ExcerptsEdited {
22838        ids: Vec<ExcerptId>,
22839    },
22840    ExcerptsExpanded {
22841        ids: Vec<ExcerptId>,
22842    },
22843    BufferEdited,
22844    Edited {
22845        transaction_id: clock::Lamport,
22846    },
22847    Reparsed(BufferId),
22848    Focused,
22849    FocusedIn,
22850    Blurred,
22851    DirtyChanged,
22852    Saved,
22853    TitleChanged,
22854    DiffBaseChanged,
22855    SelectionsChanged {
22856        local: bool,
22857    },
22858    ScrollPositionChanged {
22859        local: bool,
22860        autoscroll: bool,
22861    },
22862    Closed,
22863    TransactionUndone {
22864        transaction_id: clock::Lamport,
22865    },
22866    TransactionBegun {
22867        transaction_id: clock::Lamport,
22868    },
22869    Reloaded,
22870    CursorShapeChanged,
22871    BreadcrumbsChanged,
22872    PushedToNavHistory {
22873        anchor: Anchor,
22874        is_deactivate: bool,
22875    },
22876}
22877
22878impl EventEmitter<EditorEvent> for Editor {}
22879
22880impl Focusable for Editor {
22881    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22882        self.focus_handle.clone()
22883    }
22884}
22885
22886impl Render for Editor {
22887    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22888        let settings = ThemeSettings::get_global(cx);
22889
22890        let mut text_style = match self.mode {
22891            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22892                color: cx.theme().colors().editor_foreground,
22893                font_family: settings.ui_font.family.clone(),
22894                font_features: settings.ui_font.features.clone(),
22895                font_fallbacks: settings.ui_font.fallbacks.clone(),
22896                font_size: rems(0.875).into(),
22897                font_weight: settings.ui_font.weight,
22898                line_height: relative(settings.buffer_line_height.value()),
22899                ..Default::default()
22900            },
22901            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22902                color: cx.theme().colors().editor_foreground,
22903                font_family: settings.buffer_font.family.clone(),
22904                font_features: settings.buffer_font.features.clone(),
22905                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22906                font_size: settings.buffer_font_size(cx).into(),
22907                font_weight: settings.buffer_font.weight,
22908                line_height: relative(settings.buffer_line_height.value()),
22909                ..Default::default()
22910            },
22911        };
22912        if let Some(text_style_refinement) = &self.text_style_refinement {
22913            text_style.refine(text_style_refinement)
22914        }
22915
22916        let background = match self.mode {
22917            EditorMode::SingleLine => cx.theme().system().transparent,
22918            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22919            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22920            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22921        };
22922
22923        EditorElement::new(
22924            &cx.entity(),
22925            EditorStyle {
22926                background,
22927                border: cx.theme().colors().border,
22928                local_player: cx.theme().players().local(),
22929                text: text_style,
22930                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22931                syntax: cx.theme().syntax().clone(),
22932                status: cx.theme().status().clone(),
22933                inlay_hints_style: make_inlay_hints_style(cx),
22934                edit_prediction_styles: make_suggestion_styles(cx),
22935                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22936                show_underlines: self.diagnostics_enabled(),
22937            },
22938        )
22939    }
22940}
22941
22942impl EntityInputHandler for Editor {
22943    fn text_for_range(
22944        &mut self,
22945        range_utf16: Range<usize>,
22946        adjusted_range: &mut Option<Range<usize>>,
22947        _: &mut Window,
22948        cx: &mut Context<Self>,
22949    ) -> Option<String> {
22950        let snapshot = self.buffer.read(cx).read(cx);
22951        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22952        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22953        if (start.0..end.0) != range_utf16 {
22954            adjusted_range.replace(start.0..end.0);
22955        }
22956        Some(snapshot.text_for_range(start..end).collect())
22957    }
22958
22959    fn selected_text_range(
22960        &mut self,
22961        ignore_disabled_input: bool,
22962        _: &mut Window,
22963        cx: &mut Context<Self>,
22964    ) -> Option<UTF16Selection> {
22965        // Prevent the IME menu from appearing when holding down an alphabetic key
22966        // while input is disabled.
22967        if !ignore_disabled_input && !self.input_enabled {
22968            return None;
22969        }
22970
22971        let selection = self.selections.newest::<OffsetUtf16>(cx);
22972        let range = selection.range();
22973
22974        Some(UTF16Selection {
22975            range: range.start.0..range.end.0,
22976            reversed: selection.reversed,
22977        })
22978    }
22979
22980    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22981        let snapshot = self.buffer.read(cx).read(cx);
22982        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22983        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22984    }
22985
22986    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22987        self.clear_highlights::<InputComposition>(cx);
22988        self.ime_transaction.take();
22989    }
22990
22991    fn replace_text_in_range(
22992        &mut self,
22993        range_utf16: Option<Range<usize>>,
22994        text: &str,
22995        window: &mut Window,
22996        cx: &mut Context<Self>,
22997    ) {
22998        if !self.input_enabled {
22999            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23000            return;
23001        }
23002
23003        self.transact(window, cx, |this, window, cx| {
23004            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23005                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23006                Some(this.selection_replacement_ranges(range_utf16, cx))
23007            } else {
23008                this.marked_text_ranges(cx)
23009            };
23010
23011            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23012                let newest_selection_id = this.selections.newest_anchor().id;
23013                this.selections
23014                    .all::<OffsetUtf16>(cx)
23015                    .iter()
23016                    .zip(ranges_to_replace.iter())
23017                    .find_map(|(selection, range)| {
23018                        if selection.id == newest_selection_id {
23019                            Some(
23020                                (range.start.0 as isize - selection.head().0 as isize)
23021                                    ..(range.end.0 as isize - selection.head().0 as isize),
23022                            )
23023                        } else {
23024                            None
23025                        }
23026                    })
23027            });
23028
23029            cx.emit(EditorEvent::InputHandled {
23030                utf16_range_to_replace: range_to_replace,
23031                text: text.into(),
23032            });
23033
23034            if let Some(new_selected_ranges) = new_selected_ranges {
23035                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23036                    selections.select_ranges(new_selected_ranges)
23037                });
23038                this.backspace(&Default::default(), window, cx);
23039            }
23040
23041            this.handle_input(text, window, cx);
23042        });
23043
23044        if let Some(transaction) = self.ime_transaction {
23045            self.buffer.update(cx, |buffer, cx| {
23046                buffer.group_until_transaction(transaction, cx);
23047            });
23048        }
23049
23050        self.unmark_text(window, cx);
23051    }
23052
23053    fn replace_and_mark_text_in_range(
23054        &mut self,
23055        range_utf16: Option<Range<usize>>,
23056        text: &str,
23057        new_selected_range_utf16: Option<Range<usize>>,
23058        window: &mut Window,
23059        cx: &mut Context<Self>,
23060    ) {
23061        if !self.input_enabled {
23062            return;
23063        }
23064
23065        let transaction = self.transact(window, cx, |this, window, cx| {
23066            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23067                let snapshot = this.buffer.read(cx).read(cx);
23068                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23069                    for marked_range in &mut marked_ranges {
23070                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23071                        marked_range.start.0 += relative_range_utf16.start;
23072                        marked_range.start =
23073                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23074                        marked_range.end =
23075                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23076                    }
23077                }
23078                Some(marked_ranges)
23079            } else if let Some(range_utf16) = range_utf16 {
23080                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23081                Some(this.selection_replacement_ranges(range_utf16, cx))
23082            } else {
23083                None
23084            };
23085
23086            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23087                let newest_selection_id = this.selections.newest_anchor().id;
23088                this.selections
23089                    .all::<OffsetUtf16>(cx)
23090                    .iter()
23091                    .zip(ranges_to_replace.iter())
23092                    .find_map(|(selection, range)| {
23093                        if selection.id == newest_selection_id {
23094                            Some(
23095                                (range.start.0 as isize - selection.head().0 as isize)
23096                                    ..(range.end.0 as isize - selection.head().0 as isize),
23097                            )
23098                        } else {
23099                            None
23100                        }
23101                    })
23102            });
23103
23104            cx.emit(EditorEvent::InputHandled {
23105                utf16_range_to_replace: range_to_replace,
23106                text: text.into(),
23107            });
23108
23109            if let Some(ranges) = ranges_to_replace {
23110                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23111                    s.select_ranges(ranges)
23112                });
23113            }
23114
23115            let marked_ranges = {
23116                let snapshot = this.buffer.read(cx).read(cx);
23117                this.selections
23118                    .disjoint_anchors()
23119                    .iter()
23120                    .map(|selection| {
23121                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23122                    })
23123                    .collect::<Vec<_>>()
23124            };
23125
23126            if text.is_empty() {
23127                this.unmark_text(window, cx);
23128            } else {
23129                this.highlight_text::<InputComposition>(
23130                    marked_ranges.clone(),
23131                    HighlightStyle {
23132                        underline: Some(UnderlineStyle {
23133                            thickness: px(1.),
23134                            color: None,
23135                            wavy: false,
23136                        }),
23137                        ..Default::default()
23138                    },
23139                    cx,
23140                );
23141            }
23142
23143            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23144            let use_autoclose = this.use_autoclose;
23145            let use_auto_surround = this.use_auto_surround;
23146            this.set_use_autoclose(false);
23147            this.set_use_auto_surround(false);
23148            this.handle_input(text, window, cx);
23149            this.set_use_autoclose(use_autoclose);
23150            this.set_use_auto_surround(use_auto_surround);
23151
23152            if let Some(new_selected_range) = new_selected_range_utf16 {
23153                let snapshot = this.buffer.read(cx).read(cx);
23154                let new_selected_ranges = marked_ranges
23155                    .into_iter()
23156                    .map(|marked_range| {
23157                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23158                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23159                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23160                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23161                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23162                    })
23163                    .collect::<Vec<_>>();
23164
23165                drop(snapshot);
23166                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23167                    selections.select_ranges(new_selected_ranges)
23168                });
23169            }
23170        });
23171
23172        self.ime_transaction = self.ime_transaction.or(transaction);
23173        if let Some(transaction) = self.ime_transaction {
23174            self.buffer.update(cx, |buffer, cx| {
23175                buffer.group_until_transaction(transaction, cx);
23176            });
23177        }
23178
23179        if self.text_highlights::<InputComposition>(cx).is_none() {
23180            self.ime_transaction.take();
23181        }
23182    }
23183
23184    fn bounds_for_range(
23185        &mut self,
23186        range_utf16: Range<usize>,
23187        element_bounds: gpui::Bounds<Pixels>,
23188        window: &mut Window,
23189        cx: &mut Context<Self>,
23190    ) -> Option<gpui::Bounds<Pixels>> {
23191        let text_layout_details = self.text_layout_details(window);
23192        let CharacterDimensions {
23193            em_width,
23194            em_advance,
23195            line_height,
23196        } = self.character_dimensions(window);
23197
23198        let snapshot = self.snapshot(window, cx);
23199        let scroll_position = snapshot.scroll_position();
23200        let scroll_left = scroll_position.x * em_advance;
23201
23202        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23203        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23204            + self.gutter_dimensions.full_width();
23205        let y = line_height * (start.row().as_f32() - scroll_position.y);
23206
23207        Some(Bounds {
23208            origin: element_bounds.origin + point(x, y),
23209            size: size(em_width, line_height),
23210        })
23211    }
23212
23213    fn character_index_for_point(
23214        &mut self,
23215        point: gpui::Point<Pixels>,
23216        _window: &mut Window,
23217        _cx: &mut Context<Self>,
23218    ) -> Option<usize> {
23219        let position_map = self.last_position_map.as_ref()?;
23220        if !position_map.text_hitbox.contains(&point) {
23221            return None;
23222        }
23223        let display_point = position_map.point_for_position(point).previous_valid;
23224        let anchor = position_map
23225            .snapshot
23226            .display_point_to_anchor(display_point, Bias::Left);
23227        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23228        Some(utf16_offset.0)
23229    }
23230}
23231
23232trait SelectionExt {
23233    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23234    fn spanned_rows(
23235        &self,
23236        include_end_if_at_line_start: bool,
23237        map: &DisplaySnapshot,
23238    ) -> Range<MultiBufferRow>;
23239}
23240
23241impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23242    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23243        let start = self
23244            .start
23245            .to_point(&map.buffer_snapshot)
23246            .to_display_point(map);
23247        let end = self
23248            .end
23249            .to_point(&map.buffer_snapshot)
23250            .to_display_point(map);
23251        if self.reversed {
23252            end..start
23253        } else {
23254            start..end
23255        }
23256    }
23257
23258    fn spanned_rows(
23259        &self,
23260        include_end_if_at_line_start: bool,
23261        map: &DisplaySnapshot,
23262    ) -> Range<MultiBufferRow> {
23263        let start = self.start.to_point(&map.buffer_snapshot);
23264        let mut end = self.end.to_point(&map.buffer_snapshot);
23265        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23266            end.row -= 1;
23267        }
23268
23269        let buffer_start = map.prev_line_boundary(start).0;
23270        let buffer_end = map.next_line_boundary(end).0;
23271        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23272    }
23273}
23274
23275impl<T: InvalidationRegion> InvalidationStack<T> {
23276    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23277    where
23278        S: Clone + ToOffset,
23279    {
23280        while let Some(region) = self.last() {
23281            let all_selections_inside_invalidation_ranges =
23282                if selections.len() == region.ranges().len() {
23283                    selections
23284                        .iter()
23285                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23286                        .all(|(selection, invalidation_range)| {
23287                            let head = selection.head().to_offset(buffer);
23288                            invalidation_range.start <= head && invalidation_range.end >= head
23289                        })
23290                } else {
23291                    false
23292                };
23293
23294            if all_selections_inside_invalidation_ranges {
23295                break;
23296            } else {
23297                self.pop();
23298            }
23299        }
23300    }
23301}
23302
23303impl<T> Default for InvalidationStack<T> {
23304    fn default() -> Self {
23305        Self(Default::default())
23306    }
23307}
23308
23309impl<T> Deref for InvalidationStack<T> {
23310    type Target = Vec<T>;
23311
23312    fn deref(&self) -> &Self::Target {
23313        &self.0
23314    }
23315}
23316
23317impl<T> DerefMut for InvalidationStack<T> {
23318    fn deref_mut(&mut self) -> &mut Self::Target {
23319        &mut self.0
23320    }
23321}
23322
23323impl InvalidationRegion for SnippetState {
23324    fn ranges(&self) -> &[Range<Anchor>] {
23325        &self.ranges[self.active_index]
23326    }
23327}
23328
23329fn edit_prediction_edit_text(
23330    current_snapshot: &BufferSnapshot,
23331    edits: &[(Range<Anchor>, String)],
23332    edit_preview: &EditPreview,
23333    include_deletions: bool,
23334    cx: &App,
23335) -> HighlightedText {
23336    let edits = edits
23337        .iter()
23338        .map(|(anchor, text)| {
23339            (
23340                anchor.start.text_anchor..anchor.end.text_anchor,
23341                text.clone(),
23342            )
23343        })
23344        .collect::<Vec<_>>();
23345
23346    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23347}
23348
23349fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23350    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23351    // Just show the raw edit text with basic styling
23352    let mut text = String::new();
23353    let mut highlights = Vec::new();
23354
23355    let insertion_highlight_style = HighlightStyle {
23356        color: Some(cx.theme().colors().text),
23357        ..Default::default()
23358    };
23359
23360    for (_, edit_text) in edits {
23361        let start_offset = text.len();
23362        text.push_str(edit_text);
23363        let end_offset = text.len();
23364
23365        if start_offset < end_offset {
23366            highlights.push((start_offset..end_offset, insertion_highlight_style));
23367        }
23368    }
23369
23370    HighlightedText {
23371        text: text.into(),
23372        highlights,
23373    }
23374}
23375
23376pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23377    match severity {
23378        lsp::DiagnosticSeverity::ERROR => colors.error,
23379        lsp::DiagnosticSeverity::WARNING => colors.warning,
23380        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23381        lsp::DiagnosticSeverity::HINT => colors.info,
23382        _ => colors.ignored,
23383    }
23384}
23385
23386pub fn styled_runs_for_code_label<'a>(
23387    label: &'a CodeLabel,
23388    syntax_theme: &'a theme::SyntaxTheme,
23389) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23390    let fade_out = HighlightStyle {
23391        fade_out: Some(0.35),
23392        ..Default::default()
23393    };
23394
23395    let mut prev_end = label.filter_range.end;
23396    label
23397        .runs
23398        .iter()
23399        .enumerate()
23400        .flat_map(move |(ix, (range, highlight_id))| {
23401            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23402                style
23403            } else {
23404                return Default::default();
23405            };
23406            let mut muted_style = style;
23407            muted_style.highlight(fade_out);
23408
23409            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23410            if range.start >= label.filter_range.end {
23411                if range.start > prev_end {
23412                    runs.push((prev_end..range.start, fade_out));
23413                }
23414                runs.push((range.clone(), muted_style));
23415            } else if range.end <= label.filter_range.end {
23416                runs.push((range.clone(), style));
23417            } else {
23418                runs.push((range.start..label.filter_range.end, style));
23419                runs.push((label.filter_range.end..range.end, muted_style));
23420            }
23421            prev_end = cmp::max(prev_end, range.end);
23422
23423            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23424                runs.push((prev_end..label.text.len(), fade_out));
23425            }
23426
23427            runs
23428        })
23429}
23430
23431pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23432    let mut prev_index = 0;
23433    let mut prev_codepoint: Option<char> = None;
23434    text.char_indices()
23435        .chain([(text.len(), '\0')])
23436        .filter_map(move |(index, codepoint)| {
23437            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23438            let is_boundary = index == text.len()
23439                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23440                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23441            if is_boundary {
23442                let chunk = &text[prev_index..index];
23443                prev_index = index;
23444                Some(chunk)
23445            } else {
23446                None
23447            }
23448        })
23449}
23450
23451pub trait RangeToAnchorExt: Sized {
23452    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23453
23454    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23455        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23456        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23457    }
23458}
23459
23460impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23461    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23462        let start_offset = self.start.to_offset(snapshot);
23463        let end_offset = self.end.to_offset(snapshot);
23464        if start_offset == end_offset {
23465            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23466        } else {
23467            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23468        }
23469    }
23470}
23471
23472pub trait RowExt {
23473    fn as_f32(&self) -> f32;
23474
23475    fn next_row(&self) -> Self;
23476
23477    fn previous_row(&self) -> Self;
23478
23479    fn minus(&self, other: Self) -> u32;
23480}
23481
23482impl RowExt for DisplayRow {
23483    fn as_f32(&self) -> f32 {
23484        self.0 as f32
23485    }
23486
23487    fn next_row(&self) -> Self {
23488        Self(self.0 + 1)
23489    }
23490
23491    fn previous_row(&self) -> Self {
23492        Self(self.0.saturating_sub(1))
23493    }
23494
23495    fn minus(&self, other: Self) -> u32 {
23496        self.0 - other.0
23497    }
23498}
23499
23500impl RowExt for MultiBufferRow {
23501    fn as_f32(&self) -> f32 {
23502        self.0 as f32
23503    }
23504
23505    fn next_row(&self) -> Self {
23506        Self(self.0 + 1)
23507    }
23508
23509    fn previous_row(&self) -> Self {
23510        Self(self.0.saturating_sub(1))
23511    }
23512
23513    fn minus(&self, other: Self) -> u32 {
23514        self.0 - other.0
23515    }
23516}
23517
23518trait RowRangeExt {
23519    type Row;
23520
23521    fn len(&self) -> usize;
23522
23523    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23524}
23525
23526impl RowRangeExt for Range<MultiBufferRow> {
23527    type Row = MultiBufferRow;
23528
23529    fn len(&self) -> usize {
23530        (self.end.0 - self.start.0) as usize
23531    }
23532
23533    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23534        (self.start.0..self.end.0).map(MultiBufferRow)
23535    }
23536}
23537
23538impl RowRangeExt for Range<DisplayRow> {
23539    type Row = DisplayRow;
23540
23541    fn len(&self) -> usize {
23542        (self.end.0 - self.start.0) as usize
23543    }
23544
23545    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23546        (self.start.0..self.end.0).map(DisplayRow)
23547    }
23548}
23549
23550/// If select range has more than one line, we
23551/// just point the cursor to range.start.
23552fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23553    if range.start.row == range.end.row {
23554        range
23555    } else {
23556        range.start..range.start
23557    }
23558}
23559pub struct KillRing(ClipboardItem);
23560impl Global for KillRing {}
23561
23562const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23563
23564enum BreakpointPromptEditAction {
23565    Log,
23566    Condition,
23567    HitCondition,
23568}
23569
23570struct BreakpointPromptEditor {
23571    pub(crate) prompt: Entity<Editor>,
23572    editor: WeakEntity<Editor>,
23573    breakpoint_anchor: Anchor,
23574    breakpoint: Breakpoint,
23575    edit_action: BreakpointPromptEditAction,
23576    block_ids: HashSet<CustomBlockId>,
23577    editor_margins: Arc<Mutex<EditorMargins>>,
23578    _subscriptions: Vec<Subscription>,
23579}
23580
23581impl BreakpointPromptEditor {
23582    const MAX_LINES: u8 = 4;
23583
23584    fn new(
23585        editor: WeakEntity<Editor>,
23586        breakpoint_anchor: Anchor,
23587        breakpoint: Breakpoint,
23588        edit_action: BreakpointPromptEditAction,
23589        window: &mut Window,
23590        cx: &mut Context<Self>,
23591    ) -> Self {
23592        let base_text = match edit_action {
23593            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23594            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23595            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23596        }
23597        .map(|msg| msg.to_string())
23598        .unwrap_or_default();
23599
23600        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23601        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23602
23603        let prompt = cx.new(|cx| {
23604            let mut prompt = Editor::new(
23605                EditorMode::AutoHeight {
23606                    min_lines: 1,
23607                    max_lines: Some(Self::MAX_LINES as usize),
23608                },
23609                buffer,
23610                None,
23611                window,
23612                cx,
23613            );
23614            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23615            prompt.set_show_cursor_when_unfocused(false, cx);
23616            prompt.set_placeholder_text(
23617                match edit_action {
23618                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23619                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23620                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23621                },
23622                cx,
23623            );
23624
23625            prompt
23626        });
23627
23628        Self {
23629            prompt,
23630            editor,
23631            breakpoint_anchor,
23632            breakpoint,
23633            edit_action,
23634            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23635            block_ids: Default::default(),
23636            _subscriptions: vec![],
23637        }
23638    }
23639
23640    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23641        self.block_ids.extend(block_ids)
23642    }
23643
23644    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23645        if let Some(editor) = self.editor.upgrade() {
23646            let message = self
23647                .prompt
23648                .read(cx)
23649                .buffer
23650                .read(cx)
23651                .as_singleton()
23652                .expect("A multi buffer in breakpoint prompt isn't possible")
23653                .read(cx)
23654                .as_rope()
23655                .to_string();
23656
23657            editor.update(cx, |editor, cx| {
23658                editor.edit_breakpoint_at_anchor(
23659                    self.breakpoint_anchor,
23660                    self.breakpoint.clone(),
23661                    match self.edit_action {
23662                        BreakpointPromptEditAction::Log => {
23663                            BreakpointEditAction::EditLogMessage(message.into())
23664                        }
23665                        BreakpointPromptEditAction::Condition => {
23666                            BreakpointEditAction::EditCondition(message.into())
23667                        }
23668                        BreakpointPromptEditAction::HitCondition => {
23669                            BreakpointEditAction::EditHitCondition(message.into())
23670                        }
23671                    },
23672                    cx,
23673                );
23674
23675                editor.remove_blocks(self.block_ids.clone(), None, cx);
23676                cx.focus_self(window);
23677            });
23678        }
23679    }
23680
23681    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23682        self.editor
23683            .update(cx, |editor, cx| {
23684                editor.remove_blocks(self.block_ids.clone(), None, cx);
23685                window.focus(&editor.focus_handle);
23686            })
23687            .log_err();
23688    }
23689
23690    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23691        let settings = ThemeSettings::get_global(cx);
23692        let text_style = TextStyle {
23693            color: if self.prompt.read(cx).read_only(cx) {
23694                cx.theme().colors().text_disabled
23695            } else {
23696                cx.theme().colors().text
23697            },
23698            font_family: settings.buffer_font.family.clone(),
23699            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23700            font_size: settings.buffer_font_size(cx).into(),
23701            font_weight: settings.buffer_font.weight,
23702            line_height: relative(settings.buffer_line_height.value()),
23703            ..Default::default()
23704        };
23705        EditorElement::new(
23706            &self.prompt,
23707            EditorStyle {
23708                background: cx.theme().colors().editor_background,
23709                local_player: cx.theme().players().local(),
23710                text: text_style,
23711                ..Default::default()
23712            },
23713        )
23714    }
23715}
23716
23717impl Render for BreakpointPromptEditor {
23718    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23719        let editor_margins = *self.editor_margins.lock();
23720        let gutter_dimensions = editor_margins.gutter;
23721        h_flex()
23722            .key_context("Editor")
23723            .bg(cx.theme().colors().editor_background)
23724            .border_y_1()
23725            .border_color(cx.theme().status().info_border)
23726            .size_full()
23727            .py(window.line_height() / 2.5)
23728            .on_action(cx.listener(Self::confirm))
23729            .on_action(cx.listener(Self::cancel))
23730            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23731            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23732    }
23733}
23734
23735impl Focusable for BreakpointPromptEditor {
23736    fn focus_handle(&self, cx: &App) -> FocusHandle {
23737        self.prompt.focus_handle(cx)
23738    }
23739}
23740
23741fn all_edits_insertions_or_deletions(
23742    edits: &Vec<(Range<Anchor>, String)>,
23743    snapshot: &MultiBufferSnapshot,
23744) -> bool {
23745    let mut all_insertions = true;
23746    let mut all_deletions = true;
23747
23748    for (range, new_text) in edits.iter() {
23749        let range_is_empty = range.to_offset(snapshot).is_empty();
23750        let text_is_empty = new_text.is_empty();
23751
23752        if range_is_empty != text_is_empty {
23753            if range_is_empty {
23754                all_deletions = false;
23755            } else {
23756                all_insertions = false;
23757            }
23758        } else {
23759            return false;
23760        }
23761
23762        if !all_insertions && !all_deletions {
23763            return false;
23764        }
23765    }
23766    all_insertions || all_deletions
23767}
23768
23769struct MissingEditPredictionKeybindingTooltip;
23770
23771impl Render for MissingEditPredictionKeybindingTooltip {
23772    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23773        ui::tooltip_container(window, cx, |container, _, cx| {
23774            container
23775                .flex_shrink_0()
23776                .max_w_80()
23777                .min_h(rems_from_px(124.))
23778                .justify_between()
23779                .child(
23780                    v_flex()
23781                        .flex_1()
23782                        .text_ui_sm(cx)
23783                        .child(Label::new("Conflict with Accept Keybinding"))
23784                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23785                )
23786                .child(
23787                    h_flex()
23788                        .pb_1()
23789                        .gap_1()
23790                        .items_end()
23791                        .w_full()
23792                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23793                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23794                        }))
23795                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23796                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23797                        })),
23798                )
23799        })
23800    }
23801}
23802
23803#[derive(Debug, Clone, Copy, PartialEq)]
23804pub struct LineHighlight {
23805    pub background: Background,
23806    pub border: Option<gpui::Hsla>,
23807    pub include_gutter: bool,
23808    pub type_id: Option<TypeId>,
23809}
23810
23811struct LineManipulationResult {
23812    pub new_text: String,
23813    pub line_count_before: usize,
23814    pub line_count_after: usize,
23815}
23816
23817fn render_diff_hunk_controls(
23818    row: u32,
23819    status: &DiffHunkStatus,
23820    hunk_range: Range<Anchor>,
23821    is_created_file: bool,
23822    line_height: Pixels,
23823    editor: &Entity<Editor>,
23824    _window: &mut Window,
23825    cx: &mut App,
23826) -> AnyElement {
23827    h_flex()
23828        .h(line_height)
23829        .mr_1()
23830        .gap_1()
23831        .px_0p5()
23832        .pb_1()
23833        .border_x_1()
23834        .border_b_1()
23835        .border_color(cx.theme().colors().border_variant)
23836        .rounded_b_lg()
23837        .bg(cx.theme().colors().editor_background)
23838        .gap_1()
23839        .block_mouse_except_scroll()
23840        .shadow_md()
23841        .child(if status.has_secondary_hunk() {
23842            Button::new(("stage", row as u64), "Stage")
23843                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23844                .tooltip({
23845                    let focus_handle = editor.focus_handle(cx);
23846                    move |window, cx| {
23847                        Tooltip::for_action_in(
23848                            "Stage Hunk",
23849                            &::git::ToggleStaged,
23850                            &focus_handle,
23851                            window,
23852                            cx,
23853                        )
23854                    }
23855                })
23856                .on_click({
23857                    let editor = editor.clone();
23858                    move |_event, _window, cx| {
23859                        editor.update(cx, |editor, cx| {
23860                            editor.stage_or_unstage_diff_hunks(
23861                                true,
23862                                vec![hunk_range.start..hunk_range.start],
23863                                cx,
23864                            );
23865                        });
23866                    }
23867                })
23868        } else {
23869            Button::new(("unstage", row as u64), "Unstage")
23870                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23871                .tooltip({
23872                    let focus_handle = editor.focus_handle(cx);
23873                    move |window, cx| {
23874                        Tooltip::for_action_in(
23875                            "Unstage Hunk",
23876                            &::git::ToggleStaged,
23877                            &focus_handle,
23878                            window,
23879                            cx,
23880                        )
23881                    }
23882                })
23883                .on_click({
23884                    let editor = editor.clone();
23885                    move |_event, _window, cx| {
23886                        editor.update(cx, |editor, cx| {
23887                            editor.stage_or_unstage_diff_hunks(
23888                                false,
23889                                vec![hunk_range.start..hunk_range.start],
23890                                cx,
23891                            );
23892                        });
23893                    }
23894                })
23895        })
23896        .child(
23897            Button::new(("restore", row as u64), "Restore")
23898                .tooltip({
23899                    let focus_handle = editor.focus_handle(cx);
23900                    move |window, cx| {
23901                        Tooltip::for_action_in(
23902                            "Restore Hunk",
23903                            &::git::Restore,
23904                            &focus_handle,
23905                            window,
23906                            cx,
23907                        )
23908                    }
23909                })
23910                .on_click({
23911                    let editor = editor.clone();
23912                    move |_event, window, cx| {
23913                        editor.update(cx, |editor, cx| {
23914                            let snapshot = editor.snapshot(window, cx);
23915                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23916                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23917                        });
23918                    }
23919                })
23920                .disabled(is_created_file),
23921        )
23922        .when(
23923            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23924            |el| {
23925                el.child(
23926                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23927                        .shape(IconButtonShape::Square)
23928                        .icon_size(IconSize::Small)
23929                        // .disabled(!has_multiple_hunks)
23930                        .tooltip({
23931                            let focus_handle = editor.focus_handle(cx);
23932                            move |window, cx| {
23933                                Tooltip::for_action_in(
23934                                    "Next Hunk",
23935                                    &GoToHunk,
23936                                    &focus_handle,
23937                                    window,
23938                                    cx,
23939                                )
23940                            }
23941                        })
23942                        .on_click({
23943                            let editor = editor.clone();
23944                            move |_event, window, cx| {
23945                                editor.update(cx, |editor, cx| {
23946                                    let snapshot = editor.snapshot(window, cx);
23947                                    let position =
23948                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23949                                    editor.go_to_hunk_before_or_after_position(
23950                                        &snapshot,
23951                                        position,
23952                                        Direction::Next,
23953                                        window,
23954                                        cx,
23955                                    );
23956                                    editor.expand_selected_diff_hunks(cx);
23957                                });
23958                            }
23959                        }),
23960                )
23961                .child(
23962                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23963                        .shape(IconButtonShape::Square)
23964                        .icon_size(IconSize::Small)
23965                        // .disabled(!has_multiple_hunks)
23966                        .tooltip({
23967                            let focus_handle = editor.focus_handle(cx);
23968                            move |window, cx| {
23969                                Tooltip::for_action_in(
23970                                    "Previous Hunk",
23971                                    &GoToPreviousHunk,
23972                                    &focus_handle,
23973                                    window,
23974                                    cx,
23975                                )
23976                            }
23977                        })
23978                        .on_click({
23979                            let editor = editor.clone();
23980                            move |_event, window, cx| {
23981                                editor.update(cx, |editor, cx| {
23982                                    let snapshot = editor.snapshot(window, cx);
23983                                    let point =
23984                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23985                                    editor.go_to_hunk_before_or_after_position(
23986                                        &snapshot,
23987                                        point,
23988                                        Direction::Prev,
23989                                        window,
23990                                        cx,
23991                                    );
23992                                    editor.expand_selected_diff_hunks(cx);
23993                                });
23994                            }
23995                        }),
23996                )
23997            },
23998        )
23999        .into_any_element()
24000}