editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::{seq::SliceRandom, thread_rng};
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::OnceCell,
  181    cell::RefCell,
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::Not,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use sum_tree::TreeMap;
  194use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::{
  215    code_context_menus::CompletionsMenuSource,
  216    editor_settings::MultiCursorModifier,
  217    hover_links::{find_url, find_url_from_range},
  218    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  219};
  220
  221pub const FILE_HEADER_HEIGHT: u32 = 2;
  222pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  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            let mut display_options: Option<CompletionDisplayOptions> = None;
 5640            if let Some(provider_responses) = provider_responses.await.log_err()
 5641                && !provider_responses.is_empty()
 5642            {
 5643                for response in provider_responses {
 5644                    completions.extend(response.completions);
 5645                    is_incomplete = is_incomplete || response.is_incomplete;
 5646                    match display_options.as_mut() {
 5647                        None => {
 5648                            display_options = Some(response.display_options);
 5649                        }
 5650                        Some(options) => options.merge(&response.display_options),
 5651                    }
 5652                }
 5653                if completion_settings.words == WordsCompletionMode::Fallback {
 5654                    words = Task::ready(BTreeMap::default());
 5655                }
 5656            }
 5657            let display_options = display_options.unwrap_or_default();
 5658
 5659            let mut words = words.await;
 5660            if let Some(word_to_exclude) = &word_to_exclude {
 5661                words.remove(word_to_exclude);
 5662            }
 5663            for lsp_completion in &completions {
 5664                words.remove(&lsp_completion.new_text);
 5665            }
 5666            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5667                replace_range: word_replace_range.clone(),
 5668                new_text: word.clone(),
 5669                label: CodeLabel::plain(word, None),
 5670                icon_path: None,
 5671                documentation: None,
 5672                source: CompletionSource::BufferWord {
 5673                    word_range,
 5674                    resolved: false,
 5675                },
 5676                insert_text_mode: Some(InsertTextMode::AS_IS),
 5677                confirm: None,
 5678            }));
 5679
 5680            let menu = if completions.is_empty() {
 5681                None
 5682            } else {
 5683                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5684                    let languages = editor
 5685                        .workspace
 5686                        .as_ref()
 5687                        .and_then(|(workspace, _)| workspace.upgrade())
 5688                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5689                    let menu = CompletionsMenu::new(
 5690                        id,
 5691                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5692                        sort_completions,
 5693                        show_completion_documentation,
 5694                        position,
 5695                        query.clone(),
 5696                        is_incomplete,
 5697                        buffer.clone(),
 5698                        completions.into(),
 5699                        display_options,
 5700                        snippet_sort_order,
 5701                        languages,
 5702                        language,
 5703                        cx,
 5704                    );
 5705
 5706                    let query = if filter_completions { query } else { None };
 5707                    let matches_task = if let Some(query) = query {
 5708                        menu.do_async_filtering(query, cx)
 5709                    } else {
 5710                        Task::ready(menu.unfiltered_matches())
 5711                    };
 5712                    (menu, matches_task)
 5713                }) else {
 5714                    return;
 5715                };
 5716
 5717                let matches = matches_task.await;
 5718
 5719                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5720                    // Newer menu already set, so exit.
 5721                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5722                        editor.context_menu.borrow().as_ref()
 5723                        && prev_menu.id > id
 5724                    {
 5725                        return;
 5726                    };
 5727
 5728                    // Only valid to take prev_menu because it the new menu is immediately set
 5729                    // below, or the menu is hidden.
 5730                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5731                        editor.context_menu.borrow_mut().take()
 5732                    {
 5733                        let position_matches =
 5734                            if prev_menu.initial_position == menu.initial_position {
 5735                                true
 5736                            } else {
 5737                                let snapshot = editor.buffer.read(cx).read(cx);
 5738                                prev_menu.initial_position.to_offset(&snapshot)
 5739                                    == menu.initial_position.to_offset(&snapshot)
 5740                            };
 5741                        if position_matches {
 5742                            // Preserve markdown cache before `set_filter_results` because it will
 5743                            // try to populate the documentation cache.
 5744                            menu.preserve_markdown_cache(prev_menu);
 5745                        }
 5746                    };
 5747
 5748                    menu.set_filter_results(matches, provider, window, cx);
 5749                }) else {
 5750                    return;
 5751                };
 5752
 5753                menu.visible().then_some(menu)
 5754            };
 5755
 5756            editor
 5757                .update_in(cx, |editor, window, cx| {
 5758                    if editor.focus_handle.is_focused(window)
 5759                        && let Some(menu) = menu
 5760                    {
 5761                        *editor.context_menu.borrow_mut() =
 5762                            Some(CodeContextMenu::Completions(menu));
 5763
 5764                        crate::hover_popover::hide_hover(editor, cx);
 5765                        if editor.show_edit_predictions_in_menu() {
 5766                            editor.update_visible_edit_prediction(window, cx);
 5767                        } else {
 5768                            editor.discard_edit_prediction(false, cx);
 5769                        }
 5770
 5771                        cx.notify();
 5772                        return;
 5773                    }
 5774
 5775                    if editor.completion_tasks.len() <= 1 {
 5776                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5777                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5778                        // If it was already hidden and we don't show edit predictions in the menu,
 5779                        // we should also show the edit prediction when available.
 5780                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5781                            editor.update_visible_edit_prediction(window, cx);
 5782                        }
 5783                    }
 5784                })
 5785                .ok();
 5786        });
 5787
 5788        self.completion_tasks.push((id, task));
 5789    }
 5790
 5791    #[cfg(feature = "test-support")]
 5792    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5793        let menu = self.context_menu.borrow();
 5794        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5795            let completions = menu.completions.borrow();
 5796            Some(completions.to_vec())
 5797        } else {
 5798            None
 5799        }
 5800    }
 5801
 5802    pub fn with_completions_menu_matching_id<R>(
 5803        &self,
 5804        id: CompletionId,
 5805        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5806    ) -> R {
 5807        let mut context_menu = self.context_menu.borrow_mut();
 5808        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5809            return f(None);
 5810        };
 5811        if completions_menu.id != id {
 5812            return f(None);
 5813        }
 5814        f(Some(completions_menu))
 5815    }
 5816
 5817    pub fn confirm_completion(
 5818        &mut self,
 5819        action: &ConfirmCompletion,
 5820        window: &mut Window,
 5821        cx: &mut Context<Self>,
 5822    ) -> Option<Task<Result<()>>> {
 5823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5824        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5825    }
 5826
 5827    pub fn confirm_completion_insert(
 5828        &mut self,
 5829        _: &ConfirmCompletionInsert,
 5830        window: &mut Window,
 5831        cx: &mut Context<Self>,
 5832    ) -> Option<Task<Result<()>>> {
 5833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5834        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5835    }
 5836
 5837    pub fn confirm_completion_replace(
 5838        &mut self,
 5839        _: &ConfirmCompletionReplace,
 5840        window: &mut Window,
 5841        cx: &mut Context<Self>,
 5842    ) -> Option<Task<Result<()>>> {
 5843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5844        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5845    }
 5846
 5847    pub fn compose_completion(
 5848        &mut self,
 5849        action: &ComposeCompletion,
 5850        window: &mut Window,
 5851        cx: &mut Context<Self>,
 5852    ) -> Option<Task<Result<()>>> {
 5853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5854        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5855    }
 5856
 5857    fn do_completion(
 5858        &mut self,
 5859        item_ix: Option<usize>,
 5860        intent: CompletionIntent,
 5861        window: &mut Window,
 5862        cx: &mut Context<Editor>,
 5863    ) -> Option<Task<Result<()>>> {
 5864        use language::ToOffset as _;
 5865
 5866        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5867        else {
 5868            return None;
 5869        };
 5870
 5871        let candidate_id = {
 5872            let entries = completions_menu.entries.borrow();
 5873            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5874            if self.show_edit_predictions_in_menu() {
 5875                self.discard_edit_prediction(true, cx);
 5876            }
 5877            mat.candidate_id
 5878        };
 5879
 5880        let completion = completions_menu
 5881            .completions
 5882            .borrow()
 5883            .get(candidate_id)?
 5884            .clone();
 5885        cx.stop_propagation();
 5886
 5887        let buffer_handle = completions_menu.buffer.clone();
 5888
 5889        let CompletionEdit {
 5890            new_text,
 5891            snippet,
 5892            replace_range,
 5893        } = process_completion_for_edit(
 5894            &completion,
 5895            intent,
 5896            &buffer_handle,
 5897            &completions_menu.initial_position.text_anchor,
 5898            cx,
 5899        );
 5900
 5901        let buffer = buffer_handle.read(cx);
 5902        let snapshot = self.buffer.read(cx).snapshot(cx);
 5903        let newest_anchor = self.selections.newest_anchor();
 5904        let replace_range_multibuffer = {
 5905            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5906            let multibuffer_anchor = snapshot
 5907                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5908                .unwrap()
 5909                ..snapshot
 5910                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5911                    .unwrap();
 5912            multibuffer_anchor.start.to_offset(&snapshot)
 5913                ..multibuffer_anchor.end.to_offset(&snapshot)
 5914        };
 5915        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5916            return None;
 5917        }
 5918
 5919        let old_text = buffer
 5920            .text_for_range(replace_range.clone())
 5921            .collect::<String>();
 5922        let lookbehind = newest_anchor
 5923            .start
 5924            .text_anchor
 5925            .to_offset(buffer)
 5926            .saturating_sub(replace_range.start);
 5927        let lookahead = replace_range
 5928            .end
 5929            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5930        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5931        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5932
 5933        let selections = self.selections.all::<usize>(cx);
 5934        let mut ranges = Vec::new();
 5935        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5936
 5937        for selection in &selections {
 5938            let range = if selection.id == newest_anchor.id {
 5939                replace_range_multibuffer.clone()
 5940            } else {
 5941                let mut range = selection.range();
 5942
 5943                // if prefix is present, don't duplicate it
 5944                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5945                    range.start = range.start.saturating_sub(lookbehind);
 5946
 5947                    // if suffix is also present, mimic the newest cursor and replace it
 5948                    if selection.id != newest_anchor.id
 5949                        && snapshot.contains_str_at(range.end, suffix)
 5950                    {
 5951                        range.end += lookahead;
 5952                    }
 5953                }
 5954                range
 5955            };
 5956
 5957            ranges.push(range.clone());
 5958
 5959            if !self.linked_edit_ranges.is_empty() {
 5960                let start_anchor = snapshot.anchor_before(range.start);
 5961                let end_anchor = snapshot.anchor_after(range.end);
 5962                if let Some(ranges) = self
 5963                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5964                {
 5965                    for (buffer, edits) in ranges {
 5966                        linked_edits
 5967                            .entry(buffer.clone())
 5968                            .or_default()
 5969                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5970                    }
 5971                }
 5972            }
 5973        }
 5974
 5975        let common_prefix_len = old_text
 5976            .chars()
 5977            .zip(new_text.chars())
 5978            .take_while(|(a, b)| a == b)
 5979            .map(|(a, _)| a.len_utf8())
 5980            .sum::<usize>();
 5981
 5982        cx.emit(EditorEvent::InputHandled {
 5983            utf16_range_to_replace: None,
 5984            text: new_text[common_prefix_len..].into(),
 5985        });
 5986
 5987        self.transact(window, cx, |editor, window, cx| {
 5988            if let Some(mut snippet) = snippet {
 5989                snippet.text = new_text.to_string();
 5990                editor
 5991                    .insert_snippet(&ranges, snippet, window, cx)
 5992                    .log_err();
 5993            } else {
 5994                editor.buffer.update(cx, |multi_buffer, cx| {
 5995                    let auto_indent = match completion.insert_text_mode {
 5996                        Some(InsertTextMode::AS_IS) => None,
 5997                        _ => editor.autoindent_mode.clone(),
 5998                    };
 5999                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6000                    multi_buffer.edit(edits, auto_indent, cx);
 6001                });
 6002            }
 6003            for (buffer, edits) in linked_edits {
 6004                buffer.update(cx, |buffer, cx| {
 6005                    let snapshot = buffer.snapshot();
 6006                    let edits = edits
 6007                        .into_iter()
 6008                        .map(|(range, text)| {
 6009                            use text::ToPoint as TP;
 6010                            let end_point = TP::to_point(&range.end, &snapshot);
 6011                            let start_point = TP::to_point(&range.start, &snapshot);
 6012                            (start_point..end_point, text)
 6013                        })
 6014                        .sorted_by_key(|(range, _)| range.start);
 6015                    buffer.edit(edits, None, cx);
 6016                })
 6017            }
 6018
 6019            editor.refresh_edit_prediction(true, false, window, cx);
 6020        });
 6021        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6022
 6023        let show_new_completions_on_confirm = completion
 6024            .confirm
 6025            .as_ref()
 6026            .is_some_and(|confirm| confirm(intent, window, cx));
 6027        if show_new_completions_on_confirm {
 6028            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6029        }
 6030
 6031        let provider = self.completion_provider.as_ref()?;
 6032        drop(completion);
 6033        let apply_edits = provider.apply_additional_edits_for_completion(
 6034            buffer_handle,
 6035            completions_menu.completions.clone(),
 6036            candidate_id,
 6037            true,
 6038            cx,
 6039        );
 6040
 6041        let editor_settings = EditorSettings::get_global(cx);
 6042        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6043            // After the code completion is finished, users often want to know what signatures are needed.
 6044            // so we should automatically call signature_help
 6045            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6046        }
 6047
 6048        Some(cx.foreground_executor().spawn(async move {
 6049            apply_edits.await?;
 6050            Ok(())
 6051        }))
 6052    }
 6053
 6054    pub fn toggle_code_actions(
 6055        &mut self,
 6056        action: &ToggleCodeActions,
 6057        window: &mut Window,
 6058        cx: &mut Context<Self>,
 6059    ) {
 6060        let quick_launch = action.quick_launch;
 6061        let mut context_menu = self.context_menu.borrow_mut();
 6062        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6063            if code_actions.deployed_from == action.deployed_from {
 6064                // Toggle if we're selecting the same one
 6065                *context_menu = None;
 6066                cx.notify();
 6067                return;
 6068            } else {
 6069                // Otherwise, clear it and start a new one
 6070                *context_menu = None;
 6071                cx.notify();
 6072            }
 6073        }
 6074        drop(context_menu);
 6075        let snapshot = self.snapshot(window, cx);
 6076        let deployed_from = action.deployed_from.clone();
 6077        let action = action.clone();
 6078        self.completion_tasks.clear();
 6079        self.discard_edit_prediction(false, cx);
 6080
 6081        let multibuffer_point = match &action.deployed_from {
 6082            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6083                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6084            }
 6085            _ => self.selections.newest::<Point>(cx).head(),
 6086        };
 6087        let Some((buffer, buffer_row)) = snapshot
 6088            .buffer_snapshot
 6089            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6090            .and_then(|(buffer_snapshot, range)| {
 6091                self.buffer()
 6092                    .read(cx)
 6093                    .buffer(buffer_snapshot.remote_id())
 6094                    .map(|buffer| (buffer, range.start.row))
 6095            })
 6096        else {
 6097            return;
 6098        };
 6099        let buffer_id = buffer.read(cx).remote_id();
 6100        let tasks = self
 6101            .tasks
 6102            .get(&(buffer_id, buffer_row))
 6103            .map(|t| Arc::new(t.to_owned()));
 6104
 6105        if !self.focus_handle.is_focused(window) {
 6106            return;
 6107        }
 6108        let project = self.project.clone();
 6109
 6110        let code_actions_task = match deployed_from {
 6111            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6112            _ => self.code_actions(buffer_row, window, cx),
 6113        };
 6114
 6115        let runnable_task = match deployed_from {
 6116            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6117            _ => {
 6118                let mut task_context_task = Task::ready(None);
 6119                if let Some(tasks) = &tasks
 6120                    && let Some(project) = project
 6121                {
 6122                    task_context_task =
 6123                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6124                }
 6125
 6126                cx.spawn_in(window, {
 6127                    let buffer = buffer.clone();
 6128                    async move |editor, cx| {
 6129                        let task_context = task_context_task.await;
 6130
 6131                        let resolved_tasks =
 6132                            tasks
 6133                                .zip(task_context.clone())
 6134                                .map(|(tasks, task_context)| ResolvedTasks {
 6135                                    templates: tasks.resolve(&task_context).collect(),
 6136                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6137                                        multibuffer_point.row,
 6138                                        tasks.column,
 6139                                    )),
 6140                                });
 6141                        let debug_scenarios = editor
 6142                            .update(cx, |editor, cx| {
 6143                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6144                            })?
 6145                            .await;
 6146                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6147                    }
 6148                })
 6149            }
 6150        };
 6151
 6152        cx.spawn_in(window, async move |editor, cx| {
 6153            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6154            let code_actions = code_actions_task.await;
 6155            let spawn_straight_away = quick_launch
 6156                && resolved_tasks
 6157                    .as_ref()
 6158                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6159                && code_actions
 6160                    .as_ref()
 6161                    .is_none_or(|actions| actions.is_empty())
 6162                && debug_scenarios.is_empty();
 6163
 6164            editor.update_in(cx, |editor, window, cx| {
 6165                crate::hover_popover::hide_hover(editor, cx);
 6166                let actions = CodeActionContents::new(
 6167                    resolved_tasks,
 6168                    code_actions,
 6169                    debug_scenarios,
 6170                    task_context.unwrap_or_default(),
 6171                );
 6172
 6173                // Don't show the menu if there are no actions available
 6174                if actions.is_empty() {
 6175                    cx.notify();
 6176                    return Task::ready(Ok(()));
 6177                }
 6178
 6179                *editor.context_menu.borrow_mut() =
 6180                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6181                        buffer,
 6182                        actions,
 6183                        selected_item: Default::default(),
 6184                        scroll_handle: UniformListScrollHandle::default(),
 6185                        deployed_from,
 6186                    }));
 6187                cx.notify();
 6188                if spawn_straight_away
 6189                    && let Some(task) = editor.confirm_code_action(
 6190                        &ConfirmCodeAction { item_ix: Some(0) },
 6191                        window,
 6192                        cx,
 6193                    )
 6194                {
 6195                    return task;
 6196                }
 6197
 6198                Task::ready(Ok(()))
 6199            })
 6200        })
 6201        .detach_and_log_err(cx);
 6202    }
 6203
 6204    fn debug_scenarios(
 6205        &mut self,
 6206        resolved_tasks: &Option<ResolvedTasks>,
 6207        buffer: &Entity<Buffer>,
 6208        cx: &mut App,
 6209    ) -> Task<Vec<task::DebugScenario>> {
 6210        maybe!({
 6211            let project = self.project()?;
 6212            let dap_store = project.read(cx).dap_store();
 6213            let mut scenarios = vec![];
 6214            let resolved_tasks = resolved_tasks.as_ref()?;
 6215            let buffer = buffer.read(cx);
 6216            let language = buffer.language()?;
 6217            let file = buffer.file();
 6218            let debug_adapter = language_settings(language.name().into(), file, cx)
 6219                .debuggers
 6220                .first()
 6221                .map(SharedString::from)
 6222                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6223
 6224            dap_store.update(cx, |dap_store, cx| {
 6225                for (_, task) in &resolved_tasks.templates {
 6226                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6227                        task.original_task().clone(),
 6228                        debug_adapter.clone().into(),
 6229                        task.display_label().to_owned().into(),
 6230                        cx,
 6231                    );
 6232                    scenarios.push(maybe_scenario);
 6233                }
 6234            });
 6235            Some(cx.background_spawn(async move {
 6236                futures::future::join_all(scenarios)
 6237                    .await
 6238                    .into_iter()
 6239                    .flatten()
 6240                    .collect::<Vec<_>>()
 6241            }))
 6242        })
 6243        .unwrap_or_else(|| Task::ready(vec![]))
 6244    }
 6245
 6246    fn code_actions(
 6247        &mut self,
 6248        buffer_row: u32,
 6249        window: &mut Window,
 6250        cx: &mut Context<Self>,
 6251    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6252        let mut task = self.code_actions_task.take();
 6253        cx.spawn_in(window, async move |editor, cx| {
 6254            while let Some(prev_task) = task {
 6255                prev_task.await.log_err();
 6256                task = editor
 6257                    .update(cx, |this, _| this.code_actions_task.take())
 6258                    .ok()?;
 6259            }
 6260
 6261            editor
 6262                .update(cx, |editor, cx| {
 6263                    editor
 6264                        .available_code_actions
 6265                        .clone()
 6266                        .and_then(|(location, code_actions)| {
 6267                            let snapshot = location.buffer.read(cx).snapshot();
 6268                            let point_range = location.range.to_point(&snapshot);
 6269                            let point_range = point_range.start.row..=point_range.end.row;
 6270                            if point_range.contains(&buffer_row) {
 6271                                Some(code_actions)
 6272                            } else {
 6273                                None
 6274                            }
 6275                        })
 6276                })
 6277                .ok()
 6278                .flatten()
 6279        })
 6280    }
 6281
 6282    pub fn confirm_code_action(
 6283        &mut self,
 6284        action: &ConfirmCodeAction,
 6285        window: &mut Window,
 6286        cx: &mut Context<Self>,
 6287    ) -> Option<Task<Result<()>>> {
 6288        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6289
 6290        let actions_menu =
 6291            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6292                menu
 6293            } else {
 6294                return None;
 6295            };
 6296
 6297        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6298        let action = actions_menu.actions.get(action_ix)?;
 6299        let title = action.label();
 6300        let buffer = actions_menu.buffer;
 6301        let workspace = self.workspace()?;
 6302
 6303        match action {
 6304            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6305                workspace.update(cx, |workspace, cx| {
 6306                    workspace.schedule_resolved_task(
 6307                        task_source_kind,
 6308                        resolved_task,
 6309                        false,
 6310                        window,
 6311                        cx,
 6312                    );
 6313
 6314                    Some(Task::ready(Ok(())))
 6315                })
 6316            }
 6317            CodeActionsItem::CodeAction {
 6318                excerpt_id,
 6319                action,
 6320                provider,
 6321            } => {
 6322                let apply_code_action =
 6323                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6324                let workspace = workspace.downgrade();
 6325                Some(cx.spawn_in(window, async move |editor, cx| {
 6326                    let project_transaction = apply_code_action.await?;
 6327                    Self::open_project_transaction(
 6328                        &editor,
 6329                        workspace,
 6330                        project_transaction,
 6331                        title,
 6332                        cx,
 6333                    )
 6334                    .await
 6335                }))
 6336            }
 6337            CodeActionsItem::DebugScenario(scenario) => {
 6338                let context = actions_menu.actions.context;
 6339
 6340                workspace.update(cx, |workspace, cx| {
 6341                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6342                    workspace.start_debug_session(
 6343                        scenario,
 6344                        context,
 6345                        Some(buffer),
 6346                        None,
 6347                        window,
 6348                        cx,
 6349                    );
 6350                });
 6351                Some(Task::ready(Ok(())))
 6352            }
 6353        }
 6354    }
 6355
 6356    pub async fn open_project_transaction(
 6357        editor: &WeakEntity<Editor>,
 6358        workspace: WeakEntity<Workspace>,
 6359        transaction: ProjectTransaction,
 6360        title: String,
 6361        cx: &mut AsyncWindowContext,
 6362    ) -> Result<()> {
 6363        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6364        cx.update(|_, cx| {
 6365            entries.sort_unstable_by_key(|(buffer, _)| {
 6366                buffer.read(cx).file().map(|f| f.path().clone())
 6367            });
 6368        })?;
 6369
 6370        // If the project transaction's edits are all contained within this editor, then
 6371        // avoid opening a new editor to display them.
 6372
 6373        if let Some((buffer, transaction)) = entries.first() {
 6374            if entries.len() == 1 {
 6375                let excerpt = editor.update(cx, |editor, cx| {
 6376                    editor
 6377                        .buffer()
 6378                        .read(cx)
 6379                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6380                })?;
 6381                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6382                    && excerpted_buffer == *buffer
 6383                {
 6384                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6385                        let excerpt_range = excerpt_range.to_offset(buffer);
 6386                        buffer
 6387                            .edited_ranges_for_transaction::<usize>(transaction)
 6388                            .all(|range| {
 6389                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6390                            })
 6391                    })?;
 6392
 6393                    if all_edits_within_excerpt {
 6394                        return Ok(());
 6395                    }
 6396                }
 6397            }
 6398        } else {
 6399            return Ok(());
 6400        }
 6401
 6402        let mut ranges_to_highlight = Vec::new();
 6403        let excerpt_buffer = cx.new(|cx| {
 6404            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6405            for (buffer_handle, transaction) in &entries {
 6406                let edited_ranges = buffer_handle
 6407                    .read(cx)
 6408                    .edited_ranges_for_transaction::<Point>(transaction)
 6409                    .collect::<Vec<_>>();
 6410                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6411                    PathKey::for_buffer(buffer_handle, cx),
 6412                    buffer_handle.clone(),
 6413                    edited_ranges,
 6414                    multibuffer_context_lines(cx),
 6415                    cx,
 6416                );
 6417
 6418                ranges_to_highlight.extend(ranges);
 6419            }
 6420            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6421            multibuffer
 6422        })?;
 6423
 6424        workspace.update_in(cx, |workspace, window, cx| {
 6425            let project = workspace.project().clone();
 6426            let editor =
 6427                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6428            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6429            editor.update(cx, |editor, cx| {
 6430                editor.highlight_background::<Self>(
 6431                    &ranges_to_highlight,
 6432                    |theme| theme.colors().editor_highlighted_line_background,
 6433                    cx,
 6434                );
 6435            });
 6436        })?;
 6437
 6438        Ok(())
 6439    }
 6440
 6441    pub fn clear_code_action_providers(&mut self) {
 6442        self.code_action_providers.clear();
 6443        self.available_code_actions.take();
 6444    }
 6445
 6446    pub fn add_code_action_provider(
 6447        &mut self,
 6448        provider: Rc<dyn CodeActionProvider>,
 6449        window: &mut Window,
 6450        cx: &mut Context<Self>,
 6451    ) {
 6452        if self
 6453            .code_action_providers
 6454            .iter()
 6455            .any(|existing_provider| existing_provider.id() == provider.id())
 6456        {
 6457            return;
 6458        }
 6459
 6460        self.code_action_providers.push(provider);
 6461        self.refresh_code_actions(window, cx);
 6462    }
 6463
 6464    pub fn remove_code_action_provider(
 6465        &mut self,
 6466        id: Arc<str>,
 6467        window: &mut Window,
 6468        cx: &mut Context<Self>,
 6469    ) {
 6470        self.code_action_providers
 6471            .retain(|provider| provider.id() != id);
 6472        self.refresh_code_actions(window, cx);
 6473    }
 6474
 6475    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6476        !self.code_action_providers.is_empty()
 6477            && EditorSettings::get_global(cx).toolbar.code_actions
 6478    }
 6479
 6480    pub fn has_available_code_actions(&self) -> bool {
 6481        self.available_code_actions
 6482            .as_ref()
 6483            .is_some_and(|(_, actions)| !actions.is_empty())
 6484    }
 6485
 6486    fn render_inline_code_actions(
 6487        &self,
 6488        icon_size: ui::IconSize,
 6489        display_row: DisplayRow,
 6490        is_active: bool,
 6491        cx: &mut Context<Self>,
 6492    ) -> AnyElement {
 6493        let show_tooltip = !self.context_menu_visible();
 6494        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6495            .icon_size(icon_size)
 6496            .shape(ui::IconButtonShape::Square)
 6497            .icon_color(ui::Color::Hidden)
 6498            .toggle_state(is_active)
 6499            .when(show_tooltip, |this| {
 6500                this.tooltip({
 6501                    let focus_handle = self.focus_handle.clone();
 6502                    move |window, cx| {
 6503                        Tooltip::for_action_in(
 6504                            "Toggle Code Actions",
 6505                            &ToggleCodeActions {
 6506                                deployed_from: None,
 6507                                quick_launch: false,
 6508                            },
 6509                            &focus_handle,
 6510                            window,
 6511                            cx,
 6512                        )
 6513                    }
 6514                })
 6515            })
 6516            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6517                window.focus(&editor.focus_handle(cx));
 6518                editor.toggle_code_actions(
 6519                    &crate::actions::ToggleCodeActions {
 6520                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6521                            display_row,
 6522                        )),
 6523                        quick_launch: false,
 6524                    },
 6525                    window,
 6526                    cx,
 6527                );
 6528            }))
 6529            .into_any_element()
 6530    }
 6531
 6532    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6533        &self.context_menu
 6534    }
 6535
 6536    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6537        let newest_selection = self.selections.newest_anchor().clone();
 6538        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6539        let buffer = self.buffer.read(cx);
 6540        if newest_selection.head().diff_base_anchor.is_some() {
 6541            return None;
 6542        }
 6543        let (start_buffer, start) =
 6544            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6545        let (end_buffer, end) =
 6546            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6547        if start_buffer != end_buffer {
 6548            return None;
 6549        }
 6550
 6551        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6552            cx.background_executor()
 6553                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6554                .await;
 6555
 6556            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6557                let providers = this.code_action_providers.clone();
 6558                let tasks = this
 6559                    .code_action_providers
 6560                    .iter()
 6561                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6562                    .collect::<Vec<_>>();
 6563                (providers, tasks)
 6564            })?;
 6565
 6566            let mut actions = Vec::new();
 6567            for (provider, provider_actions) in
 6568                providers.into_iter().zip(future::join_all(tasks).await)
 6569            {
 6570                if let Some(provider_actions) = provider_actions.log_err() {
 6571                    actions.extend(provider_actions.into_iter().map(|action| {
 6572                        AvailableCodeAction {
 6573                            excerpt_id: newest_selection.start.excerpt_id,
 6574                            action,
 6575                            provider: provider.clone(),
 6576                        }
 6577                    }));
 6578                }
 6579            }
 6580
 6581            this.update(cx, |this, cx| {
 6582                this.available_code_actions = if actions.is_empty() {
 6583                    None
 6584                } else {
 6585                    Some((
 6586                        Location {
 6587                            buffer: start_buffer,
 6588                            range: start..end,
 6589                        },
 6590                        actions.into(),
 6591                    ))
 6592                };
 6593                cx.notify();
 6594            })
 6595        }));
 6596        None
 6597    }
 6598
 6599    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6600        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6601            self.show_git_blame_inline = false;
 6602
 6603            self.show_git_blame_inline_delay_task =
 6604                Some(cx.spawn_in(window, async move |this, cx| {
 6605                    cx.background_executor().timer(delay).await;
 6606
 6607                    this.update(cx, |this, cx| {
 6608                        this.show_git_blame_inline = true;
 6609                        cx.notify();
 6610                    })
 6611                    .log_err();
 6612                }));
 6613        }
 6614    }
 6615
 6616    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6617        let snapshot = self.snapshot(window, cx);
 6618        let cursor = self.selections.newest::<Point>(cx).head();
 6619        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6620        else {
 6621            return;
 6622        };
 6623
 6624        let Some(blame) = self.blame.as_ref() else {
 6625            return;
 6626        };
 6627
 6628        let row_info = RowInfo {
 6629            buffer_id: Some(buffer.remote_id()),
 6630            buffer_row: Some(point.row),
 6631            ..Default::default()
 6632        };
 6633        let Some(blame_entry) = blame
 6634            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6635            .flatten()
 6636        else {
 6637            return;
 6638        };
 6639
 6640        let anchor = self.selections.newest_anchor().head();
 6641        let position = self.to_pixel_point(anchor, &snapshot, window);
 6642        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6643            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6644        };
 6645    }
 6646
 6647    fn show_blame_popover(
 6648        &mut self,
 6649        blame_entry: &BlameEntry,
 6650        position: gpui::Point<Pixels>,
 6651        ignore_timeout: bool,
 6652        cx: &mut Context<Self>,
 6653    ) {
 6654        if let Some(state) = &mut self.inline_blame_popover {
 6655            state.hide_task.take();
 6656        } else {
 6657            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6658            let blame_entry = blame_entry.clone();
 6659            let show_task = cx.spawn(async move |editor, cx| {
 6660                if !ignore_timeout {
 6661                    cx.background_executor()
 6662                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6663                        .await;
 6664                }
 6665                editor
 6666                    .update(cx, |editor, cx| {
 6667                        editor.inline_blame_popover_show_task.take();
 6668                        let Some(blame) = editor.blame.as_ref() else {
 6669                            return;
 6670                        };
 6671                        let blame = blame.read(cx);
 6672                        let details = blame.details_for_entry(&blame_entry);
 6673                        let markdown = cx.new(|cx| {
 6674                            Markdown::new(
 6675                                details
 6676                                    .as_ref()
 6677                                    .map(|message| message.message.clone())
 6678                                    .unwrap_or_default(),
 6679                                None,
 6680                                None,
 6681                                cx,
 6682                            )
 6683                        });
 6684                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6685                            position,
 6686                            hide_task: None,
 6687                            popover_bounds: None,
 6688                            popover_state: InlineBlamePopoverState {
 6689                                scroll_handle: ScrollHandle::new(),
 6690                                commit_message: details,
 6691                                markdown,
 6692                            },
 6693                            keyboard_grace: ignore_timeout,
 6694                        });
 6695                        cx.notify();
 6696                    })
 6697                    .ok();
 6698            });
 6699            self.inline_blame_popover_show_task = Some(show_task);
 6700        }
 6701    }
 6702
 6703    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6704        self.inline_blame_popover_show_task.take();
 6705        if let Some(state) = &mut self.inline_blame_popover {
 6706            let hide_task = cx.spawn(async move |editor, cx| {
 6707                cx.background_executor()
 6708                    .timer(std::time::Duration::from_millis(100))
 6709                    .await;
 6710                editor
 6711                    .update(cx, |editor, cx| {
 6712                        editor.inline_blame_popover.take();
 6713                        cx.notify();
 6714                    })
 6715                    .ok();
 6716            });
 6717            state.hide_task = Some(hide_task);
 6718        }
 6719    }
 6720
 6721    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6722        if self.pending_rename.is_some() {
 6723            return None;
 6724        }
 6725
 6726        let provider = self.semantics_provider.clone()?;
 6727        let buffer = self.buffer.read(cx);
 6728        let newest_selection = self.selections.newest_anchor().clone();
 6729        let cursor_position = newest_selection.head();
 6730        let (cursor_buffer, cursor_buffer_position) =
 6731            buffer.text_anchor_for_position(cursor_position, cx)?;
 6732        let (tail_buffer, tail_buffer_position) =
 6733            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6734        if cursor_buffer != tail_buffer {
 6735            return None;
 6736        }
 6737
 6738        let snapshot = cursor_buffer.read(cx).snapshot();
 6739        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6740        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6741        if start_word_range != end_word_range {
 6742            self.document_highlights_task.take();
 6743            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6744            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6745            return None;
 6746        }
 6747
 6748        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6749        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6750            cx.background_executor()
 6751                .timer(Duration::from_millis(debounce))
 6752                .await;
 6753
 6754            let highlights = if let Some(highlights) = cx
 6755                .update(|cx| {
 6756                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6757                })
 6758                .ok()
 6759                .flatten()
 6760            {
 6761                highlights.await.log_err()
 6762            } else {
 6763                None
 6764            };
 6765
 6766            if let Some(highlights) = highlights {
 6767                this.update(cx, |this, cx| {
 6768                    if this.pending_rename.is_some() {
 6769                        return;
 6770                    }
 6771
 6772                    let buffer = this.buffer.read(cx);
 6773                    if buffer
 6774                        .text_anchor_for_position(cursor_position, cx)
 6775                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6776                    {
 6777                        return;
 6778                    }
 6779
 6780                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6781                    let mut write_ranges = Vec::new();
 6782                    let mut read_ranges = Vec::new();
 6783                    for highlight in highlights {
 6784                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6785                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6786                        {
 6787                            let start = highlight
 6788                                .range
 6789                                .start
 6790                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6791                            let end = highlight
 6792                                .range
 6793                                .end
 6794                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6795                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6796                                continue;
 6797                            }
 6798
 6799                            let range = Anchor {
 6800                                buffer_id: Some(buffer_id),
 6801                                excerpt_id,
 6802                                text_anchor: start,
 6803                                diff_base_anchor: None,
 6804                            }..Anchor {
 6805                                buffer_id: Some(buffer_id),
 6806                                excerpt_id,
 6807                                text_anchor: end,
 6808                                diff_base_anchor: None,
 6809                            };
 6810                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6811                                write_ranges.push(range);
 6812                            } else {
 6813                                read_ranges.push(range);
 6814                            }
 6815                        }
 6816                    }
 6817
 6818                    this.highlight_background::<DocumentHighlightRead>(
 6819                        &read_ranges,
 6820                        |theme| theme.colors().editor_document_highlight_read_background,
 6821                        cx,
 6822                    );
 6823                    this.highlight_background::<DocumentHighlightWrite>(
 6824                        &write_ranges,
 6825                        |theme| theme.colors().editor_document_highlight_write_background,
 6826                        cx,
 6827                    );
 6828                    cx.notify();
 6829                })
 6830                .log_err();
 6831            }
 6832        }));
 6833        None
 6834    }
 6835
 6836    fn prepare_highlight_query_from_selection(
 6837        &mut self,
 6838        cx: &mut Context<Editor>,
 6839    ) -> Option<(String, Range<Anchor>)> {
 6840        if matches!(self.mode, EditorMode::SingleLine) {
 6841            return None;
 6842        }
 6843        if !EditorSettings::get_global(cx).selection_highlight {
 6844            return None;
 6845        }
 6846        if self.selections.count() != 1 || self.selections.line_mode {
 6847            return None;
 6848        }
 6849        let selection = self.selections.newest::<Point>(cx);
 6850        if selection.is_empty() || selection.start.row != selection.end.row {
 6851            return None;
 6852        }
 6853        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6854        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6855        let query = multi_buffer_snapshot
 6856            .text_for_range(selection_anchor_range.clone())
 6857            .collect::<String>();
 6858        if query.trim().is_empty() {
 6859            return None;
 6860        }
 6861        Some((query, selection_anchor_range))
 6862    }
 6863
 6864    fn update_selection_occurrence_highlights(
 6865        &mut self,
 6866        query_text: String,
 6867        query_range: Range<Anchor>,
 6868        multi_buffer_range_to_query: Range<Point>,
 6869        use_debounce: bool,
 6870        window: &mut Window,
 6871        cx: &mut Context<Editor>,
 6872    ) -> Task<()> {
 6873        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6874        cx.spawn_in(window, async move |editor, cx| {
 6875            if use_debounce {
 6876                cx.background_executor()
 6877                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6878                    .await;
 6879            }
 6880            let match_task = cx.background_spawn(async move {
 6881                let buffer_ranges = multi_buffer_snapshot
 6882                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6883                    .into_iter()
 6884                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6885                let mut match_ranges = Vec::new();
 6886                let Ok(regex) = project::search::SearchQuery::text(
 6887                    query_text.clone(),
 6888                    false,
 6889                    false,
 6890                    false,
 6891                    Default::default(),
 6892                    Default::default(),
 6893                    false,
 6894                    None,
 6895                ) else {
 6896                    return Vec::default();
 6897                };
 6898                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6899                    match_ranges.extend(
 6900                        regex
 6901                            .search(buffer_snapshot, Some(search_range.clone()))
 6902                            .await
 6903                            .into_iter()
 6904                            .filter_map(|match_range| {
 6905                                let match_start = buffer_snapshot
 6906                                    .anchor_after(search_range.start + match_range.start);
 6907                                let match_end = buffer_snapshot
 6908                                    .anchor_before(search_range.start + match_range.end);
 6909                                let match_anchor_range = Anchor::range_in_buffer(
 6910                                    excerpt_id,
 6911                                    buffer_snapshot.remote_id(),
 6912                                    match_start..match_end,
 6913                                );
 6914                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6915                            }),
 6916                    );
 6917                }
 6918                match_ranges
 6919            });
 6920            let match_ranges = match_task.await;
 6921            editor
 6922                .update_in(cx, |editor, _, cx| {
 6923                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6924                    if !match_ranges.is_empty() {
 6925                        editor.highlight_background::<SelectedTextHighlight>(
 6926                            &match_ranges,
 6927                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6928                            cx,
 6929                        )
 6930                    }
 6931                })
 6932                .log_err();
 6933        })
 6934    }
 6935
 6936    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6937        struct NewlineFold;
 6938        let type_id = std::any::TypeId::of::<NewlineFold>();
 6939        if !self.mode.is_single_line() {
 6940            return;
 6941        }
 6942        let snapshot = self.snapshot(window, cx);
 6943        if snapshot.buffer_snapshot.max_point().row == 0 {
 6944            return;
 6945        }
 6946        let task = cx.background_spawn(async move {
 6947            let new_newlines = snapshot
 6948                .buffer_chars_at(0)
 6949                .filter_map(|(c, i)| {
 6950                    if c == '\n' {
 6951                        Some(
 6952                            snapshot.buffer_snapshot.anchor_after(i)
 6953                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6954                        )
 6955                    } else {
 6956                        None
 6957                    }
 6958                })
 6959                .collect::<Vec<_>>();
 6960            let existing_newlines = snapshot
 6961                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6962                .filter_map(|fold| {
 6963                    if fold.placeholder.type_tag == Some(type_id) {
 6964                        Some(fold.range.start..fold.range.end)
 6965                    } else {
 6966                        None
 6967                    }
 6968                })
 6969                .collect::<Vec<_>>();
 6970
 6971            (new_newlines, existing_newlines)
 6972        });
 6973        self.folding_newlines = cx.spawn(async move |this, cx| {
 6974            let (new_newlines, existing_newlines) = task.await;
 6975            if new_newlines == existing_newlines {
 6976                return;
 6977            }
 6978            let placeholder = FoldPlaceholder {
 6979                render: Arc::new(move |_, _, cx| {
 6980                    div()
 6981                        .bg(cx.theme().status().hint_background)
 6982                        .border_b_1()
 6983                        .size_full()
 6984                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6985                        .border_color(cx.theme().status().hint)
 6986                        .child("\\n")
 6987                        .into_any()
 6988                }),
 6989                constrain_width: false,
 6990                merge_adjacent: false,
 6991                type_tag: Some(type_id),
 6992            };
 6993            let creases = new_newlines
 6994                .into_iter()
 6995                .map(|range| Crease::simple(range, placeholder.clone()))
 6996                .collect();
 6997            this.update(cx, |this, cx| {
 6998                this.display_map.update(cx, |display_map, cx| {
 6999                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7000                    display_map.fold(creases, cx);
 7001                });
 7002            })
 7003            .ok();
 7004        });
 7005    }
 7006
 7007    fn refresh_selected_text_highlights(
 7008        &mut self,
 7009        on_buffer_edit: bool,
 7010        window: &mut Window,
 7011        cx: &mut Context<Editor>,
 7012    ) {
 7013        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7014        else {
 7015            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7016            self.quick_selection_highlight_task.take();
 7017            self.debounced_selection_highlight_task.take();
 7018            return;
 7019        };
 7020        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7021        if on_buffer_edit
 7022            || self
 7023                .quick_selection_highlight_task
 7024                .as_ref()
 7025                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7026        {
 7027            let multi_buffer_visible_start = self
 7028                .scroll_manager
 7029                .anchor()
 7030                .anchor
 7031                .to_point(&multi_buffer_snapshot);
 7032            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7033                multi_buffer_visible_start
 7034                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7035                Bias::Left,
 7036            );
 7037            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7038            self.quick_selection_highlight_task = Some((
 7039                query_range.clone(),
 7040                self.update_selection_occurrence_highlights(
 7041                    query_text.clone(),
 7042                    query_range.clone(),
 7043                    multi_buffer_visible_range,
 7044                    false,
 7045                    window,
 7046                    cx,
 7047                ),
 7048            ));
 7049        }
 7050        if on_buffer_edit
 7051            || self
 7052                .debounced_selection_highlight_task
 7053                .as_ref()
 7054                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7055        {
 7056            let multi_buffer_start = multi_buffer_snapshot
 7057                .anchor_before(0)
 7058                .to_point(&multi_buffer_snapshot);
 7059            let multi_buffer_end = multi_buffer_snapshot
 7060                .anchor_after(multi_buffer_snapshot.len())
 7061                .to_point(&multi_buffer_snapshot);
 7062            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7063            self.debounced_selection_highlight_task = Some((
 7064                query_range.clone(),
 7065                self.update_selection_occurrence_highlights(
 7066                    query_text,
 7067                    query_range,
 7068                    multi_buffer_full_range,
 7069                    true,
 7070                    window,
 7071                    cx,
 7072                ),
 7073            ));
 7074        }
 7075    }
 7076
 7077    pub fn refresh_edit_prediction(
 7078        &mut self,
 7079        debounce: bool,
 7080        user_requested: bool,
 7081        window: &mut Window,
 7082        cx: &mut Context<Self>,
 7083    ) -> Option<()> {
 7084        if DisableAiSettings::get_global(cx).disable_ai {
 7085            return None;
 7086        }
 7087
 7088        let provider = self.edit_prediction_provider()?;
 7089        let cursor = self.selections.newest_anchor().head();
 7090        let (buffer, cursor_buffer_position) =
 7091            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7092
 7093        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7094            self.discard_edit_prediction(false, cx);
 7095            return None;
 7096        }
 7097
 7098        if !user_requested
 7099            && (!self.should_show_edit_predictions()
 7100                || !self.is_focused(window)
 7101                || buffer.read(cx).is_empty())
 7102        {
 7103            self.discard_edit_prediction(false, cx);
 7104            return None;
 7105        }
 7106
 7107        self.update_visible_edit_prediction(window, cx);
 7108        provider.refresh(
 7109            self.project.clone(),
 7110            buffer,
 7111            cursor_buffer_position,
 7112            debounce,
 7113            cx,
 7114        );
 7115        Some(())
 7116    }
 7117
 7118    fn show_edit_predictions_in_menu(&self) -> bool {
 7119        match self.edit_prediction_settings {
 7120            EditPredictionSettings::Disabled => false,
 7121            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7122        }
 7123    }
 7124
 7125    pub fn edit_predictions_enabled(&self) -> bool {
 7126        match self.edit_prediction_settings {
 7127            EditPredictionSettings::Disabled => false,
 7128            EditPredictionSettings::Enabled { .. } => true,
 7129        }
 7130    }
 7131
 7132    fn edit_prediction_requires_modifier(&self) -> bool {
 7133        match self.edit_prediction_settings {
 7134            EditPredictionSettings::Disabled => false,
 7135            EditPredictionSettings::Enabled {
 7136                preview_requires_modifier,
 7137                ..
 7138            } => preview_requires_modifier,
 7139        }
 7140    }
 7141
 7142    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7143        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7144            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7145            self.discard_edit_prediction(false, cx);
 7146        } else {
 7147            let selection = self.selections.newest_anchor();
 7148            let cursor = selection.head();
 7149
 7150            if let Some((buffer, cursor_buffer_position)) =
 7151                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7152            {
 7153                self.edit_prediction_settings =
 7154                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7155            }
 7156        }
 7157    }
 7158
 7159    fn edit_prediction_settings_at_position(
 7160        &self,
 7161        buffer: &Entity<Buffer>,
 7162        buffer_position: language::Anchor,
 7163        cx: &App,
 7164    ) -> EditPredictionSettings {
 7165        if !self.mode.is_full()
 7166            || !self.show_edit_predictions_override.unwrap_or(true)
 7167            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7168        {
 7169            return EditPredictionSettings::Disabled;
 7170        }
 7171
 7172        let buffer = buffer.read(cx);
 7173
 7174        let file = buffer.file();
 7175
 7176        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7177            return EditPredictionSettings::Disabled;
 7178        };
 7179
 7180        let by_provider = matches!(
 7181            self.menu_edit_predictions_policy,
 7182            MenuEditPredictionsPolicy::ByProvider
 7183        );
 7184
 7185        let show_in_menu = by_provider
 7186            && self
 7187                .edit_prediction_provider
 7188                .as_ref()
 7189                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7190
 7191        let preview_requires_modifier =
 7192            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7193
 7194        EditPredictionSettings::Enabled {
 7195            show_in_menu,
 7196            preview_requires_modifier,
 7197        }
 7198    }
 7199
 7200    fn should_show_edit_predictions(&self) -> bool {
 7201        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7202    }
 7203
 7204    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7205        matches!(
 7206            self.edit_prediction_preview,
 7207            EditPredictionPreview::Active { .. }
 7208        )
 7209    }
 7210
 7211    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7212        let cursor = self.selections.newest_anchor().head();
 7213        if let Some((buffer, cursor_position)) =
 7214            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7215        {
 7216            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7217        } else {
 7218            false
 7219        }
 7220    }
 7221
 7222    pub fn supports_minimap(&self, cx: &App) -> bool {
 7223        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7224    }
 7225
 7226    fn edit_predictions_enabled_in_buffer(
 7227        &self,
 7228        buffer: &Entity<Buffer>,
 7229        buffer_position: language::Anchor,
 7230        cx: &App,
 7231    ) -> bool {
 7232        maybe!({
 7233            if self.read_only(cx) {
 7234                return Some(false);
 7235            }
 7236            let provider = self.edit_prediction_provider()?;
 7237            if !provider.is_enabled(buffer, buffer_position, cx) {
 7238                return Some(false);
 7239            }
 7240            let buffer = buffer.read(cx);
 7241            let Some(file) = buffer.file() else {
 7242                return Some(true);
 7243            };
 7244            let settings = all_language_settings(Some(file), cx);
 7245            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7246        })
 7247        .unwrap_or(false)
 7248    }
 7249
 7250    fn cycle_edit_prediction(
 7251        &mut self,
 7252        direction: Direction,
 7253        window: &mut Window,
 7254        cx: &mut Context<Self>,
 7255    ) -> Option<()> {
 7256        let provider = self.edit_prediction_provider()?;
 7257        let cursor = self.selections.newest_anchor().head();
 7258        let (buffer, cursor_buffer_position) =
 7259            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7260        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7261            return None;
 7262        }
 7263
 7264        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7265        self.update_visible_edit_prediction(window, cx);
 7266
 7267        Some(())
 7268    }
 7269
 7270    pub fn show_edit_prediction(
 7271        &mut self,
 7272        _: &ShowEditPrediction,
 7273        window: &mut Window,
 7274        cx: &mut Context<Self>,
 7275    ) {
 7276        if !self.has_active_edit_prediction() {
 7277            self.refresh_edit_prediction(false, true, window, cx);
 7278            return;
 7279        }
 7280
 7281        self.update_visible_edit_prediction(window, cx);
 7282    }
 7283
 7284    pub fn display_cursor_names(
 7285        &mut self,
 7286        _: &DisplayCursorNames,
 7287        window: &mut Window,
 7288        cx: &mut Context<Self>,
 7289    ) {
 7290        self.show_cursor_names(window, cx);
 7291    }
 7292
 7293    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7294        self.show_cursor_names = true;
 7295        cx.notify();
 7296        cx.spawn_in(window, async move |this, cx| {
 7297            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7298            this.update(cx, |this, cx| {
 7299                this.show_cursor_names = false;
 7300                cx.notify()
 7301            })
 7302            .ok()
 7303        })
 7304        .detach();
 7305    }
 7306
 7307    pub fn next_edit_prediction(
 7308        &mut self,
 7309        _: &NextEditPrediction,
 7310        window: &mut Window,
 7311        cx: &mut Context<Self>,
 7312    ) {
 7313        if self.has_active_edit_prediction() {
 7314            self.cycle_edit_prediction(Direction::Next, window, cx);
 7315        } else {
 7316            let is_copilot_disabled = self
 7317                .refresh_edit_prediction(false, true, window, cx)
 7318                .is_none();
 7319            if is_copilot_disabled {
 7320                cx.propagate();
 7321            }
 7322        }
 7323    }
 7324
 7325    pub fn previous_edit_prediction(
 7326        &mut self,
 7327        _: &PreviousEditPrediction,
 7328        window: &mut Window,
 7329        cx: &mut Context<Self>,
 7330    ) {
 7331        if self.has_active_edit_prediction() {
 7332            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7333        } else {
 7334            let is_copilot_disabled = self
 7335                .refresh_edit_prediction(false, true, window, cx)
 7336                .is_none();
 7337            if is_copilot_disabled {
 7338                cx.propagate();
 7339            }
 7340        }
 7341    }
 7342
 7343    pub fn accept_edit_prediction(
 7344        &mut self,
 7345        _: &AcceptEditPrediction,
 7346        window: &mut Window,
 7347        cx: &mut Context<Self>,
 7348    ) {
 7349        if self.show_edit_predictions_in_menu() {
 7350            self.hide_context_menu(window, cx);
 7351        }
 7352
 7353        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7354            return;
 7355        };
 7356
 7357        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7358
 7359        match &active_edit_prediction.completion {
 7360            EditPrediction::Move { target, .. } => {
 7361                let target = *target;
 7362
 7363                if let Some(position_map) = &self.last_position_map {
 7364                    if position_map
 7365                        .visible_row_range
 7366                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7367                        || !self.edit_prediction_requires_modifier()
 7368                    {
 7369                        self.unfold_ranges(&[target..target], true, false, cx);
 7370                        // Note that this is also done in vim's handler of the Tab action.
 7371                        self.change_selections(
 7372                            SelectionEffects::scroll(Autoscroll::newest()),
 7373                            window,
 7374                            cx,
 7375                            |selections| {
 7376                                selections.select_anchor_ranges([target..target]);
 7377                            },
 7378                        );
 7379                        self.clear_row_highlights::<EditPredictionPreview>();
 7380
 7381                        self.edit_prediction_preview
 7382                            .set_previous_scroll_position(None);
 7383                    } else {
 7384                        self.edit_prediction_preview
 7385                            .set_previous_scroll_position(Some(
 7386                                position_map.snapshot.scroll_anchor,
 7387                            ));
 7388
 7389                        self.highlight_rows::<EditPredictionPreview>(
 7390                            target..target,
 7391                            cx.theme().colors().editor_highlighted_line_background,
 7392                            RowHighlightOptions {
 7393                                autoscroll: true,
 7394                                ..Default::default()
 7395                            },
 7396                            cx,
 7397                        );
 7398                        self.request_autoscroll(Autoscroll::fit(), cx);
 7399                    }
 7400                }
 7401            }
 7402            EditPrediction::Edit { edits, .. } => {
 7403                if let Some(provider) = self.edit_prediction_provider() {
 7404                    provider.accept(cx);
 7405                }
 7406
 7407                // Store the transaction ID and selections before applying the edit
 7408                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7409
 7410                let snapshot = self.buffer.read(cx).snapshot(cx);
 7411                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7412
 7413                self.buffer.update(cx, |buffer, cx| {
 7414                    buffer.edit(edits.iter().cloned(), None, cx)
 7415                });
 7416
 7417                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7418                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7419                });
 7420
 7421                let selections = self.selections.disjoint_anchors();
 7422                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7423                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7424                    if has_new_transaction {
 7425                        self.selection_history
 7426                            .insert_transaction(transaction_id_now, selections);
 7427                    }
 7428                }
 7429
 7430                self.update_visible_edit_prediction(window, cx);
 7431                if self.active_edit_prediction.is_none() {
 7432                    self.refresh_edit_prediction(true, true, window, cx);
 7433                }
 7434
 7435                cx.notify();
 7436            }
 7437        }
 7438
 7439        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7440    }
 7441
 7442    pub fn accept_partial_edit_prediction(
 7443        &mut self,
 7444        _: &AcceptPartialEditPrediction,
 7445        window: &mut Window,
 7446        cx: &mut Context<Self>,
 7447    ) {
 7448        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7449            return;
 7450        };
 7451        if self.selections.count() != 1 {
 7452            return;
 7453        }
 7454
 7455        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7456
 7457        match &active_edit_prediction.completion {
 7458            EditPrediction::Move { target, .. } => {
 7459                let target = *target;
 7460                self.change_selections(
 7461                    SelectionEffects::scroll(Autoscroll::newest()),
 7462                    window,
 7463                    cx,
 7464                    |selections| {
 7465                        selections.select_anchor_ranges([target..target]);
 7466                    },
 7467                );
 7468            }
 7469            EditPrediction::Edit { edits, .. } => {
 7470                // Find an insertion that starts at the cursor position.
 7471                let snapshot = self.buffer.read(cx).snapshot(cx);
 7472                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7473                let insertion = edits.iter().find_map(|(range, text)| {
 7474                    let range = range.to_offset(&snapshot);
 7475                    if range.is_empty() && range.start == cursor_offset {
 7476                        Some(text)
 7477                    } else {
 7478                        None
 7479                    }
 7480                });
 7481
 7482                if let Some(text) = insertion {
 7483                    let mut partial_completion = text
 7484                        .chars()
 7485                        .by_ref()
 7486                        .take_while(|c| c.is_alphabetic())
 7487                        .collect::<String>();
 7488                    if partial_completion.is_empty() {
 7489                        partial_completion = text
 7490                            .chars()
 7491                            .by_ref()
 7492                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7493                            .collect::<String>();
 7494                    }
 7495
 7496                    cx.emit(EditorEvent::InputHandled {
 7497                        utf16_range_to_replace: None,
 7498                        text: partial_completion.clone().into(),
 7499                    });
 7500
 7501                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7502
 7503                    self.refresh_edit_prediction(true, true, window, cx);
 7504                    cx.notify();
 7505                } else {
 7506                    self.accept_edit_prediction(&Default::default(), window, cx);
 7507                }
 7508            }
 7509        }
 7510    }
 7511
 7512    fn discard_edit_prediction(
 7513        &mut self,
 7514        should_report_edit_prediction_event: bool,
 7515        cx: &mut Context<Self>,
 7516    ) -> bool {
 7517        if should_report_edit_prediction_event {
 7518            let completion_id = self
 7519                .active_edit_prediction
 7520                .as_ref()
 7521                .and_then(|active_completion| active_completion.completion_id.clone());
 7522
 7523            self.report_edit_prediction_event(completion_id, false, cx);
 7524        }
 7525
 7526        if let Some(provider) = self.edit_prediction_provider() {
 7527            provider.discard(cx);
 7528        }
 7529
 7530        self.take_active_edit_prediction(cx)
 7531    }
 7532
 7533    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7534        let Some(provider) = self.edit_prediction_provider() else {
 7535            return;
 7536        };
 7537
 7538        let Some((_, buffer, _)) = self
 7539            .buffer
 7540            .read(cx)
 7541            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7542        else {
 7543            return;
 7544        };
 7545
 7546        let extension = buffer
 7547            .read(cx)
 7548            .file()
 7549            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7550
 7551        let event_type = match accepted {
 7552            true => "Edit Prediction Accepted",
 7553            false => "Edit Prediction Discarded",
 7554        };
 7555        telemetry::event!(
 7556            event_type,
 7557            provider = provider.name(),
 7558            prediction_id = id,
 7559            suggestion_accepted = accepted,
 7560            file_extension = extension,
 7561        );
 7562    }
 7563
 7564    pub fn has_active_edit_prediction(&self) -> bool {
 7565        self.active_edit_prediction.is_some()
 7566    }
 7567
 7568    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7569        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7570            return false;
 7571        };
 7572
 7573        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7574        self.clear_highlights::<EditPredictionHighlight>(cx);
 7575        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7576        true
 7577    }
 7578
 7579    /// Returns true when we're displaying the edit prediction popover below the cursor
 7580    /// like we are not previewing and the LSP autocomplete menu is visible
 7581    /// or we are in `when_holding_modifier` mode.
 7582    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7583        if self.edit_prediction_preview_is_active()
 7584            || !self.show_edit_predictions_in_menu()
 7585            || !self.edit_predictions_enabled()
 7586        {
 7587            return false;
 7588        }
 7589
 7590        if self.has_visible_completions_menu() {
 7591            return true;
 7592        }
 7593
 7594        has_completion && self.edit_prediction_requires_modifier()
 7595    }
 7596
 7597    fn handle_modifiers_changed(
 7598        &mut self,
 7599        modifiers: Modifiers,
 7600        position_map: &PositionMap,
 7601        window: &mut Window,
 7602        cx: &mut Context<Self>,
 7603    ) {
 7604        if self.show_edit_predictions_in_menu() {
 7605            self.update_edit_prediction_preview(&modifiers, window, cx);
 7606        }
 7607
 7608        self.update_selection_mode(&modifiers, position_map, window, cx);
 7609
 7610        let mouse_position = window.mouse_position();
 7611        if !position_map.text_hitbox.is_hovered(window) {
 7612            return;
 7613        }
 7614
 7615        self.update_hovered_link(
 7616            position_map.point_for_position(mouse_position),
 7617            &position_map.snapshot,
 7618            modifiers,
 7619            window,
 7620            cx,
 7621        )
 7622    }
 7623
 7624    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7625        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7626        if invert {
 7627            match multi_cursor_setting {
 7628                MultiCursorModifier::Alt => modifiers.alt,
 7629                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7630            }
 7631        } else {
 7632            match multi_cursor_setting {
 7633                MultiCursorModifier::Alt => modifiers.secondary(),
 7634                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7635            }
 7636        }
 7637    }
 7638
 7639    fn columnar_selection_mode(
 7640        modifiers: &Modifiers,
 7641        cx: &mut Context<Self>,
 7642    ) -> Option<ColumnarMode> {
 7643        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7644            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7645                Some(ColumnarMode::FromMouse)
 7646            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7647                Some(ColumnarMode::FromSelection)
 7648            } else {
 7649                None
 7650            }
 7651        } else {
 7652            None
 7653        }
 7654    }
 7655
 7656    fn update_selection_mode(
 7657        &mut self,
 7658        modifiers: &Modifiers,
 7659        position_map: &PositionMap,
 7660        window: &mut Window,
 7661        cx: &mut Context<Self>,
 7662    ) {
 7663        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7664            return;
 7665        };
 7666        if self.selections.pending.is_none() {
 7667            return;
 7668        }
 7669
 7670        let mouse_position = window.mouse_position();
 7671        let point_for_position = position_map.point_for_position(mouse_position);
 7672        let position = point_for_position.previous_valid;
 7673
 7674        self.select(
 7675            SelectPhase::BeginColumnar {
 7676                position,
 7677                reset: false,
 7678                mode,
 7679                goal_column: point_for_position.exact_unclipped.column(),
 7680            },
 7681            window,
 7682            cx,
 7683        );
 7684    }
 7685
 7686    fn update_edit_prediction_preview(
 7687        &mut self,
 7688        modifiers: &Modifiers,
 7689        window: &mut Window,
 7690        cx: &mut Context<Self>,
 7691    ) {
 7692        let mut modifiers_held = false;
 7693        if let Some(accept_keystroke) = self
 7694            .accept_edit_prediction_keybind(false, window, cx)
 7695            .keystroke()
 7696        {
 7697            modifiers_held = modifiers_held
 7698                || (accept_keystroke.modifiers() == modifiers
 7699                    && accept_keystroke.modifiers().modified());
 7700        };
 7701        if let Some(accept_partial_keystroke) = self
 7702            .accept_edit_prediction_keybind(true, window, cx)
 7703            .keystroke()
 7704        {
 7705            modifiers_held = modifiers_held
 7706                || (accept_partial_keystroke.modifiers() == modifiers
 7707                    && accept_partial_keystroke.modifiers().modified());
 7708        }
 7709
 7710        if modifiers_held {
 7711            if matches!(
 7712                self.edit_prediction_preview,
 7713                EditPredictionPreview::Inactive { .. }
 7714            ) {
 7715                self.edit_prediction_preview = EditPredictionPreview::Active {
 7716                    previous_scroll_position: None,
 7717                    since: Instant::now(),
 7718                };
 7719
 7720                self.update_visible_edit_prediction(window, cx);
 7721                cx.notify();
 7722            }
 7723        } else if let EditPredictionPreview::Active {
 7724            previous_scroll_position,
 7725            since,
 7726        } = self.edit_prediction_preview
 7727        {
 7728            if let (Some(previous_scroll_position), Some(position_map)) =
 7729                (previous_scroll_position, self.last_position_map.as_ref())
 7730            {
 7731                self.set_scroll_position(
 7732                    previous_scroll_position
 7733                        .scroll_position(&position_map.snapshot.display_snapshot),
 7734                    window,
 7735                    cx,
 7736                );
 7737            }
 7738
 7739            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7740                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7741            };
 7742            self.clear_row_highlights::<EditPredictionPreview>();
 7743            self.update_visible_edit_prediction(window, cx);
 7744            cx.notify();
 7745        }
 7746    }
 7747
 7748    fn update_visible_edit_prediction(
 7749        &mut self,
 7750        _window: &mut Window,
 7751        cx: &mut Context<Self>,
 7752    ) -> Option<()> {
 7753        if DisableAiSettings::get_global(cx).disable_ai {
 7754            return None;
 7755        }
 7756
 7757        if self.ime_transaction.is_some() {
 7758            self.discard_edit_prediction(false, cx);
 7759            return None;
 7760        }
 7761
 7762        let selection = self.selections.newest_anchor();
 7763        let cursor = selection.head();
 7764        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7765        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7766        let excerpt_id = cursor.excerpt_id;
 7767
 7768        let show_in_menu = self.show_edit_predictions_in_menu();
 7769        let completions_menu_has_precedence = !show_in_menu
 7770            && (self.context_menu.borrow().is_some()
 7771                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7772
 7773        if completions_menu_has_precedence
 7774            || !offset_selection.is_empty()
 7775            || self
 7776                .active_edit_prediction
 7777                .as_ref()
 7778                .is_some_and(|completion| {
 7779                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7780                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7781                    !invalidation_range.contains(&offset_selection.head())
 7782                })
 7783        {
 7784            self.discard_edit_prediction(false, cx);
 7785            return None;
 7786        }
 7787
 7788        self.take_active_edit_prediction(cx);
 7789        let Some(provider) = self.edit_prediction_provider() else {
 7790            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7791            return None;
 7792        };
 7793
 7794        let (buffer, cursor_buffer_position) =
 7795            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7796
 7797        self.edit_prediction_settings =
 7798            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7799
 7800        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7801            self.discard_edit_prediction(false, cx);
 7802            return None;
 7803        };
 7804
 7805        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7806
 7807        if self.edit_prediction_indent_conflict {
 7808            let cursor_point = cursor.to_point(&multibuffer);
 7809
 7810            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7811
 7812            if let Some((_, indent)) = indents.iter().next()
 7813                && indent.len == cursor_point.column
 7814            {
 7815                self.edit_prediction_indent_conflict = false;
 7816            }
 7817        }
 7818
 7819        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7820        let edits = edit_prediction
 7821            .edits
 7822            .into_iter()
 7823            .flat_map(|(range, new_text)| {
 7824                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7825                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7826                Some((start..end, new_text))
 7827            })
 7828            .collect::<Vec<_>>();
 7829        if edits.is_empty() {
 7830            return None;
 7831        }
 7832
 7833        let first_edit_start = edits.first().unwrap().0.start;
 7834        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7835        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7836
 7837        let last_edit_end = edits.last().unwrap().0.end;
 7838        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7839        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7840
 7841        let cursor_row = cursor.to_point(&multibuffer).row;
 7842
 7843        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7844
 7845        let mut inlay_ids = Vec::new();
 7846        let invalidation_row_range;
 7847        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7848            Some(cursor_row..edit_end_row)
 7849        } else if cursor_row > edit_end_row {
 7850            Some(edit_start_row..cursor_row)
 7851        } else {
 7852            None
 7853        };
 7854        let supports_jump = self
 7855            .edit_prediction_provider
 7856            .as_ref()
 7857            .map(|provider| provider.provider.supports_jump_to_edit())
 7858            .unwrap_or(true);
 7859
 7860        let is_move = supports_jump
 7861            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7862        let completion = if is_move {
 7863            invalidation_row_range =
 7864                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7865            let target = first_edit_start;
 7866            EditPrediction::Move { target, snapshot }
 7867        } else {
 7868            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7869                && !self.edit_predictions_hidden_for_vim_mode;
 7870
 7871            if show_completions_in_buffer {
 7872                if edits
 7873                    .iter()
 7874                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7875                {
 7876                    let mut inlays = Vec::new();
 7877                    for (range, new_text) in &edits {
 7878                        let inlay = Inlay::edit_prediction(
 7879                            post_inc(&mut self.next_inlay_id),
 7880                            range.start,
 7881                            new_text.as_str(),
 7882                        );
 7883                        inlay_ids.push(inlay.id);
 7884                        inlays.push(inlay);
 7885                    }
 7886
 7887                    self.splice_inlays(&[], inlays, cx);
 7888                } else {
 7889                    let background_color = cx.theme().status().deleted_background;
 7890                    self.highlight_text::<EditPredictionHighlight>(
 7891                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7892                        HighlightStyle {
 7893                            background_color: Some(background_color),
 7894                            ..Default::default()
 7895                        },
 7896                        cx,
 7897                    );
 7898                }
 7899            }
 7900
 7901            invalidation_row_range = edit_start_row..edit_end_row;
 7902
 7903            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7904                if provider.show_tab_accept_marker() {
 7905                    EditDisplayMode::TabAccept
 7906                } else {
 7907                    EditDisplayMode::Inline
 7908                }
 7909            } else {
 7910                EditDisplayMode::DiffPopover
 7911            };
 7912
 7913            EditPrediction::Edit {
 7914                edits,
 7915                edit_preview: edit_prediction.edit_preview,
 7916                display_mode,
 7917                snapshot,
 7918            }
 7919        };
 7920
 7921        let invalidation_range = multibuffer
 7922            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7923            ..multibuffer.anchor_after(Point::new(
 7924                invalidation_row_range.end,
 7925                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7926            ));
 7927
 7928        self.stale_edit_prediction_in_menu = None;
 7929        self.active_edit_prediction = Some(EditPredictionState {
 7930            inlay_ids,
 7931            completion,
 7932            completion_id: edit_prediction.id,
 7933            invalidation_range,
 7934        });
 7935
 7936        cx.notify();
 7937
 7938        Some(())
 7939    }
 7940
 7941    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7942        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7943    }
 7944
 7945    fn clear_tasks(&mut self) {
 7946        self.tasks.clear()
 7947    }
 7948
 7949    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7950        if self.tasks.insert(key, value).is_some() {
 7951            // This case should hopefully be rare, but just in case...
 7952            log::error!(
 7953                "multiple different run targets found on a single line, only the last target will be rendered"
 7954            )
 7955        }
 7956    }
 7957
 7958    /// Get all display points of breakpoints that will be rendered within editor
 7959    ///
 7960    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7961    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7962    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7963    fn active_breakpoints(
 7964        &self,
 7965        range: Range<DisplayRow>,
 7966        window: &mut Window,
 7967        cx: &mut Context<Self>,
 7968    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7969        let mut breakpoint_display_points = HashMap::default();
 7970
 7971        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7972            return breakpoint_display_points;
 7973        };
 7974
 7975        let snapshot = self.snapshot(window, cx);
 7976
 7977        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7978        let Some(project) = self.project() else {
 7979            return breakpoint_display_points;
 7980        };
 7981
 7982        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7983            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7984
 7985        for (buffer_snapshot, range, excerpt_id) in
 7986            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7987        {
 7988            let Some(buffer) = project
 7989                .read(cx)
 7990                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7991            else {
 7992                continue;
 7993            };
 7994            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7995                &buffer,
 7996                Some(
 7997                    buffer_snapshot.anchor_before(range.start)
 7998                        ..buffer_snapshot.anchor_after(range.end),
 7999                ),
 8000                buffer_snapshot,
 8001                cx,
 8002            );
 8003            for (breakpoint, state) in breakpoints {
 8004                let multi_buffer_anchor =
 8005                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8006                let position = multi_buffer_anchor
 8007                    .to_point(multi_buffer_snapshot)
 8008                    .to_display_point(&snapshot);
 8009
 8010                breakpoint_display_points.insert(
 8011                    position.row(),
 8012                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8013                );
 8014            }
 8015        }
 8016
 8017        breakpoint_display_points
 8018    }
 8019
 8020    fn breakpoint_context_menu(
 8021        &self,
 8022        anchor: Anchor,
 8023        window: &mut Window,
 8024        cx: &mut Context<Self>,
 8025    ) -> Entity<ui::ContextMenu> {
 8026        let weak_editor = cx.weak_entity();
 8027        let focus_handle = self.focus_handle(cx);
 8028
 8029        let row = self
 8030            .buffer
 8031            .read(cx)
 8032            .snapshot(cx)
 8033            .summary_for_anchor::<Point>(&anchor)
 8034            .row;
 8035
 8036        let breakpoint = self
 8037            .breakpoint_at_row(row, window, cx)
 8038            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8039
 8040        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8041            "Edit Log Breakpoint"
 8042        } else {
 8043            "Set Log Breakpoint"
 8044        };
 8045
 8046        let condition_breakpoint_msg = if breakpoint
 8047            .as_ref()
 8048            .is_some_and(|bp| bp.1.condition.is_some())
 8049        {
 8050            "Edit Condition Breakpoint"
 8051        } else {
 8052            "Set Condition Breakpoint"
 8053        };
 8054
 8055        let hit_condition_breakpoint_msg = if breakpoint
 8056            .as_ref()
 8057            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8058        {
 8059            "Edit Hit Condition Breakpoint"
 8060        } else {
 8061            "Set Hit Condition Breakpoint"
 8062        };
 8063
 8064        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8065            "Unset Breakpoint"
 8066        } else {
 8067            "Set Breakpoint"
 8068        };
 8069
 8070        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8071
 8072        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8073            BreakpointState::Enabled => Some("Disable"),
 8074            BreakpointState::Disabled => Some("Enable"),
 8075        });
 8076
 8077        let (anchor, breakpoint) =
 8078            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8079
 8080        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8081            menu.on_blur_subscription(Subscription::new(|| {}))
 8082                .context(focus_handle)
 8083                .when(run_to_cursor, |this| {
 8084                    let weak_editor = weak_editor.clone();
 8085                    this.entry("Run to cursor", None, move |window, cx| {
 8086                        weak_editor
 8087                            .update(cx, |editor, cx| {
 8088                                editor.change_selections(
 8089                                    SelectionEffects::no_scroll(),
 8090                                    window,
 8091                                    cx,
 8092                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8093                                );
 8094                            })
 8095                            .ok();
 8096
 8097                        window.dispatch_action(Box::new(RunToCursor), cx);
 8098                    })
 8099                    .separator()
 8100                })
 8101                .when_some(toggle_state_msg, |this, msg| {
 8102                    this.entry(msg, None, {
 8103                        let weak_editor = weak_editor.clone();
 8104                        let breakpoint = breakpoint.clone();
 8105                        move |_window, cx| {
 8106                            weak_editor
 8107                                .update(cx, |this, cx| {
 8108                                    this.edit_breakpoint_at_anchor(
 8109                                        anchor,
 8110                                        breakpoint.as_ref().clone(),
 8111                                        BreakpointEditAction::InvertState,
 8112                                        cx,
 8113                                    );
 8114                                })
 8115                                .log_err();
 8116                        }
 8117                    })
 8118                })
 8119                .entry(set_breakpoint_msg, None, {
 8120                    let weak_editor = weak_editor.clone();
 8121                    let breakpoint = breakpoint.clone();
 8122                    move |_window, cx| {
 8123                        weak_editor
 8124                            .update(cx, |this, cx| {
 8125                                this.edit_breakpoint_at_anchor(
 8126                                    anchor,
 8127                                    breakpoint.as_ref().clone(),
 8128                                    BreakpointEditAction::Toggle,
 8129                                    cx,
 8130                                );
 8131                            })
 8132                            .log_err();
 8133                    }
 8134                })
 8135                .entry(log_breakpoint_msg, None, {
 8136                    let breakpoint = breakpoint.clone();
 8137                    let weak_editor = weak_editor.clone();
 8138                    move |window, cx| {
 8139                        weak_editor
 8140                            .update(cx, |this, cx| {
 8141                                this.add_edit_breakpoint_block(
 8142                                    anchor,
 8143                                    breakpoint.as_ref(),
 8144                                    BreakpointPromptEditAction::Log,
 8145                                    window,
 8146                                    cx,
 8147                                );
 8148                            })
 8149                            .log_err();
 8150                    }
 8151                })
 8152                .entry(condition_breakpoint_msg, None, {
 8153                    let breakpoint = breakpoint.clone();
 8154                    let weak_editor = weak_editor.clone();
 8155                    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::Condition,
 8162                                    window,
 8163                                    cx,
 8164                                );
 8165                            })
 8166                            .log_err();
 8167                    }
 8168                })
 8169                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8170                    weak_editor
 8171                        .update(cx, |this, cx| {
 8172                            this.add_edit_breakpoint_block(
 8173                                anchor,
 8174                                breakpoint.as_ref(),
 8175                                BreakpointPromptEditAction::HitCondition,
 8176                                window,
 8177                                cx,
 8178                            );
 8179                        })
 8180                        .log_err();
 8181                })
 8182        })
 8183    }
 8184
 8185    fn render_breakpoint(
 8186        &self,
 8187        position: Anchor,
 8188        row: DisplayRow,
 8189        breakpoint: &Breakpoint,
 8190        state: Option<BreakpointSessionState>,
 8191        cx: &mut Context<Self>,
 8192    ) -> IconButton {
 8193        let is_rejected = state.is_some_and(|s| !s.verified);
 8194        // Is it a breakpoint that shows up when hovering over gutter?
 8195        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8196            (false, false),
 8197            |PhantomBreakpointIndicator {
 8198                 is_active,
 8199                 display_row,
 8200                 collides_with_existing_breakpoint,
 8201             }| {
 8202                (
 8203                    is_active && display_row == row,
 8204                    collides_with_existing_breakpoint,
 8205                )
 8206            },
 8207        );
 8208
 8209        let (color, icon) = {
 8210            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8211                (false, false) => ui::IconName::DebugBreakpoint,
 8212                (true, false) => ui::IconName::DebugLogBreakpoint,
 8213                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8214                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8215            };
 8216
 8217            let color = if is_phantom {
 8218                Color::Hint
 8219            } else if is_rejected {
 8220                Color::Disabled
 8221            } else {
 8222                Color::Debugger
 8223            };
 8224
 8225            (color, icon)
 8226        };
 8227
 8228        let breakpoint = Arc::from(breakpoint.clone());
 8229
 8230        let alt_as_text = gpui::Keystroke {
 8231            modifiers: Modifiers::secondary_key(),
 8232            ..Default::default()
 8233        };
 8234        let primary_action_text = if breakpoint.is_disabled() {
 8235            "Enable breakpoint"
 8236        } else if is_phantom && !collides_with_existing {
 8237            "Set breakpoint"
 8238        } else {
 8239            "Unset breakpoint"
 8240        };
 8241        let focus_handle = self.focus_handle.clone();
 8242
 8243        let meta = if is_rejected {
 8244            SharedString::from("No executable code is associated with this line.")
 8245        } else if collides_with_existing && !breakpoint.is_disabled() {
 8246            SharedString::from(format!(
 8247                "{alt_as_text}-click to disable,\nright-click for more options."
 8248            ))
 8249        } else {
 8250            SharedString::from("Right-click for more options.")
 8251        };
 8252        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8253            .icon_size(IconSize::XSmall)
 8254            .size(ui::ButtonSize::None)
 8255            .when(is_rejected, |this| {
 8256                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8257            })
 8258            .icon_color(color)
 8259            .style(ButtonStyle::Transparent)
 8260            .on_click(cx.listener({
 8261                move |editor, event: &ClickEvent, window, cx| {
 8262                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8263                        BreakpointEditAction::InvertState
 8264                    } else {
 8265                        BreakpointEditAction::Toggle
 8266                    };
 8267
 8268                    window.focus(&editor.focus_handle(cx));
 8269                    editor.edit_breakpoint_at_anchor(
 8270                        position,
 8271                        breakpoint.as_ref().clone(),
 8272                        edit_action,
 8273                        cx,
 8274                    );
 8275                }
 8276            }))
 8277            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8278                editor.set_breakpoint_context_menu(
 8279                    row,
 8280                    Some(position),
 8281                    event.position(),
 8282                    window,
 8283                    cx,
 8284                );
 8285            }))
 8286            .tooltip(move |window, cx| {
 8287                Tooltip::with_meta_in(
 8288                    primary_action_text,
 8289                    Some(&ToggleBreakpoint),
 8290                    meta.clone(),
 8291                    &focus_handle,
 8292                    window,
 8293                    cx,
 8294                )
 8295            })
 8296    }
 8297
 8298    fn build_tasks_context(
 8299        project: &Entity<Project>,
 8300        buffer: &Entity<Buffer>,
 8301        buffer_row: u32,
 8302        tasks: &Arc<RunnableTasks>,
 8303        cx: &mut Context<Self>,
 8304    ) -> Task<Option<task::TaskContext>> {
 8305        let position = Point::new(buffer_row, tasks.column);
 8306        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8307        let location = Location {
 8308            buffer: buffer.clone(),
 8309            range: range_start..range_start,
 8310        };
 8311        // Fill in the environmental variables from the tree-sitter captures
 8312        let mut captured_task_variables = TaskVariables::default();
 8313        for (capture_name, value) in tasks.extra_variables.clone() {
 8314            captured_task_variables.insert(
 8315                task::VariableName::Custom(capture_name.into()),
 8316                value.clone(),
 8317            );
 8318        }
 8319        project.update(cx, |project, cx| {
 8320            project.task_store().update(cx, |task_store, cx| {
 8321                task_store.task_context_for_location(captured_task_variables, location, cx)
 8322            })
 8323        })
 8324    }
 8325
 8326    pub fn spawn_nearest_task(
 8327        &mut self,
 8328        action: &SpawnNearestTask,
 8329        window: &mut Window,
 8330        cx: &mut Context<Self>,
 8331    ) {
 8332        let Some((workspace, _)) = self.workspace.clone() else {
 8333            return;
 8334        };
 8335        let Some(project) = self.project.clone() else {
 8336            return;
 8337        };
 8338
 8339        // Try to find a closest, enclosing node using tree-sitter that has a task
 8340        let Some((buffer, buffer_row, tasks)) = self
 8341            .find_enclosing_node_task(cx)
 8342            // Or find the task that's closest in row-distance.
 8343            .or_else(|| self.find_closest_task(cx))
 8344        else {
 8345            return;
 8346        };
 8347
 8348        let reveal_strategy = action.reveal;
 8349        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8350        cx.spawn_in(window, async move |_, cx| {
 8351            let context = task_context.await?;
 8352            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8353
 8354            let resolved = &mut resolved_task.resolved;
 8355            resolved.reveal = reveal_strategy;
 8356
 8357            workspace
 8358                .update_in(cx, |workspace, window, cx| {
 8359                    workspace.schedule_resolved_task(
 8360                        task_source_kind,
 8361                        resolved_task,
 8362                        false,
 8363                        window,
 8364                        cx,
 8365                    );
 8366                })
 8367                .ok()
 8368        })
 8369        .detach();
 8370    }
 8371
 8372    fn find_closest_task(
 8373        &mut self,
 8374        cx: &mut Context<Self>,
 8375    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8376        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8377
 8378        let ((buffer_id, row), tasks) = self
 8379            .tasks
 8380            .iter()
 8381            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8382
 8383        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8384        let tasks = Arc::new(tasks.to_owned());
 8385        Some((buffer, *row, tasks))
 8386    }
 8387
 8388    fn find_enclosing_node_task(
 8389        &mut self,
 8390        cx: &mut Context<Self>,
 8391    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8392        let snapshot = self.buffer.read(cx).snapshot(cx);
 8393        let offset = self.selections.newest::<usize>(cx).head();
 8394        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8395        let buffer_id = excerpt.buffer().remote_id();
 8396
 8397        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8398        let mut cursor = layer.node().walk();
 8399
 8400        while cursor.goto_first_child_for_byte(offset).is_some() {
 8401            if cursor.node().end_byte() == offset {
 8402                cursor.goto_next_sibling();
 8403            }
 8404        }
 8405
 8406        // Ascend to the smallest ancestor that contains the range and has a task.
 8407        loop {
 8408            let node = cursor.node();
 8409            let node_range = node.byte_range();
 8410            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8411
 8412            // Check if this node contains our offset
 8413            if node_range.start <= offset && node_range.end >= offset {
 8414                // If it contains offset, check for task
 8415                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8416                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8417                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8418                }
 8419            }
 8420
 8421            if !cursor.goto_parent() {
 8422                break;
 8423            }
 8424        }
 8425        None
 8426    }
 8427
 8428    fn render_run_indicator(
 8429        &self,
 8430        _style: &EditorStyle,
 8431        is_active: bool,
 8432        row: DisplayRow,
 8433        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8434        cx: &mut Context<Self>,
 8435    ) -> IconButton {
 8436        let color = Color::Muted;
 8437        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8438
 8439        IconButton::new(
 8440            ("run_indicator", row.0 as usize),
 8441            ui::IconName::PlayOutlined,
 8442        )
 8443        .shape(ui::IconButtonShape::Square)
 8444        .icon_size(IconSize::XSmall)
 8445        .icon_color(color)
 8446        .toggle_state(is_active)
 8447        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8448            let quick_launch = match e {
 8449                ClickEvent::Keyboard(_) => true,
 8450                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8451            };
 8452
 8453            window.focus(&editor.focus_handle(cx));
 8454            editor.toggle_code_actions(
 8455                &ToggleCodeActions {
 8456                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8457                    quick_launch,
 8458                },
 8459                window,
 8460                cx,
 8461            );
 8462        }))
 8463        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8464            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8465        }))
 8466    }
 8467
 8468    pub fn context_menu_visible(&self) -> bool {
 8469        !self.edit_prediction_preview_is_active()
 8470            && self
 8471                .context_menu
 8472                .borrow()
 8473                .as_ref()
 8474                .is_some_and(|menu| menu.visible())
 8475    }
 8476
 8477    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8478        self.context_menu
 8479            .borrow()
 8480            .as_ref()
 8481            .map(|menu| menu.origin())
 8482    }
 8483
 8484    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8485        self.context_menu_options = Some(options);
 8486    }
 8487
 8488    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8489    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8490
 8491    fn render_edit_prediction_popover(
 8492        &mut self,
 8493        text_bounds: &Bounds<Pixels>,
 8494        content_origin: gpui::Point<Pixels>,
 8495        right_margin: Pixels,
 8496        editor_snapshot: &EditorSnapshot,
 8497        visible_row_range: Range<DisplayRow>,
 8498        scroll_top: f32,
 8499        scroll_bottom: f32,
 8500        line_layouts: &[LineWithInvisibles],
 8501        line_height: Pixels,
 8502        scroll_pixel_position: gpui::Point<Pixels>,
 8503        newest_selection_head: Option<DisplayPoint>,
 8504        editor_width: Pixels,
 8505        style: &EditorStyle,
 8506        window: &mut Window,
 8507        cx: &mut App,
 8508    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8509        if self.mode().is_minimap() {
 8510            return None;
 8511        }
 8512        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8513
 8514        if self.edit_prediction_visible_in_cursor_popover(true) {
 8515            return None;
 8516        }
 8517
 8518        match &active_edit_prediction.completion {
 8519            EditPrediction::Move { target, .. } => {
 8520                let target_display_point = target.to_display_point(editor_snapshot);
 8521
 8522                if self.edit_prediction_requires_modifier() {
 8523                    if !self.edit_prediction_preview_is_active() {
 8524                        return None;
 8525                    }
 8526
 8527                    self.render_edit_prediction_modifier_jump_popover(
 8528                        text_bounds,
 8529                        content_origin,
 8530                        visible_row_range,
 8531                        line_layouts,
 8532                        line_height,
 8533                        scroll_pixel_position,
 8534                        newest_selection_head,
 8535                        target_display_point,
 8536                        window,
 8537                        cx,
 8538                    )
 8539                } else {
 8540                    self.render_edit_prediction_eager_jump_popover(
 8541                        text_bounds,
 8542                        content_origin,
 8543                        editor_snapshot,
 8544                        visible_row_range,
 8545                        scroll_top,
 8546                        scroll_bottom,
 8547                        line_height,
 8548                        scroll_pixel_position,
 8549                        target_display_point,
 8550                        editor_width,
 8551                        window,
 8552                        cx,
 8553                    )
 8554                }
 8555            }
 8556            EditPrediction::Edit {
 8557                display_mode: EditDisplayMode::Inline,
 8558                ..
 8559            } => None,
 8560            EditPrediction::Edit {
 8561                display_mode: EditDisplayMode::TabAccept,
 8562                edits,
 8563                ..
 8564            } => {
 8565                let range = &edits.first()?.0;
 8566                let target_display_point = range.end.to_display_point(editor_snapshot);
 8567
 8568                self.render_edit_prediction_end_of_line_popover(
 8569                    "Accept",
 8570                    editor_snapshot,
 8571                    visible_row_range,
 8572                    target_display_point,
 8573                    line_height,
 8574                    scroll_pixel_position,
 8575                    content_origin,
 8576                    editor_width,
 8577                    window,
 8578                    cx,
 8579                )
 8580            }
 8581            EditPrediction::Edit {
 8582                edits,
 8583                edit_preview,
 8584                display_mode: EditDisplayMode::DiffPopover,
 8585                snapshot,
 8586            } => self.render_edit_prediction_diff_popover(
 8587                text_bounds,
 8588                content_origin,
 8589                right_margin,
 8590                editor_snapshot,
 8591                visible_row_range,
 8592                line_layouts,
 8593                line_height,
 8594                scroll_pixel_position,
 8595                newest_selection_head,
 8596                editor_width,
 8597                style,
 8598                edits,
 8599                edit_preview,
 8600                snapshot,
 8601                window,
 8602                cx,
 8603            ),
 8604        }
 8605    }
 8606
 8607    fn render_edit_prediction_modifier_jump_popover(
 8608        &mut self,
 8609        text_bounds: &Bounds<Pixels>,
 8610        content_origin: gpui::Point<Pixels>,
 8611        visible_row_range: Range<DisplayRow>,
 8612        line_layouts: &[LineWithInvisibles],
 8613        line_height: Pixels,
 8614        scroll_pixel_position: gpui::Point<Pixels>,
 8615        newest_selection_head: Option<DisplayPoint>,
 8616        target_display_point: DisplayPoint,
 8617        window: &mut Window,
 8618        cx: &mut App,
 8619    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8620        let scrolled_content_origin =
 8621            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8622
 8623        const SCROLL_PADDING_Y: Pixels = px(12.);
 8624
 8625        if target_display_point.row() < visible_row_range.start {
 8626            return self.render_edit_prediction_scroll_popover(
 8627                |_| SCROLL_PADDING_Y,
 8628                IconName::ArrowUp,
 8629                visible_row_range,
 8630                line_layouts,
 8631                newest_selection_head,
 8632                scrolled_content_origin,
 8633                window,
 8634                cx,
 8635            );
 8636        } else if target_display_point.row() >= visible_row_range.end {
 8637            return self.render_edit_prediction_scroll_popover(
 8638                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8639                IconName::ArrowDown,
 8640                visible_row_range,
 8641                line_layouts,
 8642                newest_selection_head,
 8643                scrolled_content_origin,
 8644                window,
 8645                cx,
 8646            );
 8647        }
 8648
 8649        const POLE_WIDTH: Pixels = px(2.);
 8650
 8651        let line_layout =
 8652            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8653        let target_column = target_display_point.column() as usize;
 8654
 8655        let target_x = line_layout.x_for_index(target_column);
 8656        let target_y =
 8657            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8658
 8659        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8660
 8661        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8662        border_color.l += 0.001;
 8663
 8664        let mut element = v_flex()
 8665            .items_end()
 8666            .when(flag_on_right, |el| el.items_start())
 8667            .child(if flag_on_right {
 8668                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8669                    .rounded_bl(px(0.))
 8670                    .rounded_tl(px(0.))
 8671                    .border_l_2()
 8672                    .border_color(border_color)
 8673            } else {
 8674                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8675                    .rounded_br(px(0.))
 8676                    .rounded_tr(px(0.))
 8677                    .border_r_2()
 8678                    .border_color(border_color)
 8679            })
 8680            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8681            .into_any();
 8682
 8683        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8684
 8685        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8686            - point(
 8687                if flag_on_right {
 8688                    POLE_WIDTH
 8689                } else {
 8690                    size.width - POLE_WIDTH
 8691                },
 8692                size.height - line_height,
 8693            );
 8694
 8695        origin.x = origin.x.max(content_origin.x);
 8696
 8697        element.prepaint_at(origin, window, cx);
 8698
 8699        Some((element, origin))
 8700    }
 8701
 8702    fn render_edit_prediction_scroll_popover(
 8703        &mut self,
 8704        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8705        scroll_icon: IconName,
 8706        visible_row_range: Range<DisplayRow>,
 8707        line_layouts: &[LineWithInvisibles],
 8708        newest_selection_head: Option<DisplayPoint>,
 8709        scrolled_content_origin: gpui::Point<Pixels>,
 8710        window: &mut Window,
 8711        cx: &mut App,
 8712    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8713        let mut element = self
 8714            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8715            .into_any();
 8716
 8717        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8718
 8719        let cursor = newest_selection_head?;
 8720        let cursor_row_layout =
 8721            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8722        let cursor_column = cursor.column() as usize;
 8723
 8724        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8725
 8726        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8727
 8728        element.prepaint_at(origin, window, cx);
 8729        Some((element, origin))
 8730    }
 8731
 8732    fn render_edit_prediction_eager_jump_popover(
 8733        &mut self,
 8734        text_bounds: &Bounds<Pixels>,
 8735        content_origin: gpui::Point<Pixels>,
 8736        editor_snapshot: &EditorSnapshot,
 8737        visible_row_range: Range<DisplayRow>,
 8738        scroll_top: f32,
 8739        scroll_bottom: f32,
 8740        line_height: Pixels,
 8741        scroll_pixel_position: gpui::Point<Pixels>,
 8742        target_display_point: DisplayPoint,
 8743        editor_width: Pixels,
 8744        window: &mut Window,
 8745        cx: &mut App,
 8746    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8747        if target_display_point.row().as_f32() < scroll_top {
 8748            let mut element = self
 8749                .render_edit_prediction_line_popover(
 8750                    "Jump to Edit",
 8751                    Some(IconName::ArrowUp),
 8752                    window,
 8753                    cx,
 8754                )?
 8755                .into_any();
 8756
 8757            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8758            let offset = point(
 8759                (text_bounds.size.width - size.width) / 2.,
 8760                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8761            );
 8762
 8763            let origin = text_bounds.origin + offset;
 8764            element.prepaint_at(origin, window, cx);
 8765            Some((element, origin))
 8766        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8767            let mut element = self
 8768                .render_edit_prediction_line_popover(
 8769                    "Jump to Edit",
 8770                    Some(IconName::ArrowDown),
 8771                    window,
 8772                    cx,
 8773                )?
 8774                .into_any();
 8775
 8776            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8777            let offset = point(
 8778                (text_bounds.size.width - size.width) / 2.,
 8779                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8780            );
 8781
 8782            let origin = text_bounds.origin + offset;
 8783            element.prepaint_at(origin, window, cx);
 8784            Some((element, origin))
 8785        } else {
 8786            self.render_edit_prediction_end_of_line_popover(
 8787                "Jump to Edit",
 8788                editor_snapshot,
 8789                visible_row_range,
 8790                target_display_point,
 8791                line_height,
 8792                scroll_pixel_position,
 8793                content_origin,
 8794                editor_width,
 8795                window,
 8796                cx,
 8797            )
 8798        }
 8799    }
 8800
 8801    fn render_edit_prediction_end_of_line_popover(
 8802        self: &mut Editor,
 8803        label: &'static str,
 8804        editor_snapshot: &EditorSnapshot,
 8805        visible_row_range: Range<DisplayRow>,
 8806        target_display_point: DisplayPoint,
 8807        line_height: Pixels,
 8808        scroll_pixel_position: gpui::Point<Pixels>,
 8809        content_origin: gpui::Point<Pixels>,
 8810        editor_width: Pixels,
 8811        window: &mut Window,
 8812        cx: &mut App,
 8813    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8814        let target_line_end = DisplayPoint::new(
 8815            target_display_point.row(),
 8816            editor_snapshot.line_len(target_display_point.row()),
 8817        );
 8818
 8819        let mut element = self
 8820            .render_edit_prediction_line_popover(label, None, window, cx)?
 8821            .into_any();
 8822
 8823        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8824
 8825        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8826
 8827        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8828        let mut origin = start_point
 8829            + line_origin
 8830            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8831        origin.x = origin.x.max(content_origin.x);
 8832
 8833        let max_x = content_origin.x + editor_width - size.width;
 8834
 8835        if origin.x > max_x {
 8836            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8837
 8838            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8839                origin.y += offset;
 8840                IconName::ArrowUp
 8841            } else {
 8842                origin.y -= offset;
 8843                IconName::ArrowDown
 8844            };
 8845
 8846            element = self
 8847                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8848                .into_any();
 8849
 8850            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8851
 8852            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8853        }
 8854
 8855        element.prepaint_at(origin, window, cx);
 8856        Some((element, origin))
 8857    }
 8858
 8859    fn render_edit_prediction_diff_popover(
 8860        self: &Editor,
 8861        text_bounds: &Bounds<Pixels>,
 8862        content_origin: gpui::Point<Pixels>,
 8863        right_margin: Pixels,
 8864        editor_snapshot: &EditorSnapshot,
 8865        visible_row_range: Range<DisplayRow>,
 8866        line_layouts: &[LineWithInvisibles],
 8867        line_height: Pixels,
 8868        scroll_pixel_position: gpui::Point<Pixels>,
 8869        newest_selection_head: Option<DisplayPoint>,
 8870        editor_width: Pixels,
 8871        style: &EditorStyle,
 8872        edits: &Vec<(Range<Anchor>, String)>,
 8873        edit_preview: &Option<language::EditPreview>,
 8874        snapshot: &language::BufferSnapshot,
 8875        window: &mut Window,
 8876        cx: &mut App,
 8877    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8878        let edit_start = edits
 8879            .first()
 8880            .unwrap()
 8881            .0
 8882            .start
 8883            .to_display_point(editor_snapshot);
 8884        let edit_end = edits
 8885            .last()
 8886            .unwrap()
 8887            .0
 8888            .end
 8889            .to_display_point(editor_snapshot);
 8890
 8891        let is_visible = visible_row_range.contains(&edit_start.row())
 8892            || visible_row_range.contains(&edit_end.row());
 8893        if !is_visible {
 8894            return None;
 8895        }
 8896
 8897        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8898            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8899        } else {
 8900            // Fallback for providers without edit_preview
 8901            crate::edit_prediction_fallback_text(edits, cx)
 8902        };
 8903
 8904        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8905        let line_count = highlighted_edits.text.lines().count();
 8906
 8907        const BORDER_WIDTH: Pixels = px(1.);
 8908
 8909        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8910        let has_keybind = keybind.is_some();
 8911
 8912        let mut element = h_flex()
 8913            .items_start()
 8914            .child(
 8915                h_flex()
 8916                    .bg(cx.theme().colors().editor_background)
 8917                    .border(BORDER_WIDTH)
 8918                    .shadow_xs()
 8919                    .border_color(cx.theme().colors().border)
 8920                    .rounded_l_lg()
 8921                    .when(line_count > 1, |el| el.rounded_br_lg())
 8922                    .pr_1()
 8923                    .child(styled_text),
 8924            )
 8925            .child(
 8926                h_flex()
 8927                    .h(line_height + BORDER_WIDTH * 2.)
 8928                    .px_1p5()
 8929                    .gap_1()
 8930                    // Workaround: For some reason, there's a gap if we don't do this
 8931                    .ml(-BORDER_WIDTH)
 8932                    .shadow(vec![gpui::BoxShadow {
 8933                        color: gpui::black().opacity(0.05),
 8934                        offset: point(px(1.), px(1.)),
 8935                        blur_radius: px(2.),
 8936                        spread_radius: px(0.),
 8937                    }])
 8938                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8939                    .border(BORDER_WIDTH)
 8940                    .border_color(cx.theme().colors().border)
 8941                    .rounded_r_lg()
 8942                    .id("edit_prediction_diff_popover_keybind")
 8943                    .when(!has_keybind, |el| {
 8944                        let status_colors = cx.theme().status();
 8945
 8946                        el.bg(status_colors.error_background)
 8947                            .border_color(status_colors.error.opacity(0.6))
 8948                            .child(Icon::new(IconName::Info).color(Color::Error))
 8949                            .cursor_default()
 8950                            .hoverable_tooltip(move |_window, cx| {
 8951                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8952                            })
 8953                    })
 8954                    .children(keybind),
 8955            )
 8956            .into_any();
 8957
 8958        let longest_row =
 8959            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8960        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8961            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8962        } else {
 8963            layout_line(
 8964                longest_row,
 8965                editor_snapshot,
 8966                style,
 8967                editor_width,
 8968                |_| false,
 8969                window,
 8970                cx,
 8971            )
 8972            .width
 8973        };
 8974
 8975        let viewport_bounds =
 8976            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8977                right: -right_margin,
 8978                ..Default::default()
 8979            });
 8980
 8981        let x_after_longest =
 8982            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8983                - scroll_pixel_position.x;
 8984
 8985        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8986
 8987        // Fully visible if it can be displayed within the window (allow overlapping other
 8988        // panes). However, this is only allowed if the popover starts within text_bounds.
 8989        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8990            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8991
 8992        let mut origin = if can_position_to_the_right {
 8993            point(
 8994                x_after_longest,
 8995                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8996                    - scroll_pixel_position.y,
 8997            )
 8998        } else {
 8999            let cursor_row = newest_selection_head.map(|head| head.row());
 9000            let above_edit = edit_start
 9001                .row()
 9002                .0
 9003                .checked_sub(line_count as u32)
 9004                .map(DisplayRow);
 9005            let below_edit = Some(edit_end.row() + 1);
 9006            let above_cursor =
 9007                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9008            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9009
 9010            // Place the edit popover adjacent to the edit if there is a location
 9011            // available that is onscreen and does not obscure the cursor. Otherwise,
 9012            // place it adjacent to the cursor.
 9013            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9014                .into_iter()
 9015                .flatten()
 9016                .find(|&start_row| {
 9017                    let end_row = start_row + line_count as u32;
 9018                    visible_row_range.contains(&start_row)
 9019                        && visible_row_range.contains(&end_row)
 9020                        && cursor_row
 9021                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9022                })?;
 9023
 9024            content_origin
 9025                + point(
 9026                    -scroll_pixel_position.x,
 9027                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9028                )
 9029        };
 9030
 9031        origin.x -= BORDER_WIDTH;
 9032
 9033        window.defer_draw(element, origin, 1);
 9034
 9035        // Do not return an element, since it will already be drawn due to defer_draw.
 9036        None
 9037    }
 9038
 9039    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9040        px(30.)
 9041    }
 9042
 9043    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9044        if self.read_only(cx) {
 9045            cx.theme().players().read_only()
 9046        } else {
 9047            self.style.as_ref().unwrap().local_player
 9048        }
 9049    }
 9050
 9051    fn render_edit_prediction_accept_keybind(
 9052        &self,
 9053        window: &mut Window,
 9054        cx: &App,
 9055    ) -> Option<AnyElement> {
 9056        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9057        let accept_keystroke = accept_binding.keystroke()?;
 9058
 9059        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9060
 9061        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9062            Color::Accent
 9063        } else {
 9064            Color::Muted
 9065        };
 9066
 9067        h_flex()
 9068            .px_0p5()
 9069            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9070            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9071            .text_size(TextSize::XSmall.rems(cx))
 9072            .child(h_flex().children(ui::render_modifiers(
 9073                accept_keystroke.modifiers(),
 9074                PlatformStyle::platform(),
 9075                Some(modifiers_color),
 9076                Some(IconSize::XSmall.rems().into()),
 9077                true,
 9078            )))
 9079            .when(is_platform_style_mac, |parent| {
 9080                parent.child(accept_keystroke.key().to_string())
 9081            })
 9082            .when(!is_platform_style_mac, |parent| {
 9083                parent.child(
 9084                    Key::new(
 9085                        util::capitalize(accept_keystroke.key()),
 9086                        Some(Color::Default),
 9087                    )
 9088                    .size(Some(IconSize::XSmall.rems().into())),
 9089                )
 9090            })
 9091            .into_any()
 9092            .into()
 9093    }
 9094
 9095    fn render_edit_prediction_line_popover(
 9096        &self,
 9097        label: impl Into<SharedString>,
 9098        icon: Option<IconName>,
 9099        window: &mut Window,
 9100        cx: &App,
 9101    ) -> Option<Stateful<Div>> {
 9102        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9103
 9104        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9105        let has_keybind = keybind.is_some();
 9106
 9107        let result = h_flex()
 9108            .id("ep-line-popover")
 9109            .py_0p5()
 9110            .pl_1()
 9111            .pr(padding_right)
 9112            .gap_1()
 9113            .rounded_md()
 9114            .border_1()
 9115            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9116            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9117            .shadow_xs()
 9118            .when(!has_keybind, |el| {
 9119                let status_colors = cx.theme().status();
 9120
 9121                el.bg(status_colors.error_background)
 9122                    .border_color(status_colors.error.opacity(0.6))
 9123                    .pl_2()
 9124                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9125                    .cursor_default()
 9126                    .hoverable_tooltip(move |_window, cx| {
 9127                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9128                    })
 9129            })
 9130            .children(keybind)
 9131            .child(
 9132                Label::new(label)
 9133                    .size(LabelSize::Small)
 9134                    .when(!has_keybind, |el| {
 9135                        el.color(cx.theme().status().error.into()).strikethrough()
 9136                    }),
 9137            )
 9138            .when(!has_keybind, |el| {
 9139                el.child(
 9140                    h_flex().ml_1().child(
 9141                        Icon::new(IconName::Info)
 9142                            .size(IconSize::Small)
 9143                            .color(cx.theme().status().error.into()),
 9144                    ),
 9145                )
 9146            })
 9147            .when_some(icon, |element, icon| {
 9148                element.child(
 9149                    div()
 9150                        .mt(px(1.5))
 9151                        .child(Icon::new(icon).size(IconSize::Small)),
 9152                )
 9153            });
 9154
 9155        Some(result)
 9156    }
 9157
 9158    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9159        let accent_color = cx.theme().colors().text_accent;
 9160        let editor_bg_color = cx.theme().colors().editor_background;
 9161        editor_bg_color.blend(accent_color.opacity(0.1))
 9162    }
 9163
 9164    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9165        let accent_color = cx.theme().colors().text_accent;
 9166        let editor_bg_color = cx.theme().colors().editor_background;
 9167        editor_bg_color.blend(accent_color.opacity(0.6))
 9168    }
 9169    fn get_prediction_provider_icon_name(
 9170        provider: &Option<RegisteredEditPredictionProvider>,
 9171    ) -> IconName {
 9172        match provider {
 9173            Some(provider) => match provider.provider.name() {
 9174                "copilot" => IconName::Copilot,
 9175                "supermaven" => IconName::Supermaven,
 9176                _ => IconName::ZedPredict,
 9177            },
 9178            None => IconName::ZedPredict,
 9179        }
 9180    }
 9181
 9182    fn render_edit_prediction_cursor_popover(
 9183        &self,
 9184        min_width: Pixels,
 9185        max_width: Pixels,
 9186        cursor_point: Point,
 9187        style: &EditorStyle,
 9188        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9189        _window: &Window,
 9190        cx: &mut Context<Editor>,
 9191    ) -> Option<AnyElement> {
 9192        let provider = self.edit_prediction_provider.as_ref()?;
 9193        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9194
 9195        let is_refreshing = provider.provider.is_refreshing(cx);
 9196
 9197        fn pending_completion_container(icon: IconName) -> Div {
 9198            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9199        }
 9200
 9201        let completion = match &self.active_edit_prediction {
 9202            Some(prediction) => {
 9203                if !self.has_visible_completions_menu() {
 9204                    const RADIUS: Pixels = px(6.);
 9205                    const BORDER_WIDTH: Pixels = px(1.);
 9206
 9207                    return Some(
 9208                        h_flex()
 9209                            .elevation_2(cx)
 9210                            .border(BORDER_WIDTH)
 9211                            .border_color(cx.theme().colors().border)
 9212                            .when(accept_keystroke.is_none(), |el| {
 9213                                el.border_color(cx.theme().status().error)
 9214                            })
 9215                            .rounded(RADIUS)
 9216                            .rounded_tl(px(0.))
 9217                            .overflow_hidden()
 9218                            .child(div().px_1p5().child(match &prediction.completion {
 9219                                EditPrediction::Move { target, snapshot } => {
 9220                                    use text::ToPoint as _;
 9221                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9222                                    {
 9223                                        Icon::new(IconName::ZedPredictDown)
 9224                                    } else {
 9225                                        Icon::new(IconName::ZedPredictUp)
 9226                                    }
 9227                                }
 9228                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9229                            }))
 9230                            .child(
 9231                                h_flex()
 9232                                    .gap_1()
 9233                                    .py_1()
 9234                                    .px_2()
 9235                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9236                                    .border_l_1()
 9237                                    .border_color(cx.theme().colors().border)
 9238                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9239                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9240                                        el.child(
 9241                                            Label::new("Hold")
 9242                                                .size(LabelSize::Small)
 9243                                                .when(accept_keystroke.is_none(), |el| {
 9244                                                    el.strikethrough()
 9245                                                })
 9246                                                .line_height_style(LineHeightStyle::UiLabel),
 9247                                        )
 9248                                    })
 9249                                    .id("edit_prediction_cursor_popover_keybind")
 9250                                    .when(accept_keystroke.is_none(), |el| {
 9251                                        let status_colors = cx.theme().status();
 9252
 9253                                        el.bg(status_colors.error_background)
 9254                                            .border_color(status_colors.error.opacity(0.6))
 9255                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9256                                            .cursor_default()
 9257                                            .hoverable_tooltip(move |_window, cx| {
 9258                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9259                                                    .into()
 9260                                            })
 9261                                    })
 9262                                    .when_some(
 9263                                        accept_keystroke.as_ref(),
 9264                                        |el, accept_keystroke| {
 9265                                            el.child(h_flex().children(ui::render_modifiers(
 9266                                                accept_keystroke.modifiers(),
 9267                                                PlatformStyle::platform(),
 9268                                                Some(Color::Default),
 9269                                                Some(IconSize::XSmall.rems().into()),
 9270                                                false,
 9271                                            )))
 9272                                        },
 9273                                    ),
 9274                            )
 9275                            .into_any(),
 9276                    );
 9277                }
 9278
 9279                self.render_edit_prediction_cursor_popover_preview(
 9280                    prediction,
 9281                    cursor_point,
 9282                    style,
 9283                    cx,
 9284                )?
 9285            }
 9286
 9287            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9288                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9289                    stale_completion,
 9290                    cursor_point,
 9291                    style,
 9292                    cx,
 9293                )?,
 9294
 9295                None => pending_completion_container(provider_icon)
 9296                    .child(Label::new("...").size(LabelSize::Small)),
 9297            },
 9298
 9299            None => pending_completion_container(provider_icon)
 9300                .child(Label::new("...").size(LabelSize::Small)),
 9301        };
 9302
 9303        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9304            completion
 9305                .with_animation(
 9306                    "loading-completion",
 9307                    Animation::new(Duration::from_secs(2))
 9308                        .repeat()
 9309                        .with_easing(pulsating_between(0.4, 0.8)),
 9310                    |label, delta| label.opacity(delta),
 9311                )
 9312                .into_any_element()
 9313        } else {
 9314            completion.into_any_element()
 9315        };
 9316
 9317        let has_completion = self.active_edit_prediction.is_some();
 9318
 9319        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9320        Some(
 9321            h_flex()
 9322                .min_w(min_width)
 9323                .max_w(max_width)
 9324                .flex_1()
 9325                .elevation_2(cx)
 9326                .border_color(cx.theme().colors().border)
 9327                .child(
 9328                    div()
 9329                        .flex_1()
 9330                        .py_1()
 9331                        .px_2()
 9332                        .overflow_hidden()
 9333                        .child(completion),
 9334                )
 9335                .when_some(accept_keystroke, |el, accept_keystroke| {
 9336                    if !accept_keystroke.modifiers().modified() {
 9337                        return el;
 9338                    }
 9339
 9340                    el.child(
 9341                        h_flex()
 9342                            .h_full()
 9343                            .border_l_1()
 9344                            .rounded_r_lg()
 9345                            .border_color(cx.theme().colors().border)
 9346                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9347                            .gap_1()
 9348                            .py_1()
 9349                            .px_2()
 9350                            .child(
 9351                                h_flex()
 9352                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9353                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9354                                    .child(h_flex().children(ui::render_modifiers(
 9355                                        accept_keystroke.modifiers(),
 9356                                        PlatformStyle::platform(),
 9357                                        Some(if !has_completion {
 9358                                            Color::Muted
 9359                                        } else {
 9360                                            Color::Default
 9361                                        }),
 9362                                        None,
 9363                                        false,
 9364                                    ))),
 9365                            )
 9366                            .child(Label::new("Preview").into_any_element())
 9367                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9368                    )
 9369                })
 9370                .into_any(),
 9371        )
 9372    }
 9373
 9374    fn render_edit_prediction_cursor_popover_preview(
 9375        &self,
 9376        completion: &EditPredictionState,
 9377        cursor_point: Point,
 9378        style: &EditorStyle,
 9379        cx: &mut Context<Editor>,
 9380    ) -> Option<Div> {
 9381        use text::ToPoint as _;
 9382
 9383        fn render_relative_row_jump(
 9384            prefix: impl Into<String>,
 9385            current_row: u32,
 9386            target_row: u32,
 9387        ) -> Div {
 9388            let (row_diff, arrow) = if target_row < current_row {
 9389                (current_row - target_row, IconName::ArrowUp)
 9390            } else {
 9391                (target_row - current_row, IconName::ArrowDown)
 9392            };
 9393
 9394            h_flex()
 9395                .child(
 9396                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9397                        .color(Color::Muted)
 9398                        .size(LabelSize::Small),
 9399                )
 9400                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9401        }
 9402
 9403        let supports_jump = self
 9404            .edit_prediction_provider
 9405            .as_ref()
 9406            .map(|provider| provider.provider.supports_jump_to_edit())
 9407            .unwrap_or(true);
 9408
 9409        match &completion.completion {
 9410            EditPrediction::Move {
 9411                target, snapshot, ..
 9412            } => {
 9413                if !supports_jump {
 9414                    return None;
 9415                }
 9416
 9417                Some(
 9418                    h_flex()
 9419                        .px_2()
 9420                        .gap_2()
 9421                        .flex_1()
 9422                        .child(
 9423                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9424                                Icon::new(IconName::ZedPredictDown)
 9425                            } else {
 9426                                Icon::new(IconName::ZedPredictUp)
 9427                            },
 9428                        )
 9429                        .child(Label::new("Jump to Edit")),
 9430                )
 9431            }
 9432
 9433            EditPrediction::Edit {
 9434                edits,
 9435                edit_preview,
 9436                snapshot,
 9437                display_mode: _,
 9438            } => {
 9439                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9440
 9441                let (highlighted_edits, has_more_lines) =
 9442                    if let Some(edit_preview) = edit_preview.as_ref() {
 9443                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9444                            .first_line_preview()
 9445                    } else {
 9446                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9447                    };
 9448
 9449                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9450                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9451
 9452                let preview = h_flex()
 9453                    .gap_1()
 9454                    .min_w_16()
 9455                    .child(styled_text)
 9456                    .when(has_more_lines, |parent| parent.child(""));
 9457
 9458                let left = if supports_jump && first_edit_row != cursor_point.row {
 9459                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9460                        .into_any_element()
 9461                } else {
 9462                    let icon_name =
 9463                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9464                    Icon::new(icon_name).into_any_element()
 9465                };
 9466
 9467                Some(
 9468                    h_flex()
 9469                        .h_full()
 9470                        .flex_1()
 9471                        .gap_2()
 9472                        .pr_1()
 9473                        .overflow_x_hidden()
 9474                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9475                        .child(left)
 9476                        .child(preview),
 9477                )
 9478            }
 9479        }
 9480    }
 9481
 9482    pub fn render_context_menu(
 9483        &self,
 9484        style: &EditorStyle,
 9485        max_height_in_lines: u32,
 9486        window: &mut Window,
 9487        cx: &mut Context<Editor>,
 9488    ) -> Option<AnyElement> {
 9489        let menu = self.context_menu.borrow();
 9490        let menu = menu.as_ref()?;
 9491        if !menu.visible() {
 9492            return None;
 9493        };
 9494        Some(menu.render(style, max_height_in_lines, window, cx))
 9495    }
 9496
 9497    fn render_context_menu_aside(
 9498        &mut self,
 9499        max_size: Size<Pixels>,
 9500        window: &mut Window,
 9501        cx: &mut Context<Editor>,
 9502    ) -> Option<AnyElement> {
 9503        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9504            if menu.visible() {
 9505                menu.render_aside(max_size, window, cx)
 9506            } else {
 9507                None
 9508            }
 9509        })
 9510    }
 9511
 9512    fn hide_context_menu(
 9513        &mut self,
 9514        window: &mut Window,
 9515        cx: &mut Context<Self>,
 9516    ) -> Option<CodeContextMenu> {
 9517        cx.notify();
 9518        self.completion_tasks.clear();
 9519        let context_menu = self.context_menu.borrow_mut().take();
 9520        self.stale_edit_prediction_in_menu.take();
 9521        self.update_visible_edit_prediction(window, cx);
 9522        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9523            && let Some(completion_provider) = &self.completion_provider
 9524        {
 9525            completion_provider.selection_changed(None, window, cx);
 9526        }
 9527        context_menu
 9528    }
 9529
 9530    fn show_snippet_choices(
 9531        &mut self,
 9532        choices: &Vec<String>,
 9533        selection: Range<Anchor>,
 9534        cx: &mut Context<Self>,
 9535    ) {
 9536        let Some((_, buffer, _)) = self
 9537            .buffer()
 9538            .read(cx)
 9539            .excerpt_containing(selection.start, cx)
 9540        else {
 9541            return;
 9542        };
 9543        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9544        else {
 9545            return;
 9546        };
 9547        if buffer != end_buffer {
 9548            log::error!("expected anchor range to have matching buffer IDs");
 9549            return;
 9550        }
 9551
 9552        let id = post_inc(&mut self.next_completion_id);
 9553        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9554        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9555            CompletionsMenu::new_snippet_choices(
 9556                id,
 9557                true,
 9558                choices,
 9559                selection,
 9560                buffer,
 9561                snippet_sort_order,
 9562            ),
 9563        ));
 9564    }
 9565
 9566    pub fn insert_snippet(
 9567        &mut self,
 9568        insertion_ranges: &[Range<usize>],
 9569        snippet: Snippet,
 9570        window: &mut Window,
 9571        cx: &mut Context<Self>,
 9572    ) -> Result<()> {
 9573        struct Tabstop<T> {
 9574            is_end_tabstop: bool,
 9575            ranges: Vec<Range<T>>,
 9576            choices: Option<Vec<String>>,
 9577        }
 9578
 9579        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9580            let snippet_text: Arc<str> = snippet.text.clone().into();
 9581            let edits = insertion_ranges
 9582                .iter()
 9583                .cloned()
 9584                .map(|range| (range, snippet_text.clone()));
 9585            let autoindent_mode = AutoindentMode::Block {
 9586                original_indent_columns: Vec::new(),
 9587            };
 9588            buffer.edit(edits, Some(autoindent_mode), cx);
 9589
 9590            let snapshot = &*buffer.read(cx);
 9591            let snippet = &snippet;
 9592            snippet
 9593                .tabstops
 9594                .iter()
 9595                .map(|tabstop| {
 9596                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9597                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9598                    });
 9599                    let mut tabstop_ranges = tabstop
 9600                        .ranges
 9601                        .iter()
 9602                        .flat_map(|tabstop_range| {
 9603                            let mut delta = 0_isize;
 9604                            insertion_ranges.iter().map(move |insertion_range| {
 9605                                let insertion_start = insertion_range.start as isize + delta;
 9606                                delta +=
 9607                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9608
 9609                                let start = ((insertion_start + tabstop_range.start) as usize)
 9610                                    .min(snapshot.len());
 9611                                let end = ((insertion_start + tabstop_range.end) as usize)
 9612                                    .min(snapshot.len());
 9613                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9614                            })
 9615                        })
 9616                        .collect::<Vec<_>>();
 9617                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9618
 9619                    Tabstop {
 9620                        is_end_tabstop,
 9621                        ranges: tabstop_ranges,
 9622                        choices: tabstop.choices.clone(),
 9623                    }
 9624                })
 9625                .collect::<Vec<_>>()
 9626        });
 9627        if let Some(tabstop) = tabstops.first() {
 9628            self.change_selections(Default::default(), window, cx, |s| {
 9629                // Reverse order so that the first range is the newest created selection.
 9630                // Completions will use it and autoscroll will prioritize it.
 9631                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9632            });
 9633
 9634            if let Some(choices) = &tabstop.choices
 9635                && let Some(selection) = tabstop.ranges.first()
 9636            {
 9637                self.show_snippet_choices(choices, selection.clone(), cx)
 9638            }
 9639
 9640            // If we're already at the last tabstop and it's at the end of the snippet,
 9641            // we're done, we don't need to keep the state around.
 9642            if !tabstop.is_end_tabstop {
 9643                let choices = tabstops
 9644                    .iter()
 9645                    .map(|tabstop| tabstop.choices.clone())
 9646                    .collect();
 9647
 9648                let ranges = tabstops
 9649                    .into_iter()
 9650                    .map(|tabstop| tabstop.ranges)
 9651                    .collect::<Vec<_>>();
 9652
 9653                self.snippet_stack.push(SnippetState {
 9654                    active_index: 0,
 9655                    ranges,
 9656                    choices,
 9657                });
 9658            }
 9659
 9660            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9661            if self.autoclose_regions.is_empty() {
 9662                let snapshot = self.buffer.read(cx).snapshot(cx);
 9663                let mut all_selections = self.selections.all::<Point>(cx);
 9664                for selection in &mut all_selections {
 9665                    let selection_head = selection.head();
 9666                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9667                        continue;
 9668                    };
 9669
 9670                    let mut bracket_pair = None;
 9671                    let max_lookup_length = scope
 9672                        .brackets()
 9673                        .map(|(pair, _)| {
 9674                            pair.start
 9675                                .as_str()
 9676                                .chars()
 9677                                .count()
 9678                                .max(pair.end.as_str().chars().count())
 9679                        })
 9680                        .max();
 9681                    if let Some(max_lookup_length) = max_lookup_length {
 9682                        let next_text = snapshot
 9683                            .chars_at(selection_head)
 9684                            .take(max_lookup_length)
 9685                            .collect::<String>();
 9686                        let prev_text = snapshot
 9687                            .reversed_chars_at(selection_head)
 9688                            .take(max_lookup_length)
 9689                            .collect::<String>();
 9690
 9691                        for (pair, enabled) in scope.brackets() {
 9692                            if enabled
 9693                                && pair.close
 9694                                && prev_text.starts_with(pair.start.as_str())
 9695                                && next_text.starts_with(pair.end.as_str())
 9696                            {
 9697                                bracket_pair = Some(pair.clone());
 9698                                break;
 9699                            }
 9700                        }
 9701                    }
 9702
 9703                    if let Some(pair) = bracket_pair {
 9704                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9705                        let autoclose_enabled =
 9706                            self.use_autoclose && snapshot_settings.use_autoclose;
 9707                        if autoclose_enabled {
 9708                            let start = snapshot.anchor_after(selection_head);
 9709                            let end = snapshot.anchor_after(selection_head);
 9710                            self.autoclose_regions.push(AutocloseRegion {
 9711                                selection_id: selection.id,
 9712                                range: start..end,
 9713                                pair,
 9714                            });
 9715                        }
 9716                    }
 9717                }
 9718            }
 9719        }
 9720        Ok(())
 9721    }
 9722
 9723    pub fn move_to_next_snippet_tabstop(
 9724        &mut self,
 9725        window: &mut Window,
 9726        cx: &mut Context<Self>,
 9727    ) -> bool {
 9728        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9729    }
 9730
 9731    pub fn move_to_prev_snippet_tabstop(
 9732        &mut self,
 9733        window: &mut Window,
 9734        cx: &mut Context<Self>,
 9735    ) -> bool {
 9736        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9737    }
 9738
 9739    pub fn move_to_snippet_tabstop(
 9740        &mut self,
 9741        bias: Bias,
 9742        window: &mut Window,
 9743        cx: &mut Context<Self>,
 9744    ) -> bool {
 9745        if let Some(mut snippet) = self.snippet_stack.pop() {
 9746            match bias {
 9747                Bias::Left => {
 9748                    if snippet.active_index > 0 {
 9749                        snippet.active_index -= 1;
 9750                    } else {
 9751                        self.snippet_stack.push(snippet);
 9752                        return false;
 9753                    }
 9754                }
 9755                Bias::Right => {
 9756                    if snippet.active_index + 1 < snippet.ranges.len() {
 9757                        snippet.active_index += 1;
 9758                    } else {
 9759                        self.snippet_stack.push(snippet);
 9760                        return false;
 9761                    }
 9762                }
 9763            }
 9764            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9765                self.change_selections(Default::default(), window, cx, |s| {
 9766                    // Reverse order so that the first range is the newest created selection.
 9767                    // Completions will use it and autoscroll will prioritize it.
 9768                    s.select_ranges(current_ranges.iter().rev().cloned())
 9769                });
 9770
 9771                if let Some(choices) = &snippet.choices[snippet.active_index]
 9772                    && let Some(selection) = current_ranges.first()
 9773                {
 9774                    self.show_snippet_choices(choices, selection.clone(), cx);
 9775                }
 9776
 9777                // If snippet state is not at the last tabstop, push it back on the stack
 9778                if snippet.active_index + 1 < snippet.ranges.len() {
 9779                    self.snippet_stack.push(snippet);
 9780                }
 9781                return true;
 9782            }
 9783        }
 9784
 9785        false
 9786    }
 9787
 9788    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9789        self.transact(window, cx, |this, window, cx| {
 9790            this.select_all(&SelectAll, window, cx);
 9791            this.insert("", window, cx);
 9792        });
 9793    }
 9794
 9795    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9796        if self.read_only(cx) {
 9797            return;
 9798        }
 9799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9800        self.transact(window, cx, |this, window, cx| {
 9801            this.select_autoclose_pair(window, cx);
 9802            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9803            if !this.linked_edit_ranges.is_empty() {
 9804                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9805                let snapshot = this.buffer.read(cx).snapshot(cx);
 9806
 9807                for selection in selections.iter() {
 9808                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9809                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9810                    if selection_start.buffer_id != selection_end.buffer_id {
 9811                        continue;
 9812                    }
 9813                    if let Some(ranges) =
 9814                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9815                    {
 9816                        for (buffer, entries) in ranges {
 9817                            linked_ranges.entry(buffer).or_default().extend(entries);
 9818                        }
 9819                    }
 9820                }
 9821            }
 9822
 9823            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9824            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9825            for selection in &mut selections {
 9826                if selection.is_empty() {
 9827                    let old_head = selection.head();
 9828                    let mut new_head =
 9829                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9830                            .to_point(&display_map);
 9831                    if let Some((buffer, line_buffer_range)) = display_map
 9832                        .buffer_snapshot
 9833                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9834                    {
 9835                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9836                        let indent_len = match indent_size.kind {
 9837                            IndentKind::Space => {
 9838                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9839                            }
 9840                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9841                        };
 9842                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9843                            let indent_len = indent_len.get();
 9844                            new_head = cmp::min(
 9845                                new_head,
 9846                                MultiBufferPoint::new(
 9847                                    old_head.row,
 9848                                    ((old_head.column - 1) / indent_len) * indent_len,
 9849                                ),
 9850                            );
 9851                        }
 9852                    }
 9853
 9854                    selection.set_head(new_head, SelectionGoal::None);
 9855                }
 9856            }
 9857
 9858            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9859            this.insert("", window, cx);
 9860            let empty_str: Arc<str> = Arc::from("");
 9861            for (buffer, edits) in linked_ranges {
 9862                let snapshot = buffer.read(cx).snapshot();
 9863                use text::ToPoint as TP;
 9864
 9865                let edits = edits
 9866                    .into_iter()
 9867                    .map(|range| {
 9868                        let end_point = TP::to_point(&range.end, &snapshot);
 9869                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9870
 9871                        if end_point == start_point {
 9872                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9873                                .saturating_sub(1);
 9874                            start_point =
 9875                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9876                        };
 9877
 9878                        (start_point..end_point, empty_str.clone())
 9879                    })
 9880                    .sorted_by_key(|(range, _)| range.start)
 9881                    .collect::<Vec<_>>();
 9882                buffer.update(cx, |this, cx| {
 9883                    this.edit(edits, None, cx);
 9884                })
 9885            }
 9886            this.refresh_edit_prediction(true, false, window, cx);
 9887            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9888        });
 9889    }
 9890
 9891    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9892        if self.read_only(cx) {
 9893            return;
 9894        }
 9895        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9896        self.transact(window, cx, |this, window, cx| {
 9897            this.change_selections(Default::default(), window, cx, |s| {
 9898                s.move_with(|map, selection| {
 9899                    if selection.is_empty() {
 9900                        let cursor = movement::right(map, selection.head());
 9901                        selection.end = cursor;
 9902                        selection.reversed = true;
 9903                        selection.goal = SelectionGoal::None;
 9904                    }
 9905                })
 9906            });
 9907            this.insert("", window, cx);
 9908            this.refresh_edit_prediction(true, false, window, cx);
 9909        });
 9910    }
 9911
 9912    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9913        if self.mode.is_single_line() {
 9914            cx.propagate();
 9915            return;
 9916        }
 9917
 9918        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9919        if self.move_to_prev_snippet_tabstop(window, cx) {
 9920            return;
 9921        }
 9922        self.outdent(&Outdent, window, cx);
 9923    }
 9924
 9925    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9926        if self.mode.is_single_line() {
 9927            cx.propagate();
 9928            return;
 9929        }
 9930
 9931        if self.move_to_next_snippet_tabstop(window, cx) {
 9932            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9933            return;
 9934        }
 9935        if self.read_only(cx) {
 9936            return;
 9937        }
 9938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9939        let mut selections = self.selections.all_adjusted(cx);
 9940        let buffer = self.buffer.read(cx);
 9941        let snapshot = buffer.snapshot(cx);
 9942        let rows_iter = selections.iter().map(|s| s.head().row);
 9943        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9944
 9945        let has_some_cursor_in_whitespace = selections
 9946            .iter()
 9947            .filter(|selection| selection.is_empty())
 9948            .any(|selection| {
 9949                let cursor = selection.head();
 9950                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9951                cursor.column < current_indent.len
 9952            });
 9953
 9954        let mut edits = Vec::new();
 9955        let mut prev_edited_row = 0;
 9956        let mut row_delta = 0;
 9957        for selection in &mut selections {
 9958            if selection.start.row != prev_edited_row {
 9959                row_delta = 0;
 9960            }
 9961            prev_edited_row = selection.end.row;
 9962
 9963            // If the selection is non-empty, then increase the indentation of the selected lines.
 9964            if !selection.is_empty() {
 9965                row_delta =
 9966                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9967                continue;
 9968            }
 9969
 9970            let cursor = selection.head();
 9971            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9972            if let Some(suggested_indent) =
 9973                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9974            {
 9975                // Don't do anything if already at suggested indent
 9976                // and there is any other cursor which is not
 9977                if has_some_cursor_in_whitespace
 9978                    && cursor.column == current_indent.len
 9979                    && current_indent.len == suggested_indent.len
 9980                {
 9981                    continue;
 9982                }
 9983
 9984                // Adjust line and move cursor to suggested indent
 9985                // if cursor is not at suggested indent
 9986                if cursor.column < suggested_indent.len
 9987                    && cursor.column <= current_indent.len
 9988                    && current_indent.len <= suggested_indent.len
 9989                {
 9990                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9991                    selection.end = selection.start;
 9992                    if row_delta == 0 {
 9993                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9994                            cursor.row,
 9995                            current_indent,
 9996                            suggested_indent,
 9997                        ));
 9998                        row_delta = suggested_indent.len - current_indent.len;
 9999                    }
10000                    continue;
10001                }
10002
10003                // If current indent is more than suggested indent
10004                // only move cursor to current indent and skip indent
10005                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10006                    selection.start = Point::new(cursor.row, current_indent.len);
10007                    selection.end = selection.start;
10008                    continue;
10009                }
10010            }
10011
10012            // Otherwise, insert a hard or soft tab.
10013            let settings = buffer.language_settings_at(cursor, cx);
10014            let tab_size = if settings.hard_tabs {
10015                IndentSize::tab()
10016            } else {
10017                let tab_size = settings.tab_size.get();
10018                let indent_remainder = snapshot
10019                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10020                    .flat_map(str::chars)
10021                    .fold(row_delta % tab_size, |counter: u32, c| {
10022                        if c == '\t' {
10023                            0
10024                        } else {
10025                            (counter + 1) % tab_size
10026                        }
10027                    });
10028
10029                let chars_to_next_tab_stop = tab_size - indent_remainder;
10030                IndentSize::spaces(chars_to_next_tab_stop)
10031            };
10032            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10033            selection.end = selection.start;
10034            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10035            row_delta += tab_size.len;
10036        }
10037
10038        self.transact(window, cx, |this, window, cx| {
10039            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10040            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10041            this.refresh_edit_prediction(true, false, window, cx);
10042        });
10043    }
10044
10045    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10046        if self.read_only(cx) {
10047            return;
10048        }
10049        if self.mode.is_single_line() {
10050            cx.propagate();
10051            return;
10052        }
10053
10054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10055        let mut selections = self.selections.all::<Point>(cx);
10056        let mut prev_edited_row = 0;
10057        let mut row_delta = 0;
10058        let mut edits = Vec::new();
10059        let buffer = self.buffer.read(cx);
10060        let snapshot = buffer.snapshot(cx);
10061        for selection in &mut selections {
10062            if selection.start.row != prev_edited_row {
10063                row_delta = 0;
10064            }
10065            prev_edited_row = selection.end.row;
10066
10067            row_delta =
10068                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10069        }
10070
10071        self.transact(window, cx, |this, window, cx| {
10072            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10073            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10074        });
10075    }
10076
10077    fn indent_selection(
10078        buffer: &MultiBuffer,
10079        snapshot: &MultiBufferSnapshot,
10080        selection: &mut Selection<Point>,
10081        edits: &mut Vec<(Range<Point>, String)>,
10082        delta_for_start_row: u32,
10083        cx: &App,
10084    ) -> u32 {
10085        let settings = buffer.language_settings_at(selection.start, cx);
10086        let tab_size = settings.tab_size.get();
10087        let indent_kind = if settings.hard_tabs {
10088            IndentKind::Tab
10089        } else {
10090            IndentKind::Space
10091        };
10092        let mut start_row = selection.start.row;
10093        let mut end_row = selection.end.row + 1;
10094
10095        // If a selection ends at the beginning of a line, don't indent
10096        // that last line.
10097        if selection.end.column == 0 && selection.end.row > selection.start.row {
10098            end_row -= 1;
10099        }
10100
10101        // Avoid re-indenting a row that has already been indented by a
10102        // previous selection, but still update this selection's column
10103        // to reflect that indentation.
10104        if delta_for_start_row > 0 {
10105            start_row += 1;
10106            selection.start.column += delta_for_start_row;
10107            if selection.end.row == selection.start.row {
10108                selection.end.column += delta_for_start_row;
10109            }
10110        }
10111
10112        let mut delta_for_end_row = 0;
10113        let has_multiple_rows = start_row + 1 != end_row;
10114        for row in start_row..end_row {
10115            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10116            let indent_delta = match (current_indent.kind, indent_kind) {
10117                (IndentKind::Space, IndentKind::Space) => {
10118                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10119                    IndentSize::spaces(columns_to_next_tab_stop)
10120                }
10121                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10122                (_, IndentKind::Tab) => IndentSize::tab(),
10123            };
10124
10125            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10126                0
10127            } else {
10128                selection.start.column
10129            };
10130            let row_start = Point::new(row, start);
10131            edits.push((
10132                row_start..row_start,
10133                indent_delta.chars().collect::<String>(),
10134            ));
10135
10136            // Update this selection's endpoints to reflect the indentation.
10137            if row == selection.start.row {
10138                selection.start.column += indent_delta.len;
10139            }
10140            if row == selection.end.row {
10141                selection.end.column += indent_delta.len;
10142                delta_for_end_row = indent_delta.len;
10143            }
10144        }
10145
10146        if selection.start.row == selection.end.row {
10147            delta_for_start_row + delta_for_end_row
10148        } else {
10149            delta_for_end_row
10150        }
10151    }
10152
10153    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10154        if self.read_only(cx) {
10155            return;
10156        }
10157        if self.mode.is_single_line() {
10158            cx.propagate();
10159            return;
10160        }
10161
10162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10163        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10164        let selections = self.selections.all::<Point>(cx);
10165        let mut deletion_ranges = Vec::new();
10166        let mut last_outdent = None;
10167        {
10168            let buffer = self.buffer.read(cx);
10169            let snapshot = buffer.snapshot(cx);
10170            for selection in &selections {
10171                let settings = buffer.language_settings_at(selection.start, cx);
10172                let tab_size = settings.tab_size.get();
10173                let mut rows = selection.spanned_rows(false, &display_map);
10174
10175                // Avoid re-outdenting a row that has already been outdented by a
10176                // previous selection.
10177                if let Some(last_row) = last_outdent
10178                    && last_row == rows.start
10179                {
10180                    rows.start = rows.start.next_row();
10181                }
10182                let has_multiple_rows = rows.len() > 1;
10183                for row in rows.iter_rows() {
10184                    let indent_size = snapshot.indent_size_for_line(row);
10185                    if indent_size.len > 0 {
10186                        let deletion_len = match indent_size.kind {
10187                            IndentKind::Space => {
10188                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10189                                if columns_to_prev_tab_stop == 0 {
10190                                    tab_size
10191                                } else {
10192                                    columns_to_prev_tab_stop
10193                                }
10194                            }
10195                            IndentKind::Tab => 1,
10196                        };
10197                        let start = if has_multiple_rows
10198                            || deletion_len > selection.start.column
10199                            || indent_size.len < selection.start.column
10200                        {
10201                            0
10202                        } else {
10203                            selection.start.column - deletion_len
10204                        };
10205                        deletion_ranges.push(
10206                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10207                        );
10208                        last_outdent = Some(row);
10209                    }
10210                }
10211            }
10212        }
10213
10214        self.transact(window, cx, |this, window, cx| {
10215            this.buffer.update(cx, |buffer, cx| {
10216                let empty_str: Arc<str> = Arc::default();
10217                buffer.edit(
10218                    deletion_ranges
10219                        .into_iter()
10220                        .map(|range| (range, empty_str.clone())),
10221                    None,
10222                    cx,
10223                );
10224            });
10225            let selections = this.selections.all::<usize>(cx);
10226            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10227        });
10228    }
10229
10230    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10231        if self.read_only(cx) {
10232            return;
10233        }
10234        if self.mode.is_single_line() {
10235            cx.propagate();
10236            return;
10237        }
10238
10239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10240        let selections = self
10241            .selections
10242            .all::<usize>(cx)
10243            .into_iter()
10244            .map(|s| s.range());
10245
10246        self.transact(window, cx, |this, window, cx| {
10247            this.buffer.update(cx, |buffer, cx| {
10248                buffer.autoindent_ranges(selections, cx);
10249            });
10250            let selections = this.selections.all::<usize>(cx);
10251            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10252        });
10253    }
10254
10255    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10256        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10258        let selections = self.selections.all::<Point>(cx);
10259
10260        let mut new_cursors = Vec::new();
10261        let mut edit_ranges = Vec::new();
10262        let mut selections = selections.iter().peekable();
10263        while let Some(selection) = selections.next() {
10264            let mut rows = selection.spanned_rows(false, &display_map);
10265            let goal_display_column = selection.head().to_display_point(&display_map).column();
10266
10267            // Accumulate contiguous regions of rows that we want to delete.
10268            while let Some(next_selection) = selections.peek() {
10269                let next_rows = next_selection.spanned_rows(false, &display_map);
10270                if next_rows.start <= rows.end {
10271                    rows.end = next_rows.end;
10272                    selections.next().unwrap();
10273                } else {
10274                    break;
10275                }
10276            }
10277
10278            let buffer = &display_map.buffer_snapshot;
10279            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10280            let edit_end;
10281            let cursor_buffer_row;
10282            if buffer.max_point().row >= rows.end.0 {
10283                // If there's a line after the range, delete the \n from the end of the row range
10284                // and position the cursor on the next line.
10285                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10286                cursor_buffer_row = rows.end;
10287            } else {
10288                // If there isn't a line after the range, delete the \n from the line before the
10289                // start of the row range and position the cursor there.
10290                edit_start = edit_start.saturating_sub(1);
10291                edit_end = buffer.len();
10292                cursor_buffer_row = rows.start.previous_row();
10293            }
10294
10295            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10296            *cursor.column_mut() =
10297                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10298
10299            new_cursors.push((
10300                selection.id,
10301                buffer.anchor_after(cursor.to_point(&display_map)),
10302            ));
10303            edit_ranges.push(edit_start..edit_end);
10304        }
10305
10306        self.transact(window, cx, |this, window, cx| {
10307            let buffer = this.buffer.update(cx, |buffer, cx| {
10308                let empty_str: Arc<str> = Arc::default();
10309                buffer.edit(
10310                    edit_ranges
10311                        .into_iter()
10312                        .map(|range| (range, empty_str.clone())),
10313                    None,
10314                    cx,
10315                );
10316                buffer.snapshot(cx)
10317            });
10318            let new_selections = new_cursors
10319                .into_iter()
10320                .map(|(id, cursor)| {
10321                    let cursor = cursor.to_point(&buffer);
10322                    Selection {
10323                        id,
10324                        start: cursor,
10325                        end: cursor,
10326                        reversed: false,
10327                        goal: SelectionGoal::None,
10328                    }
10329                })
10330                .collect();
10331
10332            this.change_selections(Default::default(), window, cx, |s| {
10333                s.select(new_selections);
10334            });
10335        });
10336    }
10337
10338    pub fn join_lines_impl(
10339        &mut self,
10340        insert_whitespace: bool,
10341        window: &mut Window,
10342        cx: &mut Context<Self>,
10343    ) {
10344        if self.read_only(cx) {
10345            return;
10346        }
10347        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10348        for selection in self.selections.all::<Point>(cx) {
10349            let start = MultiBufferRow(selection.start.row);
10350            // Treat single line selections as if they include the next line. Otherwise this action
10351            // would do nothing for single line selections individual cursors.
10352            let end = if selection.start.row == selection.end.row {
10353                MultiBufferRow(selection.start.row + 1)
10354            } else {
10355                MultiBufferRow(selection.end.row)
10356            };
10357
10358            if let Some(last_row_range) = row_ranges.last_mut()
10359                && start <= last_row_range.end
10360            {
10361                last_row_range.end = end;
10362                continue;
10363            }
10364            row_ranges.push(start..end);
10365        }
10366
10367        let snapshot = self.buffer.read(cx).snapshot(cx);
10368        let mut cursor_positions = Vec::new();
10369        for row_range in &row_ranges {
10370            let anchor = snapshot.anchor_before(Point::new(
10371                row_range.end.previous_row().0,
10372                snapshot.line_len(row_range.end.previous_row()),
10373            ));
10374            cursor_positions.push(anchor..anchor);
10375        }
10376
10377        self.transact(window, cx, |this, window, cx| {
10378            for row_range in row_ranges.into_iter().rev() {
10379                for row in row_range.iter_rows().rev() {
10380                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10381                    let next_line_row = row.next_row();
10382                    let indent = snapshot.indent_size_for_line(next_line_row);
10383                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10384
10385                    let replace =
10386                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10387                            " "
10388                        } else {
10389                            ""
10390                        };
10391
10392                    this.buffer.update(cx, |buffer, cx| {
10393                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10394                    });
10395                }
10396            }
10397
10398            this.change_selections(Default::default(), window, cx, |s| {
10399                s.select_anchor_ranges(cursor_positions)
10400            });
10401        });
10402    }
10403
10404    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10405        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10406        self.join_lines_impl(true, window, cx);
10407    }
10408
10409    pub fn sort_lines_case_sensitive(
10410        &mut self,
10411        _: &SortLinesCaseSensitive,
10412        window: &mut Window,
10413        cx: &mut Context<Self>,
10414    ) {
10415        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10416    }
10417
10418    pub fn sort_lines_by_length(
10419        &mut self,
10420        _: &SortLinesByLength,
10421        window: &mut Window,
10422        cx: &mut Context<Self>,
10423    ) {
10424        self.manipulate_immutable_lines(window, cx, |lines| {
10425            lines.sort_by_key(|&line| line.chars().count())
10426        })
10427    }
10428
10429    pub fn sort_lines_case_insensitive(
10430        &mut self,
10431        _: &SortLinesCaseInsensitive,
10432        window: &mut Window,
10433        cx: &mut Context<Self>,
10434    ) {
10435        self.manipulate_immutable_lines(window, cx, |lines| {
10436            lines.sort_by_key(|line| line.to_lowercase())
10437        })
10438    }
10439
10440    pub fn unique_lines_case_insensitive(
10441        &mut self,
10442        _: &UniqueLinesCaseInsensitive,
10443        window: &mut Window,
10444        cx: &mut Context<Self>,
10445    ) {
10446        self.manipulate_immutable_lines(window, cx, |lines| {
10447            let mut seen = HashSet::default();
10448            lines.retain(|line| seen.insert(line.to_lowercase()));
10449        })
10450    }
10451
10452    pub fn unique_lines_case_sensitive(
10453        &mut self,
10454        _: &UniqueLinesCaseSensitive,
10455        window: &mut Window,
10456        cx: &mut Context<Self>,
10457    ) {
10458        self.manipulate_immutable_lines(window, cx, |lines| {
10459            let mut seen = HashSet::default();
10460            lines.retain(|line| seen.insert(*line));
10461        })
10462    }
10463
10464    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10465        let snapshot = self.buffer.read(cx).snapshot(cx);
10466        for selection in self.selections.disjoint_anchors().iter() {
10467            if snapshot
10468                .language_at(selection.start)
10469                .and_then(|lang| lang.config().wrap_characters.as_ref())
10470                .is_some()
10471            {
10472                return true;
10473            }
10474        }
10475        false
10476    }
10477
10478    fn wrap_selections_in_tag(
10479        &mut self,
10480        _: &WrapSelectionsInTag,
10481        window: &mut Window,
10482        cx: &mut Context<Self>,
10483    ) {
10484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10485
10486        let snapshot = self.buffer.read(cx).snapshot(cx);
10487
10488        let mut edits = Vec::new();
10489        let mut boundaries = Vec::new();
10490
10491        for selection in self.selections.all::<Point>(cx).iter() {
10492            let Some(wrap_config) = snapshot
10493                .language_at(selection.start)
10494                .and_then(|lang| lang.config().wrap_characters.clone())
10495            else {
10496                continue;
10497            };
10498
10499            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10500            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10501
10502            let start_before = snapshot.anchor_before(selection.start);
10503            let end_after = snapshot.anchor_after(selection.end);
10504
10505            edits.push((start_before..start_before, open_tag));
10506            edits.push((end_after..end_after, close_tag));
10507
10508            boundaries.push((
10509                start_before,
10510                end_after,
10511                wrap_config.start_prefix.len(),
10512                wrap_config.end_suffix.len(),
10513            ));
10514        }
10515
10516        if edits.is_empty() {
10517            return;
10518        }
10519
10520        self.transact(window, cx, |this, window, cx| {
10521            let buffer = this.buffer.update(cx, |buffer, cx| {
10522                buffer.edit(edits, None, cx);
10523                buffer.snapshot(cx)
10524            });
10525
10526            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10527            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10528                boundaries.into_iter()
10529            {
10530                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10531                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10532                new_selections.push(open_offset..open_offset);
10533                new_selections.push(close_offset..close_offset);
10534            }
10535
10536            this.change_selections(Default::default(), window, cx, |s| {
10537                s.select_ranges(new_selections);
10538            });
10539
10540            this.request_autoscroll(Autoscroll::fit(), cx);
10541        });
10542    }
10543
10544    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10545        let Some(project) = self.project.clone() else {
10546            return;
10547        };
10548        self.reload(project, window, cx)
10549            .detach_and_notify_err(window, cx);
10550    }
10551
10552    pub fn restore_file(
10553        &mut self,
10554        _: &::git::RestoreFile,
10555        window: &mut Window,
10556        cx: &mut Context<Self>,
10557    ) {
10558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10559        let mut buffer_ids = HashSet::default();
10560        let snapshot = self.buffer().read(cx).snapshot(cx);
10561        for selection in self.selections.all::<usize>(cx) {
10562            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10563        }
10564
10565        let buffer = self.buffer().read(cx);
10566        let ranges = buffer_ids
10567            .into_iter()
10568            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10569            .collect::<Vec<_>>();
10570
10571        self.restore_hunks_in_ranges(ranges, window, cx);
10572    }
10573
10574    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10576        let selections = self
10577            .selections
10578            .all(cx)
10579            .into_iter()
10580            .map(|s| s.range())
10581            .collect();
10582        self.restore_hunks_in_ranges(selections, window, cx);
10583    }
10584
10585    pub fn restore_hunks_in_ranges(
10586        &mut self,
10587        ranges: Vec<Range<Point>>,
10588        window: &mut Window,
10589        cx: &mut Context<Editor>,
10590    ) {
10591        let mut revert_changes = HashMap::default();
10592        let chunk_by = self
10593            .snapshot(window, cx)
10594            .hunks_for_ranges(ranges)
10595            .into_iter()
10596            .chunk_by(|hunk| hunk.buffer_id);
10597        for (buffer_id, hunks) in &chunk_by {
10598            let hunks = hunks.collect::<Vec<_>>();
10599            for hunk in &hunks {
10600                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10601            }
10602            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10603        }
10604        drop(chunk_by);
10605        if !revert_changes.is_empty() {
10606            self.transact(window, cx, |editor, window, cx| {
10607                editor.restore(revert_changes, window, cx);
10608            });
10609        }
10610    }
10611
10612    pub fn open_active_item_in_terminal(
10613        &mut self,
10614        _: &OpenInTerminal,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10619            let project_path = buffer.read(cx).project_path(cx)?;
10620            let project = self.project()?.read(cx);
10621            let entry = project.entry_for_path(&project_path, cx)?;
10622            let parent = match &entry.canonical_path {
10623                Some(canonical_path) => canonical_path.to_path_buf(),
10624                None => project.absolute_path(&project_path, cx)?,
10625            }
10626            .parent()?
10627            .to_path_buf();
10628            Some(parent)
10629        }) {
10630            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10631        }
10632    }
10633
10634    fn set_breakpoint_context_menu(
10635        &mut self,
10636        display_row: DisplayRow,
10637        position: Option<Anchor>,
10638        clicked_point: gpui::Point<Pixels>,
10639        window: &mut Window,
10640        cx: &mut Context<Self>,
10641    ) {
10642        let source = self
10643            .buffer
10644            .read(cx)
10645            .snapshot(cx)
10646            .anchor_before(Point::new(display_row.0, 0u32));
10647
10648        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10649
10650        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10651            self,
10652            source,
10653            clicked_point,
10654            context_menu,
10655            window,
10656            cx,
10657        );
10658    }
10659
10660    fn add_edit_breakpoint_block(
10661        &mut self,
10662        anchor: Anchor,
10663        breakpoint: &Breakpoint,
10664        edit_action: BreakpointPromptEditAction,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        let weak_editor = cx.weak_entity();
10669        let bp_prompt = cx.new(|cx| {
10670            BreakpointPromptEditor::new(
10671                weak_editor,
10672                anchor,
10673                breakpoint.clone(),
10674                edit_action,
10675                window,
10676                cx,
10677            )
10678        });
10679
10680        let height = bp_prompt.update(cx, |this, cx| {
10681            this.prompt
10682                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10683        });
10684        let cloned_prompt = bp_prompt.clone();
10685        let blocks = vec![BlockProperties {
10686            style: BlockStyle::Sticky,
10687            placement: BlockPlacement::Above(anchor),
10688            height: Some(height),
10689            render: Arc::new(move |cx| {
10690                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10691                cloned_prompt.clone().into_any_element()
10692            }),
10693            priority: 0,
10694        }];
10695
10696        let focus_handle = bp_prompt.focus_handle(cx);
10697        window.focus(&focus_handle);
10698
10699        let block_ids = self.insert_blocks(blocks, None, cx);
10700        bp_prompt.update(cx, |prompt, _| {
10701            prompt.add_block_ids(block_ids);
10702        });
10703    }
10704
10705    pub(crate) fn breakpoint_at_row(
10706        &self,
10707        row: u32,
10708        window: &mut Window,
10709        cx: &mut Context<Self>,
10710    ) -> Option<(Anchor, Breakpoint)> {
10711        let snapshot = self.snapshot(window, cx);
10712        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10713
10714        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10715    }
10716
10717    pub(crate) fn breakpoint_at_anchor(
10718        &self,
10719        breakpoint_position: Anchor,
10720        snapshot: &EditorSnapshot,
10721        cx: &mut Context<Self>,
10722    ) -> Option<(Anchor, Breakpoint)> {
10723        let buffer = self
10724            .buffer
10725            .read(cx)
10726            .buffer_for_anchor(breakpoint_position, cx)?;
10727
10728        let enclosing_excerpt = breakpoint_position.excerpt_id;
10729        let buffer_snapshot = buffer.read(cx).snapshot();
10730
10731        let row = buffer_snapshot
10732            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10733            .row;
10734
10735        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10736        let anchor_end = snapshot
10737            .buffer_snapshot
10738            .anchor_after(Point::new(row, line_len));
10739
10740        self.breakpoint_store
10741            .as_ref()?
10742            .read_with(cx, |breakpoint_store, cx| {
10743                breakpoint_store
10744                    .breakpoints(
10745                        &buffer,
10746                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10747                        &buffer_snapshot,
10748                        cx,
10749                    )
10750                    .next()
10751                    .and_then(|(bp, _)| {
10752                        let breakpoint_row = buffer_snapshot
10753                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10754                            .row;
10755
10756                        if breakpoint_row == row {
10757                            snapshot
10758                                .buffer_snapshot
10759                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10760                                .map(|position| (position, bp.bp.clone()))
10761                        } else {
10762                            None
10763                        }
10764                    })
10765            })
10766    }
10767
10768    pub fn edit_log_breakpoint(
10769        &mut self,
10770        _: &EditLogBreakpoint,
10771        window: &mut Window,
10772        cx: &mut Context<Self>,
10773    ) {
10774        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10775            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10776                message: None,
10777                state: BreakpointState::Enabled,
10778                condition: None,
10779                hit_condition: None,
10780            });
10781
10782            self.add_edit_breakpoint_block(
10783                anchor,
10784                &breakpoint,
10785                BreakpointPromptEditAction::Log,
10786                window,
10787                cx,
10788            );
10789        }
10790    }
10791
10792    fn breakpoints_at_cursors(
10793        &self,
10794        window: &mut Window,
10795        cx: &mut Context<Self>,
10796    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10797        let snapshot = self.snapshot(window, cx);
10798        let cursors = self
10799            .selections
10800            .disjoint_anchors()
10801            .iter()
10802            .map(|selection| {
10803                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10804
10805                let breakpoint_position = self
10806                    .breakpoint_at_row(cursor_position.row, window, cx)
10807                    .map(|bp| bp.0)
10808                    .unwrap_or_else(|| {
10809                        snapshot
10810                            .display_snapshot
10811                            .buffer_snapshot
10812                            .anchor_after(Point::new(cursor_position.row, 0))
10813                    });
10814
10815                let breakpoint = self
10816                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10817                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10818
10819                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10820            })
10821            // 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.
10822            .collect::<HashMap<Anchor, _>>();
10823
10824        cursors.into_iter().collect()
10825    }
10826
10827    pub fn enable_breakpoint(
10828        &mut self,
10829        _: &crate::actions::EnableBreakpoint,
10830        window: &mut Window,
10831        cx: &mut Context<Self>,
10832    ) {
10833        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10834            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10835                continue;
10836            };
10837            self.edit_breakpoint_at_anchor(
10838                anchor,
10839                breakpoint,
10840                BreakpointEditAction::InvertState,
10841                cx,
10842            );
10843        }
10844    }
10845
10846    pub fn disable_breakpoint(
10847        &mut self,
10848        _: &crate::actions::DisableBreakpoint,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851    ) {
10852        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10853            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10854                continue;
10855            };
10856            self.edit_breakpoint_at_anchor(
10857                anchor,
10858                breakpoint,
10859                BreakpointEditAction::InvertState,
10860                cx,
10861            );
10862        }
10863    }
10864
10865    pub fn toggle_breakpoint(
10866        &mut self,
10867        _: &crate::actions::ToggleBreakpoint,
10868        window: &mut Window,
10869        cx: &mut Context<Self>,
10870    ) {
10871        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10872            if let Some(breakpoint) = breakpoint {
10873                self.edit_breakpoint_at_anchor(
10874                    anchor,
10875                    breakpoint,
10876                    BreakpointEditAction::Toggle,
10877                    cx,
10878                );
10879            } else {
10880                self.edit_breakpoint_at_anchor(
10881                    anchor,
10882                    Breakpoint::new_standard(),
10883                    BreakpointEditAction::Toggle,
10884                    cx,
10885                );
10886            }
10887        }
10888    }
10889
10890    pub fn edit_breakpoint_at_anchor(
10891        &mut self,
10892        breakpoint_position: Anchor,
10893        breakpoint: Breakpoint,
10894        edit_action: BreakpointEditAction,
10895        cx: &mut Context<Self>,
10896    ) {
10897        let Some(breakpoint_store) = &self.breakpoint_store else {
10898            return;
10899        };
10900
10901        let Some(buffer) = self
10902            .buffer
10903            .read(cx)
10904            .buffer_for_anchor(breakpoint_position, cx)
10905        else {
10906            return;
10907        };
10908
10909        breakpoint_store.update(cx, |breakpoint_store, cx| {
10910            breakpoint_store.toggle_breakpoint(
10911                buffer,
10912                BreakpointWithPosition {
10913                    position: breakpoint_position.text_anchor,
10914                    bp: breakpoint,
10915                },
10916                edit_action,
10917                cx,
10918            );
10919        });
10920
10921        cx.notify();
10922    }
10923
10924    #[cfg(any(test, feature = "test-support"))]
10925    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10926        self.breakpoint_store.clone()
10927    }
10928
10929    pub fn prepare_restore_change(
10930        &self,
10931        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10932        hunk: &MultiBufferDiffHunk,
10933        cx: &mut App,
10934    ) -> Option<()> {
10935        if hunk.is_created_file() {
10936            return None;
10937        }
10938        let buffer = self.buffer.read(cx);
10939        let diff = buffer.diff_for(hunk.buffer_id)?;
10940        let buffer = buffer.buffer(hunk.buffer_id)?;
10941        let buffer = buffer.read(cx);
10942        let original_text = diff
10943            .read(cx)
10944            .base_text()
10945            .as_rope()
10946            .slice(hunk.diff_base_byte_range.clone());
10947        let buffer_snapshot = buffer.snapshot();
10948        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10949        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10950            probe
10951                .0
10952                .start
10953                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10954                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10955        }) {
10956            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10957            Some(())
10958        } else {
10959            None
10960        }
10961    }
10962
10963    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10964        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10965    }
10966
10967    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10968        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10969    }
10970
10971    fn manipulate_lines<M>(
10972        &mut self,
10973        window: &mut Window,
10974        cx: &mut Context<Self>,
10975        mut manipulate: M,
10976    ) where
10977        M: FnMut(&str) -> LineManipulationResult,
10978    {
10979        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10980
10981        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10982        let buffer = self.buffer.read(cx).snapshot(cx);
10983
10984        let mut edits = Vec::new();
10985
10986        let selections = self.selections.all::<Point>(cx);
10987        let mut selections = selections.iter().peekable();
10988        let mut contiguous_row_selections = Vec::new();
10989        let mut new_selections = Vec::new();
10990        let mut added_lines = 0;
10991        let mut removed_lines = 0;
10992
10993        while let Some(selection) = selections.next() {
10994            let (start_row, end_row) = consume_contiguous_rows(
10995                &mut contiguous_row_selections,
10996                selection,
10997                &display_map,
10998                &mut selections,
10999            );
11000
11001            let start_point = Point::new(start_row.0, 0);
11002            let end_point = Point::new(
11003                end_row.previous_row().0,
11004                buffer.line_len(end_row.previous_row()),
11005            );
11006            let text = buffer
11007                .text_for_range(start_point..end_point)
11008                .collect::<String>();
11009
11010            let LineManipulationResult {
11011                new_text,
11012                line_count_before,
11013                line_count_after,
11014            } = manipulate(&text);
11015
11016            edits.push((start_point..end_point, new_text));
11017
11018            // Selections must change based on added and removed line count
11019            let start_row =
11020                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11021            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11022            new_selections.push(Selection {
11023                id: selection.id,
11024                start: start_row,
11025                end: end_row,
11026                goal: SelectionGoal::None,
11027                reversed: selection.reversed,
11028            });
11029
11030            if line_count_after > line_count_before {
11031                added_lines += line_count_after - line_count_before;
11032            } else if line_count_before > line_count_after {
11033                removed_lines += line_count_before - line_count_after;
11034            }
11035        }
11036
11037        self.transact(window, cx, |this, window, cx| {
11038            let buffer = this.buffer.update(cx, |buffer, cx| {
11039                buffer.edit(edits, None, cx);
11040                buffer.snapshot(cx)
11041            });
11042
11043            // Recalculate offsets on newly edited buffer
11044            let new_selections = new_selections
11045                .iter()
11046                .map(|s| {
11047                    let start_point = Point::new(s.start.0, 0);
11048                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11049                    Selection {
11050                        id: s.id,
11051                        start: buffer.point_to_offset(start_point),
11052                        end: buffer.point_to_offset(end_point),
11053                        goal: s.goal,
11054                        reversed: s.reversed,
11055                    }
11056                })
11057                .collect();
11058
11059            this.change_selections(Default::default(), window, cx, |s| {
11060                s.select(new_selections);
11061            });
11062
11063            this.request_autoscroll(Autoscroll::fit(), cx);
11064        });
11065    }
11066
11067    fn manipulate_immutable_lines<Fn>(
11068        &mut self,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071        mut callback: Fn,
11072    ) where
11073        Fn: FnMut(&mut Vec<&str>),
11074    {
11075        self.manipulate_lines(window, cx, |text| {
11076            let mut lines: Vec<&str> = text.split('\n').collect();
11077            let line_count_before = lines.len();
11078
11079            callback(&mut lines);
11080
11081            LineManipulationResult {
11082                new_text: lines.join("\n"),
11083                line_count_before,
11084                line_count_after: lines.len(),
11085            }
11086        });
11087    }
11088
11089    fn manipulate_mutable_lines<Fn>(
11090        &mut self,
11091        window: &mut Window,
11092        cx: &mut Context<Self>,
11093        mut callback: Fn,
11094    ) where
11095        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11096    {
11097        self.manipulate_lines(window, cx, |text| {
11098            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11099            let line_count_before = lines.len();
11100
11101            callback(&mut lines);
11102
11103            LineManipulationResult {
11104                new_text: lines.join("\n"),
11105                line_count_before,
11106                line_count_after: lines.len(),
11107            }
11108        });
11109    }
11110
11111    pub fn convert_indentation_to_spaces(
11112        &mut self,
11113        _: &ConvertIndentationToSpaces,
11114        window: &mut Window,
11115        cx: &mut Context<Self>,
11116    ) {
11117        let settings = self.buffer.read(cx).language_settings(cx);
11118        let tab_size = settings.tab_size.get() as usize;
11119
11120        self.manipulate_mutable_lines(window, cx, |lines| {
11121            // Allocates a reasonably sized scratch buffer once for the whole loop
11122            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11123            // Avoids recomputing spaces that could be inserted many times
11124            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11125                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11126                .collect();
11127
11128            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11129                let mut chars = line.as_ref().chars();
11130                let mut col = 0;
11131                let mut changed = false;
11132
11133                for ch in chars.by_ref() {
11134                    match ch {
11135                        ' ' => {
11136                            reindented_line.push(' ');
11137                            col += 1;
11138                        }
11139                        '\t' => {
11140                            // \t are converted to spaces depending on the current column
11141                            let spaces_len = tab_size - (col % tab_size);
11142                            reindented_line.extend(&space_cache[spaces_len - 1]);
11143                            col += spaces_len;
11144                            changed = true;
11145                        }
11146                        _ => {
11147                            // If we dont append before break, the character is consumed
11148                            reindented_line.push(ch);
11149                            break;
11150                        }
11151                    }
11152                }
11153
11154                if !changed {
11155                    reindented_line.clear();
11156                    continue;
11157                }
11158                // Append the rest of the line and replace old reference with new one
11159                reindented_line.extend(chars);
11160                *line = Cow::Owned(reindented_line.clone());
11161                reindented_line.clear();
11162            }
11163        });
11164    }
11165
11166    pub fn convert_indentation_to_tabs(
11167        &mut self,
11168        _: &ConvertIndentationToTabs,
11169        window: &mut Window,
11170        cx: &mut Context<Self>,
11171    ) {
11172        let settings = self.buffer.read(cx).language_settings(cx);
11173        let tab_size = settings.tab_size.get() as usize;
11174
11175        self.manipulate_mutable_lines(window, cx, |lines| {
11176            // Allocates a reasonably sized buffer once for the whole loop
11177            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11178            // Avoids recomputing spaces that could be inserted many times
11179            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11180                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11181                .collect();
11182
11183            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11184                let mut chars = line.chars();
11185                let mut spaces_count = 0;
11186                let mut first_non_indent_char = None;
11187                let mut changed = false;
11188
11189                for ch in chars.by_ref() {
11190                    match ch {
11191                        ' ' => {
11192                            // Keep track of spaces. Append \t when we reach tab_size
11193                            spaces_count += 1;
11194                            changed = true;
11195                            if spaces_count == tab_size {
11196                                reindented_line.push('\t');
11197                                spaces_count = 0;
11198                            }
11199                        }
11200                        '\t' => {
11201                            reindented_line.push('\t');
11202                            spaces_count = 0;
11203                        }
11204                        _ => {
11205                            // Dont append it yet, we might have remaining spaces
11206                            first_non_indent_char = Some(ch);
11207                            break;
11208                        }
11209                    }
11210                }
11211
11212                if !changed {
11213                    reindented_line.clear();
11214                    continue;
11215                }
11216                // Remaining spaces that didn't make a full tab stop
11217                if spaces_count > 0 {
11218                    reindented_line.extend(&space_cache[spaces_count - 1]);
11219                }
11220                // If we consume an extra character that was not indentation, add it back
11221                if let Some(extra_char) = first_non_indent_char {
11222                    reindented_line.push(extra_char);
11223                }
11224                // Append the rest of the line and replace old reference with new one
11225                reindented_line.extend(chars);
11226                *line = Cow::Owned(reindented_line.clone());
11227                reindented_line.clear();
11228            }
11229        });
11230    }
11231
11232    pub fn convert_to_upper_case(
11233        &mut self,
11234        _: &ConvertToUpperCase,
11235        window: &mut Window,
11236        cx: &mut Context<Self>,
11237    ) {
11238        self.manipulate_text(window, cx, |text| text.to_uppercase())
11239    }
11240
11241    pub fn convert_to_lower_case(
11242        &mut self,
11243        _: &ConvertToLowerCase,
11244        window: &mut Window,
11245        cx: &mut Context<Self>,
11246    ) {
11247        self.manipulate_text(window, cx, |text| text.to_lowercase())
11248    }
11249
11250    pub fn convert_to_title_case(
11251        &mut self,
11252        _: &ConvertToTitleCase,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255    ) {
11256        self.manipulate_text(window, cx, |text| {
11257            text.split('\n')
11258                .map(|line| line.to_case(Case::Title))
11259                .join("\n")
11260        })
11261    }
11262
11263    pub fn convert_to_snake_case(
11264        &mut self,
11265        _: &ConvertToSnakeCase,
11266        window: &mut Window,
11267        cx: &mut Context<Self>,
11268    ) {
11269        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11270    }
11271
11272    pub fn convert_to_kebab_case(
11273        &mut self,
11274        _: &ConvertToKebabCase,
11275        window: &mut Window,
11276        cx: &mut Context<Self>,
11277    ) {
11278        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11279    }
11280
11281    pub fn convert_to_upper_camel_case(
11282        &mut self,
11283        _: &ConvertToUpperCamelCase,
11284        window: &mut Window,
11285        cx: &mut Context<Self>,
11286    ) {
11287        self.manipulate_text(window, cx, |text| {
11288            text.split('\n')
11289                .map(|line| line.to_case(Case::UpperCamel))
11290                .join("\n")
11291        })
11292    }
11293
11294    pub fn convert_to_lower_camel_case(
11295        &mut self,
11296        _: &ConvertToLowerCamelCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11301    }
11302
11303    pub fn convert_to_opposite_case(
11304        &mut self,
11305        _: &ConvertToOppositeCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.chars()
11311                .fold(String::with_capacity(text.len()), |mut t, c| {
11312                    if c.is_uppercase() {
11313                        t.extend(c.to_lowercase());
11314                    } else {
11315                        t.extend(c.to_uppercase());
11316                    }
11317                    t
11318                })
11319        })
11320    }
11321
11322    pub fn convert_to_sentence_case(
11323        &mut self,
11324        _: &ConvertToSentenceCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11329    }
11330
11331    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11332        self.manipulate_text(window, cx, |text| {
11333            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11334            if has_upper_case_characters {
11335                text.to_lowercase()
11336            } else {
11337                text.to_uppercase()
11338            }
11339        })
11340    }
11341
11342    pub fn convert_to_rot13(
11343        &mut self,
11344        _: &ConvertToRot13,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) {
11348        self.manipulate_text(window, cx, |text| {
11349            text.chars()
11350                .map(|c| match c {
11351                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11352                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11353                    _ => c,
11354                })
11355                .collect()
11356        })
11357    }
11358
11359    pub fn convert_to_rot47(
11360        &mut self,
11361        _: &ConvertToRot47,
11362        window: &mut Window,
11363        cx: &mut Context<Self>,
11364    ) {
11365        self.manipulate_text(window, cx, |text| {
11366            text.chars()
11367                .map(|c| {
11368                    let code_point = c as u32;
11369                    if code_point >= 33 && code_point <= 126 {
11370                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11371                    }
11372                    c
11373                })
11374                .collect()
11375        })
11376    }
11377
11378    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11379    where
11380        Fn: FnMut(&str) -> String,
11381    {
11382        let buffer = self.buffer.read(cx).snapshot(cx);
11383
11384        let mut new_selections = Vec::new();
11385        let mut edits = Vec::new();
11386        let mut selection_adjustment = 0i32;
11387
11388        for selection in self.selections.all::<usize>(cx) {
11389            let selection_is_empty = selection.is_empty();
11390
11391            let (start, end) = if selection_is_empty {
11392                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11393                (word_range.start, word_range.end)
11394            } else {
11395                (selection.start, selection.end)
11396            };
11397
11398            let text = buffer.text_for_range(start..end).collect::<String>();
11399            let old_length = text.len() as i32;
11400            let text = callback(&text);
11401
11402            new_selections.push(Selection {
11403                start: (start as i32 - selection_adjustment) as usize,
11404                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11405                goal: SelectionGoal::None,
11406                ..selection
11407            });
11408
11409            selection_adjustment += old_length - text.len() as i32;
11410
11411            edits.push((start..end, text));
11412        }
11413
11414        self.transact(window, cx, |this, window, cx| {
11415            this.buffer.update(cx, |buffer, cx| {
11416                buffer.edit(edits, None, cx);
11417            });
11418
11419            this.change_selections(Default::default(), window, cx, |s| {
11420                s.select(new_selections);
11421            });
11422
11423            this.request_autoscroll(Autoscroll::fit(), cx);
11424        });
11425    }
11426
11427    pub fn move_selection_on_drop(
11428        &mut self,
11429        selection: &Selection<Anchor>,
11430        target: DisplayPoint,
11431        is_cut: bool,
11432        window: &mut Window,
11433        cx: &mut Context<Self>,
11434    ) {
11435        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11436        let buffer = &display_map.buffer_snapshot;
11437        let mut edits = Vec::new();
11438        let insert_point = display_map
11439            .clip_point(target, Bias::Left)
11440            .to_point(&display_map);
11441        let text = buffer
11442            .text_for_range(selection.start..selection.end)
11443            .collect::<String>();
11444        if is_cut {
11445            edits.push(((selection.start..selection.end), String::new()));
11446        }
11447        let insert_anchor = buffer.anchor_before(insert_point);
11448        edits.push(((insert_anchor..insert_anchor), text));
11449        let last_edit_start = insert_anchor.bias_left(buffer);
11450        let last_edit_end = insert_anchor.bias_right(buffer);
11451        self.transact(window, cx, |this, window, cx| {
11452            this.buffer.update(cx, |buffer, cx| {
11453                buffer.edit(edits, None, cx);
11454            });
11455            this.change_selections(Default::default(), window, cx, |s| {
11456                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11457            });
11458        });
11459    }
11460
11461    pub fn clear_selection_drag_state(&mut self) {
11462        self.selection_drag_state = SelectionDragState::None;
11463    }
11464
11465    pub fn duplicate(
11466        &mut self,
11467        upwards: bool,
11468        whole_lines: bool,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471    ) {
11472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11473
11474        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11475        let buffer = &display_map.buffer_snapshot;
11476        let selections = self.selections.all::<Point>(cx);
11477
11478        let mut edits = Vec::new();
11479        let mut selections_iter = selections.iter().peekable();
11480        while let Some(selection) = selections_iter.next() {
11481            let mut rows = selection.spanned_rows(false, &display_map);
11482            // duplicate line-wise
11483            if whole_lines || selection.start == selection.end {
11484                // Avoid duplicating the same lines twice.
11485                while let Some(next_selection) = selections_iter.peek() {
11486                    let next_rows = next_selection.spanned_rows(false, &display_map);
11487                    if next_rows.start < rows.end {
11488                        rows.end = next_rows.end;
11489                        selections_iter.next().unwrap();
11490                    } else {
11491                        break;
11492                    }
11493                }
11494
11495                // Copy the text from the selected row region and splice it either at the start
11496                // or end of the region.
11497                let start = Point::new(rows.start.0, 0);
11498                let end = Point::new(
11499                    rows.end.previous_row().0,
11500                    buffer.line_len(rows.end.previous_row()),
11501                );
11502                let text = buffer
11503                    .text_for_range(start..end)
11504                    .chain(Some("\n"))
11505                    .collect::<String>();
11506                let insert_location = if upwards {
11507                    Point::new(rows.end.0, 0)
11508                } else {
11509                    start
11510                };
11511                edits.push((insert_location..insert_location, text));
11512            } else {
11513                // duplicate character-wise
11514                let start = selection.start;
11515                let end = selection.end;
11516                let text = buffer.text_for_range(start..end).collect::<String>();
11517                edits.push((selection.end..selection.end, text));
11518            }
11519        }
11520
11521        self.transact(window, cx, |this, _, cx| {
11522            this.buffer.update(cx, |buffer, cx| {
11523                buffer.edit(edits, None, cx);
11524            });
11525
11526            this.request_autoscroll(Autoscroll::fit(), cx);
11527        });
11528    }
11529
11530    pub fn duplicate_line_up(
11531        &mut self,
11532        _: &DuplicateLineUp,
11533        window: &mut Window,
11534        cx: &mut Context<Self>,
11535    ) {
11536        self.duplicate(true, true, window, cx);
11537    }
11538
11539    pub fn duplicate_line_down(
11540        &mut self,
11541        _: &DuplicateLineDown,
11542        window: &mut Window,
11543        cx: &mut Context<Self>,
11544    ) {
11545        self.duplicate(false, true, window, cx);
11546    }
11547
11548    pub fn duplicate_selection(
11549        &mut self,
11550        _: &DuplicateSelection,
11551        window: &mut Window,
11552        cx: &mut Context<Self>,
11553    ) {
11554        self.duplicate(false, false, window, cx);
11555    }
11556
11557    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11559        if self.mode.is_single_line() {
11560            cx.propagate();
11561            return;
11562        }
11563
11564        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11565        let buffer = self.buffer.read(cx).snapshot(cx);
11566
11567        let mut edits = Vec::new();
11568        let mut unfold_ranges = Vec::new();
11569        let mut refold_creases = Vec::new();
11570
11571        let selections = self.selections.all::<Point>(cx);
11572        let mut selections = selections.iter().peekable();
11573        let mut contiguous_row_selections = Vec::new();
11574        let mut new_selections = Vec::new();
11575
11576        while let Some(selection) = selections.next() {
11577            // Find all the selections that span a contiguous row range
11578            let (start_row, end_row) = consume_contiguous_rows(
11579                &mut contiguous_row_selections,
11580                selection,
11581                &display_map,
11582                &mut selections,
11583            );
11584
11585            // Move the text spanned by the row range to be before the line preceding the row range
11586            if start_row.0 > 0 {
11587                let range_to_move = Point::new(
11588                    start_row.previous_row().0,
11589                    buffer.line_len(start_row.previous_row()),
11590                )
11591                    ..Point::new(
11592                        end_row.previous_row().0,
11593                        buffer.line_len(end_row.previous_row()),
11594                    );
11595                let insertion_point = display_map
11596                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11597                    .0;
11598
11599                // Don't move lines across excerpts
11600                if buffer
11601                    .excerpt_containing(insertion_point..range_to_move.end)
11602                    .is_some()
11603                {
11604                    let text = buffer
11605                        .text_for_range(range_to_move.clone())
11606                        .flat_map(|s| s.chars())
11607                        .skip(1)
11608                        .chain(['\n'])
11609                        .collect::<String>();
11610
11611                    edits.push((
11612                        buffer.anchor_after(range_to_move.start)
11613                            ..buffer.anchor_before(range_to_move.end),
11614                        String::new(),
11615                    ));
11616                    let insertion_anchor = buffer.anchor_after(insertion_point);
11617                    edits.push((insertion_anchor..insertion_anchor, text));
11618
11619                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11620
11621                    // Move selections up
11622                    new_selections.extend(contiguous_row_selections.drain(..).map(
11623                        |mut selection| {
11624                            selection.start.row -= row_delta;
11625                            selection.end.row -= row_delta;
11626                            selection
11627                        },
11628                    ));
11629
11630                    // Move folds up
11631                    unfold_ranges.push(range_to_move.clone());
11632                    for fold in display_map.folds_in_range(
11633                        buffer.anchor_before(range_to_move.start)
11634                            ..buffer.anchor_after(range_to_move.end),
11635                    ) {
11636                        let mut start = fold.range.start.to_point(&buffer);
11637                        let mut end = fold.range.end.to_point(&buffer);
11638                        start.row -= row_delta;
11639                        end.row -= row_delta;
11640                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11641                    }
11642                }
11643            }
11644
11645            // If we didn't move line(s), preserve the existing selections
11646            new_selections.append(&mut contiguous_row_selections);
11647        }
11648
11649        self.transact(window, cx, |this, window, cx| {
11650            this.unfold_ranges(&unfold_ranges, true, true, cx);
11651            this.buffer.update(cx, |buffer, cx| {
11652                for (range, text) in edits {
11653                    buffer.edit([(range, text)], None, cx);
11654                }
11655            });
11656            this.fold_creases(refold_creases, true, window, cx);
11657            this.change_selections(Default::default(), window, cx, |s| {
11658                s.select(new_selections);
11659            })
11660        });
11661    }
11662
11663    pub fn move_line_down(
11664        &mut self,
11665        _: &MoveLineDown,
11666        window: &mut Window,
11667        cx: &mut Context<Self>,
11668    ) {
11669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11670        if self.mode.is_single_line() {
11671            cx.propagate();
11672            return;
11673        }
11674
11675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11676        let buffer = self.buffer.read(cx).snapshot(cx);
11677
11678        let mut edits = Vec::new();
11679        let mut unfold_ranges = Vec::new();
11680        let mut refold_creases = Vec::new();
11681
11682        let selections = self.selections.all::<Point>(cx);
11683        let mut selections = selections.iter().peekable();
11684        let mut contiguous_row_selections = Vec::new();
11685        let mut new_selections = Vec::new();
11686
11687        while let Some(selection) = selections.next() {
11688            // Find all the selections that span a contiguous row range
11689            let (start_row, end_row) = consume_contiguous_rows(
11690                &mut contiguous_row_selections,
11691                selection,
11692                &display_map,
11693                &mut selections,
11694            );
11695
11696            // Move the text spanned by the row range to be after the last line of the row range
11697            if end_row.0 <= buffer.max_point().row {
11698                let range_to_move =
11699                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11700                let insertion_point = display_map
11701                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11702                    .0;
11703
11704                // Don't move lines across excerpt boundaries
11705                if buffer
11706                    .excerpt_containing(range_to_move.start..insertion_point)
11707                    .is_some()
11708                {
11709                    let mut text = String::from("\n");
11710                    text.extend(buffer.text_for_range(range_to_move.clone()));
11711                    text.pop(); // Drop trailing newline
11712                    edits.push((
11713                        buffer.anchor_after(range_to_move.start)
11714                            ..buffer.anchor_before(range_to_move.end),
11715                        String::new(),
11716                    ));
11717                    let insertion_anchor = buffer.anchor_after(insertion_point);
11718                    edits.push((insertion_anchor..insertion_anchor, text));
11719
11720                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11721
11722                    // Move selections down
11723                    new_selections.extend(contiguous_row_selections.drain(..).map(
11724                        |mut selection| {
11725                            selection.start.row += row_delta;
11726                            selection.end.row += row_delta;
11727                            selection
11728                        },
11729                    ));
11730
11731                    // Move folds down
11732                    unfold_ranges.push(range_to_move.clone());
11733                    for fold in display_map.folds_in_range(
11734                        buffer.anchor_before(range_to_move.start)
11735                            ..buffer.anchor_after(range_to_move.end),
11736                    ) {
11737                        let mut start = fold.range.start.to_point(&buffer);
11738                        let mut end = fold.range.end.to_point(&buffer);
11739                        start.row += row_delta;
11740                        end.row += row_delta;
11741                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11742                    }
11743                }
11744            }
11745
11746            // If we didn't move line(s), preserve the existing selections
11747            new_selections.append(&mut contiguous_row_selections);
11748        }
11749
11750        self.transact(window, cx, |this, window, cx| {
11751            this.unfold_ranges(&unfold_ranges, true, true, cx);
11752            this.buffer.update(cx, |buffer, cx| {
11753                for (range, text) in edits {
11754                    buffer.edit([(range, text)], None, cx);
11755                }
11756            });
11757            this.fold_creases(refold_creases, true, window, cx);
11758            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11759        });
11760    }
11761
11762    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11764        let text_layout_details = &self.text_layout_details(window);
11765        self.transact(window, cx, |this, window, cx| {
11766            let edits = this.change_selections(Default::default(), window, cx, |s| {
11767                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11768                s.move_with(|display_map, selection| {
11769                    if !selection.is_empty() {
11770                        return;
11771                    }
11772
11773                    let mut head = selection.head();
11774                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11775                    if head.column() == display_map.line_len(head.row()) {
11776                        transpose_offset = display_map
11777                            .buffer_snapshot
11778                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11779                    }
11780
11781                    if transpose_offset == 0 {
11782                        return;
11783                    }
11784
11785                    *head.column_mut() += 1;
11786                    head = display_map.clip_point(head, Bias::Right);
11787                    let goal = SelectionGoal::HorizontalPosition(
11788                        display_map
11789                            .x_for_display_point(head, text_layout_details)
11790                            .into(),
11791                    );
11792                    selection.collapse_to(head, goal);
11793
11794                    let transpose_start = display_map
11795                        .buffer_snapshot
11796                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11797                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11798                        let transpose_end = display_map
11799                            .buffer_snapshot
11800                            .clip_offset(transpose_offset + 1, Bias::Right);
11801                        if let Some(ch) =
11802                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11803                        {
11804                            edits.push((transpose_start..transpose_offset, String::new()));
11805                            edits.push((transpose_end..transpose_end, ch.to_string()));
11806                        }
11807                    }
11808                });
11809                edits
11810            });
11811            this.buffer
11812                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11813            let selections = this.selections.all::<usize>(cx);
11814            this.change_selections(Default::default(), window, cx, |s| {
11815                s.select(selections);
11816            });
11817        });
11818    }
11819
11820    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11822        if self.mode.is_single_line() {
11823            cx.propagate();
11824            return;
11825        }
11826
11827        self.rewrap_impl(RewrapOptions::default(), cx)
11828    }
11829
11830    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11831        let buffer = self.buffer.read(cx).snapshot(cx);
11832        let selections = self.selections.all::<Point>(cx);
11833
11834        #[derive(Clone, Debug, PartialEq)]
11835        enum CommentFormat {
11836            /// single line comment, with prefix for line
11837            Line(String),
11838            /// single line within a block comment, with prefix for line
11839            BlockLine(String),
11840            /// a single line of a block comment that includes the initial delimiter
11841            BlockCommentWithStart(BlockCommentConfig),
11842            /// a single line of a block comment that includes the ending delimiter
11843            BlockCommentWithEnd(BlockCommentConfig),
11844        }
11845
11846        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11847        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11848            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11849                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11850                .peekable();
11851
11852            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11853                row
11854            } else {
11855                return Vec::new();
11856            };
11857
11858            let language_settings = buffer.language_settings_at(selection.head(), cx);
11859            let language_scope = buffer.language_scope_at(selection.head());
11860
11861            let indent_and_prefix_for_row =
11862                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11863                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11864                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11865                        &language_scope
11866                    {
11867                        let indent_end = Point::new(row, indent.len);
11868                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11869                        let line_text_after_indent = buffer
11870                            .text_for_range(indent_end..line_end)
11871                            .collect::<String>();
11872
11873                        let is_within_comment_override = buffer
11874                            .language_scope_at(indent_end)
11875                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11876                        let comment_delimiters = if is_within_comment_override {
11877                            // we are within a comment syntax node, but we don't
11878                            // yet know what kind of comment: block, doc or line
11879                            match (
11880                                language_scope.documentation_comment(),
11881                                language_scope.block_comment(),
11882                            ) {
11883                                (Some(config), _) | (_, Some(config))
11884                                    if buffer.contains_str_at(indent_end, &config.start) =>
11885                                {
11886                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11887                                }
11888                                (Some(config), _) | (_, Some(config))
11889                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11890                                {
11891                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11892                                }
11893                                (Some(config), _) | (_, Some(config))
11894                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11895                                {
11896                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11897                                }
11898                                (_, _) => language_scope
11899                                    .line_comment_prefixes()
11900                                    .iter()
11901                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11902                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11903                            }
11904                        } else {
11905                            // we not in an overridden comment node, but we may
11906                            // be within a non-overridden line comment node
11907                            language_scope
11908                                .line_comment_prefixes()
11909                                .iter()
11910                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11911                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11912                        };
11913
11914                        let rewrap_prefix = language_scope
11915                            .rewrap_prefixes()
11916                            .iter()
11917                            .find_map(|prefix_regex| {
11918                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11919                                    if mat.start() == 0 {
11920                                        Some(mat.as_str().to_string())
11921                                    } else {
11922                                        None
11923                                    }
11924                                })
11925                            })
11926                            .flatten();
11927                        (comment_delimiters, rewrap_prefix)
11928                    } else {
11929                        (None, None)
11930                    };
11931                    (indent, comment_prefix, rewrap_prefix)
11932                };
11933
11934            let mut ranges = Vec::new();
11935            let from_empty_selection = selection.is_empty();
11936
11937            let mut current_range_start = first_row;
11938            let mut prev_row = first_row;
11939            let (
11940                mut current_range_indent,
11941                mut current_range_comment_delimiters,
11942                mut current_range_rewrap_prefix,
11943            ) = indent_and_prefix_for_row(first_row);
11944
11945            for row in non_blank_rows_iter.skip(1) {
11946                let has_paragraph_break = row > prev_row + 1;
11947
11948                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
11949                    indent_and_prefix_for_row(row);
11950
11951                let has_indent_change = row_indent != current_range_indent;
11952                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
11953
11954                let has_boundary_change = has_comment_change
11955                    || row_rewrap_prefix.is_some()
11956                    || (has_indent_change && current_range_comment_delimiters.is_some());
11957
11958                if has_paragraph_break || has_boundary_change {
11959                    ranges.push((
11960                        language_settings.clone(),
11961                        Point::new(current_range_start, 0)
11962                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11963                        current_range_indent,
11964                        current_range_comment_delimiters.clone(),
11965                        current_range_rewrap_prefix.clone(),
11966                        from_empty_selection,
11967                    ));
11968                    current_range_start = row;
11969                    current_range_indent = row_indent;
11970                    current_range_comment_delimiters = row_comment_delimiters;
11971                    current_range_rewrap_prefix = row_rewrap_prefix;
11972                }
11973                prev_row = row;
11974            }
11975
11976            ranges.push((
11977                language_settings.clone(),
11978                Point::new(current_range_start, 0)
11979                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11980                current_range_indent,
11981                current_range_comment_delimiters,
11982                current_range_rewrap_prefix,
11983                from_empty_selection,
11984            ));
11985
11986            ranges
11987        });
11988
11989        let mut edits = Vec::new();
11990        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11991
11992        for (
11993            language_settings,
11994            wrap_range,
11995            mut indent_size,
11996            comment_prefix,
11997            rewrap_prefix,
11998            from_empty_selection,
11999        ) in wrap_ranges
12000        {
12001            let mut start_row = wrap_range.start.row;
12002            let mut end_row = wrap_range.end.row;
12003
12004            // Skip selections that overlap with a range that has already been rewrapped.
12005            let selection_range = start_row..end_row;
12006            if rewrapped_row_ranges
12007                .iter()
12008                .any(|range| range.overlaps(&selection_range))
12009            {
12010                continue;
12011            }
12012
12013            let tab_size = language_settings.tab_size;
12014
12015            let (line_prefix, inside_comment) = match &comment_prefix {
12016                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12017                    (Some(prefix.as_str()), true)
12018                }
12019                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12020                    (Some(prefix.as_ref()), true)
12021                }
12022                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12023                    start: _,
12024                    end: _,
12025                    prefix,
12026                    tab_size,
12027                })) => {
12028                    indent_size.len += tab_size;
12029                    (Some(prefix.as_ref()), true)
12030                }
12031                None => (None, false),
12032            };
12033            let indent_prefix = indent_size.chars().collect::<String>();
12034            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12035
12036            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12037                RewrapBehavior::InComments => inside_comment,
12038                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12039                RewrapBehavior::Anywhere => true,
12040            };
12041
12042            let should_rewrap = options.override_language_settings
12043                || allow_rewrap_based_on_language
12044                || self.hard_wrap.is_some();
12045            if !should_rewrap {
12046                continue;
12047            }
12048
12049            if from_empty_selection {
12050                'expand_upwards: while start_row > 0 {
12051                    let prev_row = start_row - 1;
12052                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12053                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12054                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12055                    {
12056                        start_row = prev_row;
12057                    } else {
12058                        break 'expand_upwards;
12059                    }
12060                }
12061
12062                'expand_downwards: while end_row < buffer.max_point().row {
12063                    let next_row = end_row + 1;
12064                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12065                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12066                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12067                    {
12068                        end_row = next_row;
12069                    } else {
12070                        break 'expand_downwards;
12071                    }
12072                }
12073            }
12074
12075            let start = Point::new(start_row, 0);
12076            let start_offset = start.to_offset(&buffer);
12077            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12078            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12079            let mut first_line_delimiter = None;
12080            let mut last_line_delimiter = None;
12081            let Some(lines_without_prefixes) = selection_text
12082                .lines()
12083                .enumerate()
12084                .map(|(ix, line)| {
12085                    let line_trimmed = line.trim_start();
12086                    if rewrap_prefix.is_some() && ix > 0 {
12087                        Ok(line_trimmed)
12088                    } else if let Some(
12089                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12090                            start,
12091                            prefix,
12092                            end,
12093                            tab_size,
12094                        })
12095                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12096                            start,
12097                            prefix,
12098                            end,
12099                            tab_size,
12100                        }),
12101                    ) = &comment_prefix
12102                    {
12103                        let line_trimmed = line_trimmed
12104                            .strip_prefix(start.as_ref())
12105                            .map(|s| {
12106                                let mut indent_size = indent_size;
12107                                indent_size.len -= tab_size;
12108                                let indent_prefix: String = indent_size.chars().collect();
12109                                first_line_delimiter = Some((indent_prefix, start));
12110                                s.trim_start()
12111                            })
12112                            .unwrap_or(line_trimmed);
12113                        let line_trimmed = line_trimmed
12114                            .strip_suffix(end.as_ref())
12115                            .map(|s| {
12116                                last_line_delimiter = Some(end);
12117                                s.trim_end()
12118                            })
12119                            .unwrap_or(line_trimmed);
12120                        let line_trimmed = line_trimmed
12121                            .strip_prefix(prefix.as_ref())
12122                            .unwrap_or(line_trimmed);
12123                        Ok(line_trimmed)
12124                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12125                        line_trimmed.strip_prefix(prefix).with_context(|| {
12126                            format!("line did not start with prefix {prefix:?}: {line:?}")
12127                        })
12128                    } else {
12129                        line_trimmed
12130                            .strip_prefix(&line_prefix.trim_start())
12131                            .with_context(|| {
12132                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12133                            })
12134                    }
12135                })
12136                .collect::<Result<Vec<_>, _>>()
12137                .log_err()
12138            else {
12139                continue;
12140            };
12141
12142            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12143                buffer
12144                    .language_settings_at(Point::new(start_row, 0), cx)
12145                    .preferred_line_length as usize
12146            });
12147
12148            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12149                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12150            } else {
12151                line_prefix.clone()
12152            };
12153
12154            let wrapped_text = {
12155                let mut wrapped_text = wrap_with_prefix(
12156                    line_prefix,
12157                    subsequent_lines_prefix,
12158                    lines_without_prefixes.join("\n"),
12159                    wrap_column,
12160                    tab_size,
12161                    options.preserve_existing_whitespace,
12162                );
12163
12164                if let Some((indent, delimiter)) = first_line_delimiter {
12165                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12166                }
12167                if let Some(last_line) = last_line_delimiter {
12168                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12169                }
12170
12171                wrapped_text
12172            };
12173
12174            // TODO: should always use char-based diff while still supporting cursor behavior that
12175            // matches vim.
12176            let mut diff_options = DiffOptions::default();
12177            if options.override_language_settings {
12178                diff_options.max_word_diff_len = 0;
12179                diff_options.max_word_diff_line_count = 0;
12180            } else {
12181                diff_options.max_word_diff_len = usize::MAX;
12182                diff_options.max_word_diff_line_count = usize::MAX;
12183            }
12184
12185            for (old_range, new_text) in
12186                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12187            {
12188                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12189                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12190                edits.push((edit_start..edit_end, new_text));
12191            }
12192
12193            rewrapped_row_ranges.push(start_row..=end_row);
12194        }
12195
12196        self.buffer
12197            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12198    }
12199
12200    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12201        let mut text = String::new();
12202        let buffer = self.buffer.read(cx).snapshot(cx);
12203        let mut selections = self.selections.all::<Point>(cx);
12204        let mut clipboard_selections = Vec::with_capacity(selections.len());
12205        {
12206            let max_point = buffer.max_point();
12207            let mut is_first = true;
12208            for selection in &mut selections {
12209                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12210                if is_entire_line {
12211                    selection.start = Point::new(selection.start.row, 0);
12212                    if !selection.is_empty() && selection.end.column == 0 {
12213                        selection.end = cmp::min(max_point, selection.end);
12214                    } else {
12215                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12216                    }
12217                    selection.goal = SelectionGoal::None;
12218                }
12219                if is_first {
12220                    is_first = false;
12221                } else {
12222                    text += "\n";
12223                }
12224                let mut len = 0;
12225                for chunk in buffer.text_for_range(selection.start..selection.end) {
12226                    text.push_str(chunk);
12227                    len += chunk.len();
12228                }
12229                clipboard_selections.push(ClipboardSelection {
12230                    len,
12231                    is_entire_line,
12232                    first_line_indent: buffer
12233                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12234                        .len,
12235                });
12236            }
12237        }
12238
12239        self.transact(window, cx, |this, window, cx| {
12240            this.change_selections(Default::default(), window, cx, |s| {
12241                s.select(selections);
12242            });
12243            this.insert("", window, cx);
12244        });
12245        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12246    }
12247
12248    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12249        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12250        let item = self.cut_common(window, cx);
12251        cx.write_to_clipboard(item);
12252    }
12253
12254    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12255        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12256        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12257            s.move_with(|snapshot, sel| {
12258                if sel.is_empty() {
12259                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12260                }
12261            });
12262        });
12263        let item = self.cut_common(window, cx);
12264        cx.set_global(KillRing(item))
12265    }
12266
12267    pub fn kill_ring_yank(
12268        &mut self,
12269        _: &KillRingYank,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12274        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12275            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12276                (kill_ring.text().to_string(), kill_ring.metadata_json())
12277            } else {
12278                return;
12279            }
12280        } else {
12281            return;
12282        };
12283        self.do_paste(&text, metadata, false, window, cx);
12284    }
12285
12286    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12287        self.do_copy(true, cx);
12288    }
12289
12290    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12291        self.do_copy(false, cx);
12292    }
12293
12294    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12295        let selections = self.selections.all::<Point>(cx);
12296        let buffer = self.buffer.read(cx).read(cx);
12297        let mut text = String::new();
12298
12299        let mut clipboard_selections = Vec::with_capacity(selections.len());
12300        {
12301            let max_point = buffer.max_point();
12302            let mut is_first = true;
12303            for selection in &selections {
12304                let mut start = selection.start;
12305                let mut end = selection.end;
12306                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12307                if is_entire_line {
12308                    start = Point::new(start.row, 0);
12309                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12310                }
12311
12312                let mut trimmed_selections = Vec::new();
12313                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12314                    let row = MultiBufferRow(start.row);
12315                    let first_indent = buffer.indent_size_for_line(row);
12316                    if first_indent.len == 0 || start.column > first_indent.len {
12317                        trimmed_selections.push(start..end);
12318                    } else {
12319                        trimmed_selections.push(
12320                            Point::new(row.0, first_indent.len)
12321                                ..Point::new(row.0, buffer.line_len(row)),
12322                        );
12323                        for row in start.row + 1..=end.row {
12324                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12325                            if row == end.row {
12326                                line_len = end.column;
12327                            }
12328                            if line_len == 0 {
12329                                trimmed_selections
12330                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12331                                continue;
12332                            }
12333                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12334                            if row_indent_size.len >= first_indent.len {
12335                                trimmed_selections.push(
12336                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12337                                );
12338                            } else {
12339                                trimmed_selections.clear();
12340                                trimmed_selections.push(start..end);
12341                                break;
12342                            }
12343                        }
12344                    }
12345                } else {
12346                    trimmed_selections.push(start..end);
12347                }
12348
12349                for trimmed_range in trimmed_selections {
12350                    if is_first {
12351                        is_first = false;
12352                    } else {
12353                        text += "\n";
12354                    }
12355                    let mut len = 0;
12356                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12357                        text.push_str(chunk);
12358                        len += chunk.len();
12359                    }
12360                    clipboard_selections.push(ClipboardSelection {
12361                        len,
12362                        is_entire_line,
12363                        first_line_indent: buffer
12364                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12365                            .len,
12366                    });
12367                }
12368            }
12369        }
12370
12371        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12372            text,
12373            clipboard_selections,
12374        ));
12375    }
12376
12377    pub fn do_paste(
12378        &mut self,
12379        text: &String,
12380        clipboard_selections: Option<Vec<ClipboardSelection>>,
12381        handle_entire_lines: bool,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        if self.read_only(cx) {
12386            return;
12387        }
12388
12389        let clipboard_text = Cow::Borrowed(text);
12390
12391        self.transact(window, cx, |this, window, cx| {
12392            let had_active_edit_prediction = this.has_active_edit_prediction();
12393
12394            if let Some(mut clipboard_selections) = clipboard_selections {
12395                let old_selections = this.selections.all::<usize>(cx);
12396                let all_selections_were_entire_line =
12397                    clipboard_selections.iter().all(|s| s.is_entire_line);
12398                let first_selection_indent_column =
12399                    clipboard_selections.first().map(|s| s.first_line_indent);
12400                if clipboard_selections.len() != old_selections.len() {
12401                    clipboard_selections.drain(..);
12402                }
12403                let cursor_offset = this.selections.last::<usize>(cx).head();
12404                let mut auto_indent_on_paste = true;
12405
12406                this.buffer.update(cx, |buffer, cx| {
12407                    let snapshot = buffer.read(cx);
12408                    auto_indent_on_paste = snapshot
12409                        .language_settings_at(cursor_offset, cx)
12410                        .auto_indent_on_paste;
12411
12412                    let mut start_offset = 0;
12413                    let mut edits = Vec::new();
12414                    let mut original_indent_columns = Vec::new();
12415                    for (ix, selection) in old_selections.iter().enumerate() {
12416                        let to_insert;
12417                        let entire_line;
12418                        let original_indent_column;
12419                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12420                            let end_offset = start_offset + clipboard_selection.len;
12421                            to_insert = &clipboard_text[start_offset..end_offset];
12422                            entire_line = clipboard_selection.is_entire_line;
12423                            start_offset = end_offset + 1;
12424                            original_indent_column = Some(clipboard_selection.first_line_indent);
12425                        } else {
12426                            to_insert = clipboard_text.as_str();
12427                            entire_line = all_selections_were_entire_line;
12428                            original_indent_column = first_selection_indent_column
12429                        }
12430
12431                        // If the corresponding selection was empty when this slice of the
12432                        // clipboard text was written, then the entire line containing the
12433                        // selection was copied. If this selection is also currently empty,
12434                        // then paste the line before the current line of the buffer.
12435                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12436                            let column = selection.start.to_point(&snapshot).column as usize;
12437                            let line_start = selection.start - column;
12438                            line_start..line_start
12439                        } else {
12440                            selection.range()
12441                        };
12442
12443                        edits.push((range, to_insert));
12444                        original_indent_columns.push(original_indent_column);
12445                    }
12446                    drop(snapshot);
12447
12448                    buffer.edit(
12449                        edits,
12450                        if auto_indent_on_paste {
12451                            Some(AutoindentMode::Block {
12452                                original_indent_columns,
12453                            })
12454                        } else {
12455                            None
12456                        },
12457                        cx,
12458                    );
12459                });
12460
12461                let selections = this.selections.all::<usize>(cx);
12462                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12463            } else {
12464                this.insert(&clipboard_text, window, cx);
12465            }
12466
12467            let trigger_in_words =
12468                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12469
12470            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12471        });
12472    }
12473
12474    pub fn diff_clipboard_with_selection(
12475        &mut self,
12476        _: &DiffClipboardWithSelection,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        let selections = self.selections.all::<usize>(cx);
12481
12482        if selections.is_empty() {
12483            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12484            return;
12485        };
12486
12487        let clipboard_text = match cx.read_from_clipboard() {
12488            Some(item) => match item.entries().first() {
12489                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12490                _ => None,
12491            },
12492            None => None,
12493        };
12494
12495        let Some(clipboard_text) = clipboard_text else {
12496            log::warn!("Clipboard doesn't contain text.");
12497            return;
12498        };
12499
12500        window.dispatch_action(
12501            Box::new(DiffClipboardWithSelectionData {
12502                clipboard_text,
12503                editor: cx.entity(),
12504            }),
12505            cx,
12506        );
12507    }
12508
12509    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12510        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12511        if let Some(item) = cx.read_from_clipboard() {
12512            let entries = item.entries();
12513
12514            match entries.first() {
12515                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12516                // of all the pasted entries.
12517                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12518                    .do_paste(
12519                        clipboard_string.text(),
12520                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12521                        true,
12522                        window,
12523                        cx,
12524                    ),
12525                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12526            }
12527        }
12528    }
12529
12530    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12531        if self.read_only(cx) {
12532            return;
12533        }
12534
12535        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12536
12537        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12538            if let Some((selections, _)) =
12539                self.selection_history.transaction(transaction_id).cloned()
12540            {
12541                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12542                    s.select_anchors(selections.to_vec());
12543                });
12544            } else {
12545                log::error!(
12546                    "No entry in selection_history found for undo. \
12547                     This may correspond to a bug where undo does not update the selection. \
12548                     If this is occurring, please add details to \
12549                     https://github.com/zed-industries/zed/issues/22692"
12550                );
12551            }
12552            self.request_autoscroll(Autoscroll::fit(), cx);
12553            self.unmark_text(window, cx);
12554            self.refresh_edit_prediction(true, false, window, cx);
12555            cx.emit(EditorEvent::Edited { transaction_id });
12556            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12557        }
12558    }
12559
12560    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12561        if self.read_only(cx) {
12562            return;
12563        }
12564
12565        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12566
12567        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12568            if let Some((_, Some(selections))) =
12569                self.selection_history.transaction(transaction_id).cloned()
12570            {
12571                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12572                    s.select_anchors(selections.to_vec());
12573                });
12574            } else {
12575                log::error!(
12576                    "No entry in selection_history found for redo. \
12577                     This may correspond to a bug where undo does not update the selection. \
12578                     If this is occurring, please add details to \
12579                     https://github.com/zed-industries/zed/issues/22692"
12580                );
12581            }
12582            self.request_autoscroll(Autoscroll::fit(), cx);
12583            self.unmark_text(window, cx);
12584            self.refresh_edit_prediction(true, false, window, cx);
12585            cx.emit(EditorEvent::Edited { transaction_id });
12586        }
12587    }
12588
12589    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12590        self.buffer
12591            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12592    }
12593
12594    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12595        self.buffer
12596            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12597    }
12598
12599    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12601        self.change_selections(Default::default(), window, cx, |s| {
12602            s.move_with(|map, selection| {
12603                let cursor = if selection.is_empty() {
12604                    movement::left(map, selection.start)
12605                } else {
12606                    selection.start
12607                };
12608                selection.collapse_to(cursor, SelectionGoal::None);
12609            });
12610        })
12611    }
12612
12613    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12614        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12615        self.change_selections(Default::default(), window, cx, |s| {
12616            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12617        })
12618    }
12619
12620    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12622        self.change_selections(Default::default(), window, cx, |s| {
12623            s.move_with(|map, selection| {
12624                let cursor = if selection.is_empty() {
12625                    movement::right(map, selection.end)
12626                } else {
12627                    selection.end
12628                };
12629                selection.collapse_to(cursor, SelectionGoal::None)
12630            });
12631        })
12632    }
12633
12634    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12636        self.change_selections(Default::default(), window, cx, |s| {
12637            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12638        })
12639    }
12640
12641    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12642        if self.take_rename(true, window, cx).is_some() {
12643            return;
12644        }
12645
12646        if self.mode.is_single_line() {
12647            cx.propagate();
12648            return;
12649        }
12650
12651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12652
12653        let text_layout_details = &self.text_layout_details(window);
12654        let selection_count = self.selections.count();
12655        let first_selection = self.selections.first_anchor();
12656
12657        self.change_selections(Default::default(), window, cx, |s| {
12658            s.move_with(|map, selection| {
12659                if !selection.is_empty() {
12660                    selection.goal = SelectionGoal::None;
12661                }
12662                let (cursor, goal) = movement::up(
12663                    map,
12664                    selection.start,
12665                    selection.goal,
12666                    false,
12667                    text_layout_details,
12668                );
12669                selection.collapse_to(cursor, goal);
12670            });
12671        });
12672
12673        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12674        {
12675            cx.propagate();
12676        }
12677    }
12678
12679    pub fn move_up_by_lines(
12680        &mut self,
12681        action: &MoveUpByLines,
12682        window: &mut Window,
12683        cx: &mut Context<Self>,
12684    ) {
12685        if self.take_rename(true, window, cx).is_some() {
12686            return;
12687        }
12688
12689        if self.mode.is_single_line() {
12690            cx.propagate();
12691            return;
12692        }
12693
12694        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12695
12696        let text_layout_details = &self.text_layout_details(window);
12697
12698        self.change_selections(Default::default(), window, cx, |s| {
12699            s.move_with(|map, selection| {
12700                if !selection.is_empty() {
12701                    selection.goal = SelectionGoal::None;
12702                }
12703                let (cursor, goal) = movement::up_by_rows(
12704                    map,
12705                    selection.start,
12706                    action.lines,
12707                    selection.goal,
12708                    false,
12709                    text_layout_details,
12710                );
12711                selection.collapse_to(cursor, goal);
12712            });
12713        })
12714    }
12715
12716    pub fn move_down_by_lines(
12717        &mut self,
12718        action: &MoveDownByLines,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        if self.take_rename(true, window, cx).is_some() {
12723            return;
12724        }
12725
12726        if self.mode.is_single_line() {
12727            cx.propagate();
12728            return;
12729        }
12730
12731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12732
12733        let text_layout_details = &self.text_layout_details(window);
12734
12735        self.change_selections(Default::default(), window, cx, |s| {
12736            s.move_with(|map, selection| {
12737                if !selection.is_empty() {
12738                    selection.goal = SelectionGoal::None;
12739                }
12740                let (cursor, goal) = movement::down_by_rows(
12741                    map,
12742                    selection.start,
12743                    action.lines,
12744                    selection.goal,
12745                    false,
12746                    text_layout_details,
12747                );
12748                selection.collapse_to(cursor, goal);
12749            });
12750        })
12751    }
12752
12753    pub fn select_down_by_lines(
12754        &mut self,
12755        action: &SelectDownByLines,
12756        window: &mut Window,
12757        cx: &mut Context<Self>,
12758    ) {
12759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12760        let text_layout_details = &self.text_layout_details(window);
12761        self.change_selections(Default::default(), window, cx, |s| {
12762            s.move_heads_with(|map, head, goal| {
12763                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12764            })
12765        })
12766    }
12767
12768    pub fn select_up_by_lines(
12769        &mut self,
12770        action: &SelectUpByLines,
12771        window: &mut Window,
12772        cx: &mut Context<Self>,
12773    ) {
12774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12775        let text_layout_details = &self.text_layout_details(window);
12776        self.change_selections(Default::default(), window, cx, |s| {
12777            s.move_heads_with(|map, head, goal| {
12778                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12779            })
12780        })
12781    }
12782
12783    pub fn select_page_up(
12784        &mut self,
12785        _: &SelectPageUp,
12786        window: &mut Window,
12787        cx: &mut Context<Self>,
12788    ) {
12789        let Some(row_count) = self.visible_row_count() else {
12790            return;
12791        };
12792
12793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12794
12795        let text_layout_details = &self.text_layout_details(window);
12796
12797        self.change_selections(Default::default(), window, cx, |s| {
12798            s.move_heads_with(|map, head, goal| {
12799                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12800            })
12801        })
12802    }
12803
12804    pub fn move_page_up(
12805        &mut self,
12806        action: &MovePageUp,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) {
12810        if self.take_rename(true, window, cx).is_some() {
12811            return;
12812        }
12813
12814        if self
12815            .context_menu
12816            .borrow_mut()
12817            .as_mut()
12818            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12819            .unwrap_or(false)
12820        {
12821            return;
12822        }
12823
12824        if matches!(self.mode, EditorMode::SingleLine) {
12825            cx.propagate();
12826            return;
12827        }
12828
12829        let Some(row_count) = self.visible_row_count() else {
12830            return;
12831        };
12832
12833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12834
12835        let effects = if action.center_cursor {
12836            SelectionEffects::scroll(Autoscroll::center())
12837        } else {
12838            SelectionEffects::default()
12839        };
12840
12841        let text_layout_details = &self.text_layout_details(window);
12842
12843        self.change_selections(effects, window, cx, |s| {
12844            s.move_with(|map, selection| {
12845                if !selection.is_empty() {
12846                    selection.goal = SelectionGoal::None;
12847                }
12848                let (cursor, goal) = movement::up_by_rows(
12849                    map,
12850                    selection.end,
12851                    row_count,
12852                    selection.goal,
12853                    false,
12854                    text_layout_details,
12855                );
12856                selection.collapse_to(cursor, goal);
12857            });
12858        });
12859    }
12860
12861    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12863        let text_layout_details = &self.text_layout_details(window);
12864        self.change_selections(Default::default(), window, cx, |s| {
12865            s.move_heads_with(|map, head, goal| {
12866                movement::up(map, head, goal, false, text_layout_details)
12867            })
12868        })
12869    }
12870
12871    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12872        self.take_rename(true, window, cx);
12873
12874        if self.mode.is_single_line() {
12875            cx.propagate();
12876            return;
12877        }
12878
12879        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12880
12881        let text_layout_details = &self.text_layout_details(window);
12882        let selection_count = self.selections.count();
12883        let first_selection = self.selections.first_anchor();
12884
12885        self.change_selections(Default::default(), window, cx, |s| {
12886            s.move_with(|map, selection| {
12887                if !selection.is_empty() {
12888                    selection.goal = SelectionGoal::None;
12889                }
12890                let (cursor, goal) = movement::down(
12891                    map,
12892                    selection.end,
12893                    selection.goal,
12894                    false,
12895                    text_layout_details,
12896                );
12897                selection.collapse_to(cursor, goal);
12898            });
12899        });
12900
12901        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12902        {
12903            cx.propagate();
12904        }
12905    }
12906
12907    pub fn select_page_down(
12908        &mut self,
12909        _: &SelectPageDown,
12910        window: &mut Window,
12911        cx: &mut Context<Self>,
12912    ) {
12913        let Some(row_count) = self.visible_row_count() else {
12914            return;
12915        };
12916
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918
12919        let text_layout_details = &self.text_layout_details(window);
12920
12921        self.change_selections(Default::default(), window, cx, |s| {
12922            s.move_heads_with(|map, head, goal| {
12923                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12924            })
12925        })
12926    }
12927
12928    pub fn move_page_down(
12929        &mut self,
12930        action: &MovePageDown,
12931        window: &mut Window,
12932        cx: &mut Context<Self>,
12933    ) {
12934        if self.take_rename(true, window, cx).is_some() {
12935            return;
12936        }
12937
12938        if self
12939            .context_menu
12940            .borrow_mut()
12941            .as_mut()
12942            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12943            .unwrap_or(false)
12944        {
12945            return;
12946        }
12947
12948        if matches!(self.mode, EditorMode::SingleLine) {
12949            cx.propagate();
12950            return;
12951        }
12952
12953        let Some(row_count) = self.visible_row_count() else {
12954            return;
12955        };
12956
12957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12958
12959        let effects = if action.center_cursor {
12960            SelectionEffects::scroll(Autoscroll::center())
12961        } else {
12962            SelectionEffects::default()
12963        };
12964
12965        let text_layout_details = &self.text_layout_details(window);
12966        self.change_selections(effects, window, cx, |s| {
12967            s.move_with(|map, selection| {
12968                if !selection.is_empty() {
12969                    selection.goal = SelectionGoal::None;
12970                }
12971                let (cursor, goal) = movement::down_by_rows(
12972                    map,
12973                    selection.end,
12974                    row_count,
12975                    selection.goal,
12976                    false,
12977                    text_layout_details,
12978                );
12979                selection.collapse_to(cursor, goal);
12980            });
12981        });
12982    }
12983
12984    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12986        let text_layout_details = &self.text_layout_details(window);
12987        self.change_selections(Default::default(), window, cx, |s| {
12988            s.move_heads_with(|map, head, goal| {
12989                movement::down(map, head, goal, false, text_layout_details)
12990            })
12991        });
12992    }
12993
12994    pub fn context_menu_first(
12995        &mut self,
12996        _: &ContextMenuFirst,
12997        window: &mut Window,
12998        cx: &mut Context<Self>,
12999    ) {
13000        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13001            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13002        }
13003    }
13004
13005    pub fn context_menu_prev(
13006        &mut self,
13007        _: &ContextMenuPrevious,
13008        window: &mut Window,
13009        cx: &mut Context<Self>,
13010    ) {
13011        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13012            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13013        }
13014    }
13015
13016    pub fn context_menu_next(
13017        &mut self,
13018        _: &ContextMenuNext,
13019        window: &mut Window,
13020        cx: &mut Context<Self>,
13021    ) {
13022        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13023            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13024        }
13025    }
13026
13027    pub fn context_menu_last(
13028        &mut self,
13029        _: &ContextMenuLast,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13034            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13035        }
13036    }
13037
13038    pub fn signature_help_prev(
13039        &mut self,
13040        _: &SignatureHelpPrevious,
13041        _: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        if let Some(popover) = self.signature_help_state.popover_mut() {
13045            if popover.current_signature == 0 {
13046                popover.current_signature = popover.signatures.len() - 1;
13047            } else {
13048                popover.current_signature -= 1;
13049            }
13050            cx.notify();
13051        }
13052    }
13053
13054    pub fn signature_help_next(
13055        &mut self,
13056        _: &SignatureHelpNext,
13057        _: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if let Some(popover) = self.signature_help_state.popover_mut() {
13061            if popover.current_signature + 1 == popover.signatures.len() {
13062                popover.current_signature = 0;
13063            } else {
13064                popover.current_signature += 1;
13065            }
13066            cx.notify();
13067        }
13068    }
13069
13070    pub fn move_to_previous_word_start(
13071        &mut self,
13072        _: &MoveToPreviousWordStart,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13077        self.change_selections(Default::default(), window, cx, |s| {
13078            s.move_cursors_with(|map, head, _| {
13079                (
13080                    movement::previous_word_start(map, head),
13081                    SelectionGoal::None,
13082                )
13083            });
13084        })
13085    }
13086
13087    pub fn move_to_previous_subword_start(
13088        &mut self,
13089        _: &MoveToPreviousSubwordStart,
13090        window: &mut Window,
13091        cx: &mut Context<Self>,
13092    ) {
13093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13094        self.change_selections(Default::default(), window, cx, |s| {
13095            s.move_cursors_with(|map, head, _| {
13096                (
13097                    movement::previous_subword_start(map, head),
13098                    SelectionGoal::None,
13099                )
13100            });
13101        })
13102    }
13103
13104    pub fn select_to_previous_word_start(
13105        &mut self,
13106        _: &SelectToPreviousWordStart,
13107        window: &mut Window,
13108        cx: &mut Context<Self>,
13109    ) {
13110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13111        self.change_selections(Default::default(), window, cx, |s| {
13112            s.move_heads_with(|map, head, _| {
13113                (
13114                    movement::previous_word_start(map, head),
13115                    SelectionGoal::None,
13116                )
13117            });
13118        })
13119    }
13120
13121    pub fn select_to_previous_subword_start(
13122        &mut self,
13123        _: &SelectToPreviousSubwordStart,
13124        window: &mut Window,
13125        cx: &mut Context<Self>,
13126    ) {
13127        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13128        self.change_selections(Default::default(), window, cx, |s| {
13129            s.move_heads_with(|map, head, _| {
13130                (
13131                    movement::previous_subword_start(map, head),
13132                    SelectionGoal::None,
13133                )
13134            });
13135        })
13136    }
13137
13138    pub fn delete_to_previous_word_start(
13139        &mut self,
13140        action: &DeleteToPreviousWordStart,
13141        window: &mut Window,
13142        cx: &mut Context<Self>,
13143    ) {
13144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13145        self.transact(window, cx, |this, window, cx| {
13146            this.select_autoclose_pair(window, cx);
13147            this.change_selections(Default::default(), window, cx, |s| {
13148                s.move_with(|map, selection| {
13149                    if selection.is_empty() {
13150                        let cursor = if action.ignore_newlines {
13151                            movement::previous_word_start(map, selection.head())
13152                        } else {
13153                            movement::previous_word_start_or_newline(map, selection.head())
13154                        };
13155                        selection.set_head(cursor, SelectionGoal::None);
13156                    }
13157                });
13158            });
13159            this.insert("", window, cx);
13160        });
13161    }
13162
13163    pub fn delete_to_previous_subword_start(
13164        &mut self,
13165        _: &DeleteToPreviousSubwordStart,
13166        window: &mut Window,
13167        cx: &mut Context<Self>,
13168    ) {
13169        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13170        self.transact(window, cx, |this, window, cx| {
13171            this.select_autoclose_pair(window, cx);
13172            this.change_selections(Default::default(), window, cx, |s| {
13173                s.move_with(|map, selection| {
13174                    if selection.is_empty() {
13175                        let cursor = movement::previous_subword_start(map, selection.head());
13176                        selection.set_head(cursor, SelectionGoal::None);
13177                    }
13178                });
13179            });
13180            this.insert("", window, cx);
13181        });
13182    }
13183
13184    pub fn move_to_next_word_end(
13185        &mut self,
13186        _: &MoveToNextWordEnd,
13187        window: &mut Window,
13188        cx: &mut Context<Self>,
13189    ) {
13190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13191        self.change_selections(Default::default(), window, cx, |s| {
13192            s.move_cursors_with(|map, head, _| {
13193                (movement::next_word_end(map, head), SelectionGoal::None)
13194            });
13195        })
13196    }
13197
13198    pub fn move_to_next_subword_end(
13199        &mut self,
13200        _: &MoveToNextSubwordEnd,
13201        window: &mut Window,
13202        cx: &mut Context<Self>,
13203    ) {
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205        self.change_selections(Default::default(), window, cx, |s| {
13206            s.move_cursors_with(|map, head, _| {
13207                (movement::next_subword_end(map, head), SelectionGoal::None)
13208            });
13209        })
13210    }
13211
13212    pub fn select_to_next_word_end(
13213        &mut self,
13214        _: &SelectToNextWordEnd,
13215        window: &mut Window,
13216        cx: &mut Context<Self>,
13217    ) {
13218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13219        self.change_selections(Default::default(), window, cx, |s| {
13220            s.move_heads_with(|map, head, _| {
13221                (movement::next_word_end(map, head), SelectionGoal::None)
13222            });
13223        })
13224    }
13225
13226    pub fn select_to_next_subword_end(
13227        &mut self,
13228        _: &SelectToNextSubwordEnd,
13229        window: &mut Window,
13230        cx: &mut Context<Self>,
13231    ) {
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_heads_with(|map, head, _| {
13235                (movement::next_subword_end(map, head), SelectionGoal::None)
13236            });
13237        })
13238    }
13239
13240    pub fn delete_to_next_word_end(
13241        &mut self,
13242        action: &DeleteToNextWordEnd,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13247        self.transact(window, cx, |this, window, cx| {
13248            this.change_selections(Default::default(), window, cx, |s| {
13249                s.move_with(|map, selection| {
13250                    if selection.is_empty() {
13251                        let cursor = if action.ignore_newlines {
13252                            movement::next_word_end(map, selection.head())
13253                        } else {
13254                            movement::next_word_end_or_newline(map, selection.head())
13255                        };
13256                        selection.set_head(cursor, SelectionGoal::None);
13257                    }
13258                });
13259            });
13260            this.insert("", window, cx);
13261        });
13262    }
13263
13264    pub fn delete_to_next_subword_end(
13265        &mut self,
13266        _: &DeleteToNextSubwordEnd,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13271        self.transact(window, cx, |this, window, cx| {
13272            this.change_selections(Default::default(), window, cx, |s| {
13273                s.move_with(|map, selection| {
13274                    if selection.is_empty() {
13275                        let cursor = movement::next_subword_end(map, selection.head());
13276                        selection.set_head(cursor, SelectionGoal::None);
13277                    }
13278                });
13279            });
13280            this.insert("", window, cx);
13281        });
13282    }
13283
13284    pub fn move_to_beginning_of_line(
13285        &mut self,
13286        action: &MoveToBeginningOfLine,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13291        self.change_selections(Default::default(), window, cx, |s| {
13292            s.move_cursors_with(|map, head, _| {
13293                (
13294                    movement::indented_line_beginning(
13295                        map,
13296                        head,
13297                        action.stop_at_soft_wraps,
13298                        action.stop_at_indent,
13299                    ),
13300                    SelectionGoal::None,
13301                )
13302            });
13303        })
13304    }
13305
13306    pub fn select_to_beginning_of_line(
13307        &mut self,
13308        action: &SelectToBeginningOfLine,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13313        self.change_selections(Default::default(), window, cx, |s| {
13314            s.move_heads_with(|map, head, _| {
13315                (
13316                    movement::indented_line_beginning(
13317                        map,
13318                        head,
13319                        action.stop_at_soft_wraps,
13320                        action.stop_at_indent,
13321                    ),
13322                    SelectionGoal::None,
13323                )
13324            });
13325        });
13326    }
13327
13328    pub fn delete_to_beginning_of_line(
13329        &mut self,
13330        action: &DeleteToBeginningOfLine,
13331        window: &mut Window,
13332        cx: &mut Context<Self>,
13333    ) {
13334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13335        self.transact(window, cx, |this, window, cx| {
13336            this.change_selections(Default::default(), window, cx, |s| {
13337                s.move_with(|_, selection| {
13338                    selection.reversed = true;
13339                });
13340            });
13341
13342            this.select_to_beginning_of_line(
13343                &SelectToBeginningOfLine {
13344                    stop_at_soft_wraps: false,
13345                    stop_at_indent: action.stop_at_indent,
13346                },
13347                window,
13348                cx,
13349            );
13350            this.backspace(&Backspace, window, cx);
13351        });
13352    }
13353
13354    pub fn move_to_end_of_line(
13355        &mut self,
13356        action: &MoveToEndOfLine,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13361        self.change_selections(Default::default(), window, cx, |s| {
13362            s.move_cursors_with(|map, head, _| {
13363                (
13364                    movement::line_end(map, head, action.stop_at_soft_wraps),
13365                    SelectionGoal::None,
13366                )
13367            });
13368        })
13369    }
13370
13371    pub fn select_to_end_of_line(
13372        &mut self,
13373        action: &SelectToEndOfLine,
13374        window: &mut Window,
13375        cx: &mut Context<Self>,
13376    ) {
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (
13381                    movement::line_end(map, head, action.stop_at_soft_wraps),
13382                    SelectionGoal::None,
13383                )
13384            });
13385        })
13386    }
13387
13388    pub fn delete_to_end_of_line(
13389        &mut self,
13390        _: &DeleteToEndOfLine,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13395        self.transact(window, cx, |this, window, cx| {
13396            this.select_to_end_of_line(
13397                &SelectToEndOfLine {
13398                    stop_at_soft_wraps: false,
13399                },
13400                window,
13401                cx,
13402            );
13403            this.delete(&Delete, window, cx);
13404        });
13405    }
13406
13407    pub fn cut_to_end_of_line(
13408        &mut self,
13409        _: &CutToEndOfLine,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13414        self.transact(window, cx, |this, window, cx| {
13415            this.select_to_end_of_line(
13416                &SelectToEndOfLine {
13417                    stop_at_soft_wraps: false,
13418                },
13419                window,
13420                cx,
13421            );
13422            this.cut(&Cut, window, cx);
13423        });
13424    }
13425
13426    pub fn move_to_start_of_paragraph(
13427        &mut self,
13428        _: &MoveToStartOfParagraph,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        if matches!(self.mode, EditorMode::SingleLine) {
13433            cx.propagate();
13434            return;
13435        }
13436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13437        self.change_selections(Default::default(), window, cx, |s| {
13438            s.move_with(|map, selection| {
13439                selection.collapse_to(
13440                    movement::start_of_paragraph(map, selection.head(), 1),
13441                    SelectionGoal::None,
13442                )
13443            });
13444        })
13445    }
13446
13447    pub fn move_to_end_of_paragraph(
13448        &mut self,
13449        _: &MoveToEndOfParagraph,
13450        window: &mut Window,
13451        cx: &mut Context<Self>,
13452    ) {
13453        if matches!(self.mode, EditorMode::SingleLine) {
13454            cx.propagate();
13455            return;
13456        }
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_with(|map, selection| {
13460                selection.collapse_to(
13461                    movement::end_of_paragraph(map, selection.head(), 1),
13462                    SelectionGoal::None,
13463                )
13464            });
13465        })
13466    }
13467
13468    pub fn select_to_start_of_paragraph(
13469        &mut self,
13470        _: &SelectToStartOfParagraph,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        if matches!(self.mode, EditorMode::SingleLine) {
13475            cx.propagate();
13476            return;
13477        }
13478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13479        self.change_selections(Default::default(), window, cx, |s| {
13480            s.move_heads_with(|map, head, _| {
13481                (
13482                    movement::start_of_paragraph(map, head, 1),
13483                    SelectionGoal::None,
13484                )
13485            });
13486        })
13487    }
13488
13489    pub fn select_to_end_of_paragraph(
13490        &mut self,
13491        _: &SelectToEndOfParagraph,
13492        window: &mut Window,
13493        cx: &mut Context<Self>,
13494    ) {
13495        if matches!(self.mode, EditorMode::SingleLine) {
13496            cx.propagate();
13497            return;
13498        }
13499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13500        self.change_selections(Default::default(), window, cx, |s| {
13501            s.move_heads_with(|map, head, _| {
13502                (
13503                    movement::end_of_paragraph(map, head, 1),
13504                    SelectionGoal::None,
13505                )
13506            });
13507        })
13508    }
13509
13510    pub fn move_to_start_of_excerpt(
13511        &mut self,
13512        _: &MoveToStartOfExcerpt,
13513        window: &mut Window,
13514        cx: &mut Context<Self>,
13515    ) {
13516        if matches!(self.mode, EditorMode::SingleLine) {
13517            cx.propagate();
13518            return;
13519        }
13520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13521        self.change_selections(Default::default(), window, cx, |s| {
13522            s.move_with(|map, selection| {
13523                selection.collapse_to(
13524                    movement::start_of_excerpt(
13525                        map,
13526                        selection.head(),
13527                        workspace::searchable::Direction::Prev,
13528                    ),
13529                    SelectionGoal::None,
13530                )
13531            });
13532        })
13533    }
13534
13535    pub fn move_to_start_of_next_excerpt(
13536        &mut self,
13537        _: &MoveToStartOfNextExcerpt,
13538        window: &mut Window,
13539        cx: &mut Context<Self>,
13540    ) {
13541        if matches!(self.mode, EditorMode::SingleLine) {
13542            cx.propagate();
13543            return;
13544        }
13545
13546        self.change_selections(Default::default(), window, cx, |s| {
13547            s.move_with(|map, selection| {
13548                selection.collapse_to(
13549                    movement::start_of_excerpt(
13550                        map,
13551                        selection.head(),
13552                        workspace::searchable::Direction::Next,
13553                    ),
13554                    SelectionGoal::None,
13555                )
13556            });
13557        })
13558    }
13559
13560    pub fn move_to_end_of_excerpt(
13561        &mut self,
13562        _: &MoveToEndOfExcerpt,
13563        window: &mut Window,
13564        cx: &mut Context<Self>,
13565    ) {
13566        if matches!(self.mode, EditorMode::SingleLine) {
13567            cx.propagate();
13568            return;
13569        }
13570        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13571        self.change_selections(Default::default(), window, cx, |s| {
13572            s.move_with(|map, selection| {
13573                selection.collapse_to(
13574                    movement::end_of_excerpt(
13575                        map,
13576                        selection.head(),
13577                        workspace::searchable::Direction::Next,
13578                    ),
13579                    SelectionGoal::None,
13580                )
13581            });
13582        })
13583    }
13584
13585    pub fn move_to_end_of_previous_excerpt(
13586        &mut self,
13587        _: &MoveToEndOfPreviousExcerpt,
13588        window: &mut Window,
13589        cx: &mut Context<Self>,
13590    ) {
13591        if matches!(self.mode, EditorMode::SingleLine) {
13592            cx.propagate();
13593            return;
13594        }
13595        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13596        self.change_selections(Default::default(), window, cx, |s| {
13597            s.move_with(|map, selection| {
13598                selection.collapse_to(
13599                    movement::end_of_excerpt(
13600                        map,
13601                        selection.head(),
13602                        workspace::searchable::Direction::Prev,
13603                    ),
13604                    SelectionGoal::None,
13605                )
13606            });
13607        })
13608    }
13609
13610    pub fn select_to_start_of_excerpt(
13611        &mut self,
13612        _: &SelectToStartOfExcerpt,
13613        window: &mut Window,
13614        cx: &mut Context<Self>,
13615    ) {
13616        if matches!(self.mode, EditorMode::SingleLine) {
13617            cx.propagate();
13618            return;
13619        }
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        self.change_selections(Default::default(), window, cx, |s| {
13622            s.move_heads_with(|map, head, _| {
13623                (
13624                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13625                    SelectionGoal::None,
13626                )
13627            });
13628        })
13629    }
13630
13631    pub fn select_to_start_of_next_excerpt(
13632        &mut self,
13633        _: &SelectToStartOfNextExcerpt,
13634        window: &mut Window,
13635        cx: &mut Context<Self>,
13636    ) {
13637        if matches!(self.mode, EditorMode::SingleLine) {
13638            cx.propagate();
13639            return;
13640        }
13641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13642        self.change_selections(Default::default(), window, cx, |s| {
13643            s.move_heads_with(|map, head, _| {
13644                (
13645                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13646                    SelectionGoal::None,
13647                )
13648            });
13649        })
13650    }
13651
13652    pub fn select_to_end_of_excerpt(
13653        &mut self,
13654        _: &SelectToEndOfExcerpt,
13655        window: &mut Window,
13656        cx: &mut Context<Self>,
13657    ) {
13658        if matches!(self.mode, EditorMode::SingleLine) {
13659            cx.propagate();
13660            return;
13661        }
13662        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13663        self.change_selections(Default::default(), window, cx, |s| {
13664            s.move_heads_with(|map, head, _| {
13665                (
13666                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13667                    SelectionGoal::None,
13668                )
13669            });
13670        })
13671    }
13672
13673    pub fn select_to_end_of_previous_excerpt(
13674        &mut self,
13675        _: &SelectToEndOfPreviousExcerpt,
13676        window: &mut Window,
13677        cx: &mut Context<Self>,
13678    ) {
13679        if matches!(self.mode, EditorMode::SingleLine) {
13680            cx.propagate();
13681            return;
13682        }
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13684        self.change_selections(Default::default(), window, cx, |s| {
13685            s.move_heads_with(|map, head, _| {
13686                (
13687                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13688                    SelectionGoal::None,
13689                )
13690            });
13691        })
13692    }
13693
13694    pub fn move_to_beginning(
13695        &mut self,
13696        _: &MoveToBeginning,
13697        window: &mut Window,
13698        cx: &mut Context<Self>,
13699    ) {
13700        if matches!(self.mode, EditorMode::SingleLine) {
13701            cx.propagate();
13702            return;
13703        }
13704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13705        self.change_selections(Default::default(), window, cx, |s| {
13706            s.select_ranges(vec![0..0]);
13707        });
13708    }
13709
13710    pub fn select_to_beginning(
13711        &mut self,
13712        _: &SelectToBeginning,
13713        window: &mut Window,
13714        cx: &mut Context<Self>,
13715    ) {
13716        let mut selection = self.selections.last::<Point>(cx);
13717        selection.set_head(Point::zero(), SelectionGoal::None);
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.select(vec![selection]);
13721        });
13722    }
13723
13724    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13725        if matches!(self.mode, EditorMode::SingleLine) {
13726            cx.propagate();
13727            return;
13728        }
13729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13730        let cursor = self.buffer.read(cx).read(cx).len();
13731        self.change_selections(Default::default(), window, cx, |s| {
13732            s.select_ranges(vec![cursor..cursor])
13733        });
13734    }
13735
13736    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13737        self.nav_history = nav_history;
13738    }
13739
13740    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13741        self.nav_history.as_ref()
13742    }
13743
13744    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13745        self.push_to_nav_history(
13746            self.selections.newest_anchor().head(),
13747            None,
13748            false,
13749            true,
13750            cx,
13751        );
13752    }
13753
13754    fn push_to_nav_history(
13755        &mut self,
13756        cursor_anchor: Anchor,
13757        new_position: Option<Point>,
13758        is_deactivate: bool,
13759        always: bool,
13760        cx: &mut Context<Self>,
13761    ) {
13762        if let Some(nav_history) = self.nav_history.as_mut() {
13763            let buffer = self.buffer.read(cx).read(cx);
13764            let cursor_position = cursor_anchor.to_point(&buffer);
13765            let scroll_state = self.scroll_manager.anchor();
13766            let scroll_top_row = scroll_state.top_row(&buffer);
13767            drop(buffer);
13768
13769            if let Some(new_position) = new_position {
13770                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13771                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13772                    return;
13773                }
13774            }
13775
13776            nav_history.push(
13777                Some(NavigationData {
13778                    cursor_anchor,
13779                    cursor_position,
13780                    scroll_anchor: scroll_state,
13781                    scroll_top_row,
13782                }),
13783                cx,
13784            );
13785            cx.emit(EditorEvent::PushedToNavHistory {
13786                anchor: cursor_anchor,
13787                is_deactivate,
13788            })
13789        }
13790    }
13791
13792    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13793        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13794        let buffer = self.buffer.read(cx).snapshot(cx);
13795        let mut selection = self.selections.first::<usize>(cx);
13796        selection.set_head(buffer.len(), SelectionGoal::None);
13797        self.change_selections(Default::default(), window, cx, |s| {
13798            s.select(vec![selection]);
13799        });
13800    }
13801
13802    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13804        let end = self.buffer.read(cx).read(cx).len();
13805        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13806            s.select_ranges(vec![0..end]);
13807        });
13808    }
13809
13810    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13813        let mut selections = self.selections.all::<Point>(cx);
13814        let max_point = display_map.buffer_snapshot.max_point();
13815        for selection in &mut selections {
13816            let rows = selection.spanned_rows(true, &display_map);
13817            selection.start = Point::new(rows.start.0, 0);
13818            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13819            selection.reversed = false;
13820        }
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.select(selections);
13823        });
13824    }
13825
13826    pub fn split_selection_into_lines(
13827        &mut self,
13828        action: &SplitSelectionIntoLines,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        let selections = self
13833            .selections
13834            .all::<Point>(cx)
13835            .into_iter()
13836            .map(|selection| selection.start..selection.end)
13837            .collect::<Vec<_>>();
13838        self.unfold_ranges(&selections, true, true, cx);
13839
13840        let mut new_selection_ranges = Vec::new();
13841        {
13842            let buffer = self.buffer.read(cx).read(cx);
13843            for selection in selections {
13844                for row in selection.start.row..selection.end.row {
13845                    let line_start = Point::new(row, 0);
13846                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13847
13848                    if action.keep_selections {
13849                        // Keep the selection range for each line
13850                        let selection_start = if row == selection.start.row {
13851                            selection.start
13852                        } else {
13853                            line_start
13854                        };
13855                        new_selection_ranges.push(selection_start..line_end);
13856                    } else {
13857                        // Collapse to cursor at end of line
13858                        new_selection_ranges.push(line_end..line_end);
13859                    }
13860                }
13861
13862                let is_multiline_selection = selection.start.row != selection.end.row;
13863                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13864                // so this action feels more ergonomic when paired with other selection operations
13865                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13866                if !should_skip_last {
13867                    if action.keep_selections {
13868                        if is_multiline_selection {
13869                            let line_start = Point::new(selection.end.row, 0);
13870                            new_selection_ranges.push(line_start..selection.end);
13871                        } else {
13872                            new_selection_ranges.push(selection.start..selection.end);
13873                        }
13874                    } else {
13875                        new_selection_ranges.push(selection.end..selection.end);
13876                    }
13877                }
13878            }
13879        }
13880        self.change_selections(Default::default(), window, cx, |s| {
13881            s.select_ranges(new_selection_ranges);
13882        });
13883    }
13884
13885    pub fn add_selection_above(
13886        &mut self,
13887        _: &AddSelectionAbove,
13888        window: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        self.add_selection(true, window, cx);
13892    }
13893
13894    pub fn add_selection_below(
13895        &mut self,
13896        _: &AddSelectionBelow,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        self.add_selection(false, window, cx);
13901    }
13902
13903    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905
13906        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13907        let all_selections = self.selections.all::<Point>(cx);
13908        let text_layout_details = self.text_layout_details(window);
13909
13910        let (mut columnar_selections, new_selections_to_columnarize) = {
13911            if let Some(state) = self.add_selections_state.as_ref() {
13912                let columnar_selection_ids: HashSet<_> = state
13913                    .groups
13914                    .iter()
13915                    .flat_map(|group| group.stack.iter())
13916                    .copied()
13917                    .collect();
13918
13919                all_selections
13920                    .into_iter()
13921                    .partition(|s| columnar_selection_ids.contains(&s.id))
13922            } else {
13923                (Vec::new(), all_selections)
13924            }
13925        };
13926
13927        let mut state = self
13928            .add_selections_state
13929            .take()
13930            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13931
13932        for selection in new_selections_to_columnarize {
13933            let range = selection.display_range(&display_map).sorted();
13934            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13935            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13936            let positions = start_x.min(end_x)..start_x.max(end_x);
13937            let mut stack = Vec::new();
13938            for row in range.start.row().0..=range.end.row().0 {
13939                if let Some(selection) = self.selections.build_columnar_selection(
13940                    &display_map,
13941                    DisplayRow(row),
13942                    &positions,
13943                    selection.reversed,
13944                    &text_layout_details,
13945                ) {
13946                    stack.push(selection.id);
13947                    columnar_selections.push(selection);
13948                }
13949            }
13950            if !stack.is_empty() {
13951                if above {
13952                    stack.reverse();
13953                }
13954                state.groups.push(AddSelectionsGroup { above, stack });
13955            }
13956        }
13957
13958        let mut final_selections = Vec::new();
13959        let end_row = if above {
13960            DisplayRow(0)
13961        } else {
13962            display_map.max_point().row()
13963        };
13964
13965        let mut last_added_item_per_group = HashMap::default();
13966        for group in state.groups.iter_mut() {
13967            if let Some(last_id) = group.stack.last() {
13968                last_added_item_per_group.insert(*last_id, group);
13969            }
13970        }
13971
13972        for selection in columnar_selections {
13973            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13974                if above == group.above {
13975                    let range = selection.display_range(&display_map).sorted();
13976                    debug_assert_eq!(range.start.row(), range.end.row());
13977                    let mut row = range.start.row();
13978                    let positions =
13979                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13980                            px(start)..px(end)
13981                        } else {
13982                            let start_x =
13983                                display_map.x_for_display_point(range.start, &text_layout_details);
13984                            let end_x =
13985                                display_map.x_for_display_point(range.end, &text_layout_details);
13986                            start_x.min(end_x)..start_x.max(end_x)
13987                        };
13988
13989                    let mut maybe_new_selection = None;
13990                    while row != end_row {
13991                        if above {
13992                            row.0 -= 1;
13993                        } else {
13994                            row.0 += 1;
13995                        }
13996                        if let Some(new_selection) = self.selections.build_columnar_selection(
13997                            &display_map,
13998                            row,
13999                            &positions,
14000                            selection.reversed,
14001                            &text_layout_details,
14002                        ) {
14003                            maybe_new_selection = Some(new_selection);
14004                            break;
14005                        }
14006                    }
14007
14008                    if let Some(new_selection) = maybe_new_selection {
14009                        group.stack.push(new_selection.id);
14010                        if above {
14011                            final_selections.push(new_selection);
14012                            final_selections.push(selection);
14013                        } else {
14014                            final_selections.push(selection);
14015                            final_selections.push(new_selection);
14016                        }
14017                    } else {
14018                        final_selections.push(selection);
14019                    }
14020                } else {
14021                    group.stack.pop();
14022                }
14023            } else {
14024                final_selections.push(selection);
14025            }
14026        }
14027
14028        self.change_selections(Default::default(), window, cx, |s| {
14029            s.select(final_selections);
14030        });
14031
14032        let final_selection_ids: HashSet<_> = self
14033            .selections
14034            .all::<Point>(cx)
14035            .iter()
14036            .map(|s| s.id)
14037            .collect();
14038        state.groups.retain_mut(|group| {
14039            // selections might get merged above so we remove invalid items from stacks
14040            group.stack.retain(|id| final_selection_ids.contains(id));
14041
14042            // single selection in stack can be treated as initial state
14043            group.stack.len() > 1
14044        });
14045
14046        if !state.groups.is_empty() {
14047            self.add_selections_state = Some(state);
14048        }
14049    }
14050
14051    fn select_match_ranges(
14052        &mut self,
14053        range: Range<usize>,
14054        reversed: bool,
14055        replace_newest: bool,
14056        auto_scroll: Option<Autoscroll>,
14057        window: &mut Window,
14058        cx: &mut Context<Editor>,
14059    ) {
14060        self.unfold_ranges(
14061            std::slice::from_ref(&range),
14062            false,
14063            auto_scroll.is_some(),
14064            cx,
14065        );
14066        let effects = if let Some(scroll) = auto_scroll {
14067            SelectionEffects::scroll(scroll)
14068        } else {
14069            SelectionEffects::no_scroll()
14070        };
14071        self.change_selections(effects, window, cx, |s| {
14072            if replace_newest {
14073                s.delete(s.newest_anchor().id);
14074            }
14075            if reversed {
14076                s.insert_range(range.end..range.start);
14077            } else {
14078                s.insert_range(range);
14079            }
14080        });
14081    }
14082
14083    pub fn select_next_match_internal(
14084        &mut self,
14085        display_map: &DisplaySnapshot,
14086        replace_newest: bool,
14087        autoscroll: Option<Autoscroll>,
14088        window: &mut Window,
14089        cx: &mut Context<Self>,
14090    ) -> Result<()> {
14091        let buffer = &display_map.buffer_snapshot;
14092        let mut selections = self.selections.all::<usize>(cx);
14093        if let Some(mut select_next_state) = self.select_next_state.take() {
14094            let query = &select_next_state.query;
14095            if !select_next_state.done {
14096                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14097                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14098                let mut next_selected_range = None;
14099
14100                let bytes_after_last_selection =
14101                    buffer.bytes_in_range(last_selection.end..buffer.len());
14102                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14103                let query_matches = query
14104                    .stream_find_iter(bytes_after_last_selection)
14105                    .map(|result| (last_selection.end, result))
14106                    .chain(
14107                        query
14108                            .stream_find_iter(bytes_before_first_selection)
14109                            .map(|result| (0, result)),
14110                    );
14111
14112                for (start_offset, query_match) in query_matches {
14113                    let query_match = query_match.unwrap(); // can only fail due to I/O
14114                    let offset_range =
14115                        start_offset + query_match.start()..start_offset + query_match.end();
14116
14117                    if !select_next_state.wordwise
14118                        || (!buffer.is_inside_word(offset_range.start, false)
14119                            && !buffer.is_inside_word(offset_range.end, false))
14120                    {
14121                        // TODO: This is n^2, because we might check all the selections
14122                        if !selections
14123                            .iter()
14124                            .any(|selection| selection.range().overlaps(&offset_range))
14125                        {
14126                            next_selected_range = Some(offset_range);
14127                            break;
14128                        }
14129                    }
14130                }
14131
14132                if let Some(next_selected_range) = next_selected_range {
14133                    self.select_match_ranges(
14134                        next_selected_range,
14135                        last_selection.reversed,
14136                        replace_newest,
14137                        autoscroll,
14138                        window,
14139                        cx,
14140                    );
14141                } else {
14142                    select_next_state.done = true;
14143                }
14144            }
14145
14146            self.select_next_state = Some(select_next_state);
14147        } else {
14148            let mut only_carets = true;
14149            let mut same_text_selected = true;
14150            let mut selected_text = None;
14151
14152            let mut selections_iter = selections.iter().peekable();
14153            while let Some(selection) = selections_iter.next() {
14154                if selection.start != selection.end {
14155                    only_carets = false;
14156                }
14157
14158                if same_text_selected {
14159                    if selected_text.is_none() {
14160                        selected_text =
14161                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14162                    }
14163
14164                    if let Some(next_selection) = selections_iter.peek() {
14165                        if next_selection.range().len() == selection.range().len() {
14166                            let next_selected_text = buffer
14167                                .text_for_range(next_selection.range())
14168                                .collect::<String>();
14169                            if Some(next_selected_text) != selected_text {
14170                                same_text_selected = false;
14171                                selected_text = None;
14172                            }
14173                        } else {
14174                            same_text_selected = false;
14175                            selected_text = None;
14176                        }
14177                    }
14178                }
14179            }
14180
14181            if only_carets {
14182                for selection in &mut selections {
14183                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14184                    selection.start = word_range.start;
14185                    selection.end = word_range.end;
14186                    selection.goal = SelectionGoal::None;
14187                    selection.reversed = false;
14188                    self.select_match_ranges(
14189                        selection.start..selection.end,
14190                        selection.reversed,
14191                        replace_newest,
14192                        autoscroll,
14193                        window,
14194                        cx,
14195                    );
14196                }
14197
14198                if selections.len() == 1 {
14199                    let selection = selections
14200                        .last()
14201                        .expect("ensured that there's only one selection");
14202                    let query = buffer
14203                        .text_for_range(selection.start..selection.end)
14204                        .collect::<String>();
14205                    let is_empty = query.is_empty();
14206                    let select_state = SelectNextState {
14207                        query: AhoCorasick::new(&[query])?,
14208                        wordwise: true,
14209                        done: is_empty,
14210                    };
14211                    self.select_next_state = Some(select_state);
14212                } else {
14213                    self.select_next_state = None;
14214                }
14215            } else if let Some(selected_text) = selected_text {
14216                self.select_next_state = Some(SelectNextState {
14217                    query: AhoCorasick::new(&[selected_text])?,
14218                    wordwise: false,
14219                    done: false,
14220                });
14221                self.select_next_match_internal(
14222                    display_map,
14223                    replace_newest,
14224                    autoscroll,
14225                    window,
14226                    cx,
14227                )?;
14228            }
14229        }
14230        Ok(())
14231    }
14232
14233    pub fn select_all_matches(
14234        &mut self,
14235        _action: &SelectAllMatches,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) -> Result<()> {
14239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14240
14241        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14242
14243        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14244        let Some(select_next_state) = self.select_next_state.as_mut() else {
14245            return Ok(());
14246        };
14247        if select_next_state.done {
14248            return Ok(());
14249        }
14250
14251        let mut new_selections = Vec::new();
14252
14253        let reversed = self.selections.oldest::<usize>(cx).reversed;
14254        let buffer = &display_map.buffer_snapshot;
14255        let query_matches = select_next_state
14256            .query
14257            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14258
14259        for query_match in query_matches.into_iter() {
14260            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14261            let offset_range = if reversed {
14262                query_match.end()..query_match.start()
14263            } else {
14264                query_match.start()..query_match.end()
14265            };
14266
14267            if !select_next_state.wordwise
14268                || (!buffer.is_inside_word(offset_range.start, false)
14269                    && !buffer.is_inside_word(offset_range.end, false))
14270            {
14271                new_selections.push(offset_range.start..offset_range.end);
14272            }
14273        }
14274
14275        select_next_state.done = true;
14276
14277        if new_selections.is_empty() {
14278            log::error!("bug: new_selections is empty in select_all_matches");
14279            return Ok(());
14280        }
14281
14282        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14283        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14284            selections.select_ranges(new_selections)
14285        });
14286
14287        Ok(())
14288    }
14289
14290    pub fn select_next(
14291        &mut self,
14292        action: &SelectNext,
14293        window: &mut Window,
14294        cx: &mut Context<Self>,
14295    ) -> Result<()> {
14296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14297        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14298        self.select_next_match_internal(
14299            &display_map,
14300            action.replace_newest,
14301            Some(Autoscroll::newest()),
14302            window,
14303            cx,
14304        )?;
14305        Ok(())
14306    }
14307
14308    pub fn select_previous(
14309        &mut self,
14310        action: &SelectPrevious,
14311        window: &mut Window,
14312        cx: &mut Context<Self>,
14313    ) -> Result<()> {
14314        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14315        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14316        let buffer = &display_map.buffer_snapshot;
14317        let mut selections = self.selections.all::<usize>(cx);
14318        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14319            let query = &select_prev_state.query;
14320            if !select_prev_state.done {
14321                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14322                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14323                let mut next_selected_range = None;
14324                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14325                let bytes_before_last_selection =
14326                    buffer.reversed_bytes_in_range(0..last_selection.start);
14327                let bytes_after_first_selection =
14328                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14329                let query_matches = query
14330                    .stream_find_iter(bytes_before_last_selection)
14331                    .map(|result| (last_selection.start, result))
14332                    .chain(
14333                        query
14334                            .stream_find_iter(bytes_after_first_selection)
14335                            .map(|result| (buffer.len(), result)),
14336                    );
14337                for (end_offset, query_match) in query_matches {
14338                    let query_match = query_match.unwrap(); // can only fail due to I/O
14339                    let offset_range =
14340                        end_offset - query_match.end()..end_offset - query_match.start();
14341
14342                    if !select_prev_state.wordwise
14343                        || (!buffer.is_inside_word(offset_range.start, false)
14344                            && !buffer.is_inside_word(offset_range.end, false))
14345                    {
14346                        next_selected_range = Some(offset_range);
14347                        break;
14348                    }
14349                }
14350
14351                if let Some(next_selected_range) = next_selected_range {
14352                    self.select_match_ranges(
14353                        next_selected_range,
14354                        last_selection.reversed,
14355                        action.replace_newest,
14356                        Some(Autoscroll::newest()),
14357                        window,
14358                        cx,
14359                    );
14360                } else {
14361                    select_prev_state.done = true;
14362                }
14363            }
14364
14365            self.select_prev_state = Some(select_prev_state);
14366        } else {
14367            let mut only_carets = true;
14368            let mut same_text_selected = true;
14369            let mut selected_text = None;
14370
14371            let mut selections_iter = selections.iter().peekable();
14372            while let Some(selection) = selections_iter.next() {
14373                if selection.start != selection.end {
14374                    only_carets = false;
14375                }
14376
14377                if same_text_selected {
14378                    if selected_text.is_none() {
14379                        selected_text =
14380                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14381                    }
14382
14383                    if let Some(next_selection) = selections_iter.peek() {
14384                        if next_selection.range().len() == selection.range().len() {
14385                            let next_selected_text = buffer
14386                                .text_for_range(next_selection.range())
14387                                .collect::<String>();
14388                            if Some(next_selected_text) != selected_text {
14389                                same_text_selected = false;
14390                                selected_text = None;
14391                            }
14392                        } else {
14393                            same_text_selected = false;
14394                            selected_text = None;
14395                        }
14396                    }
14397                }
14398            }
14399
14400            if only_carets {
14401                for selection in &mut selections {
14402                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14403                    selection.start = word_range.start;
14404                    selection.end = word_range.end;
14405                    selection.goal = SelectionGoal::None;
14406                    selection.reversed = false;
14407                    self.select_match_ranges(
14408                        selection.start..selection.end,
14409                        selection.reversed,
14410                        action.replace_newest,
14411                        Some(Autoscroll::newest()),
14412                        window,
14413                        cx,
14414                    );
14415                }
14416                if selections.len() == 1 {
14417                    let selection = selections
14418                        .last()
14419                        .expect("ensured that there's only one selection");
14420                    let query = buffer
14421                        .text_for_range(selection.start..selection.end)
14422                        .collect::<String>();
14423                    let is_empty = query.is_empty();
14424                    let select_state = SelectNextState {
14425                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14426                        wordwise: true,
14427                        done: is_empty,
14428                    };
14429                    self.select_prev_state = Some(select_state);
14430                } else {
14431                    self.select_prev_state = None;
14432                }
14433            } else if let Some(selected_text) = selected_text {
14434                self.select_prev_state = Some(SelectNextState {
14435                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14436                    wordwise: false,
14437                    done: false,
14438                });
14439                self.select_previous(action, window, cx)?;
14440            }
14441        }
14442        Ok(())
14443    }
14444
14445    pub fn find_next_match(
14446        &mut self,
14447        _: &FindNextMatch,
14448        window: &mut Window,
14449        cx: &mut Context<Self>,
14450    ) -> Result<()> {
14451        let selections = self.selections.disjoint_anchors();
14452        match selections.first() {
14453            Some(first) if selections.len() >= 2 => {
14454                self.change_selections(Default::default(), window, cx, |s| {
14455                    s.select_ranges([first.range()]);
14456                });
14457            }
14458            _ => self.select_next(
14459                &SelectNext {
14460                    replace_newest: true,
14461                },
14462                window,
14463                cx,
14464            )?,
14465        }
14466        Ok(())
14467    }
14468
14469    pub fn find_previous_match(
14470        &mut self,
14471        _: &FindPreviousMatch,
14472        window: &mut Window,
14473        cx: &mut Context<Self>,
14474    ) -> Result<()> {
14475        let selections = self.selections.disjoint_anchors();
14476        match selections.last() {
14477            Some(last) if selections.len() >= 2 => {
14478                self.change_selections(Default::default(), window, cx, |s| {
14479                    s.select_ranges([last.range()]);
14480                });
14481            }
14482            _ => self.select_previous(
14483                &SelectPrevious {
14484                    replace_newest: true,
14485                },
14486                window,
14487                cx,
14488            )?,
14489        }
14490        Ok(())
14491    }
14492
14493    pub fn toggle_comments(
14494        &mut self,
14495        action: &ToggleComments,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) {
14499        if self.read_only(cx) {
14500            return;
14501        }
14502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14503        let text_layout_details = &self.text_layout_details(window);
14504        self.transact(window, cx, |this, window, cx| {
14505            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14506            let mut edits = Vec::new();
14507            let mut selection_edit_ranges = Vec::new();
14508            let mut last_toggled_row = None;
14509            let snapshot = this.buffer.read(cx).read(cx);
14510            let empty_str: Arc<str> = Arc::default();
14511            let mut suffixes_inserted = Vec::new();
14512            let ignore_indent = action.ignore_indent;
14513
14514            fn comment_prefix_range(
14515                snapshot: &MultiBufferSnapshot,
14516                row: MultiBufferRow,
14517                comment_prefix: &str,
14518                comment_prefix_whitespace: &str,
14519                ignore_indent: bool,
14520            ) -> Range<Point> {
14521                let indent_size = if ignore_indent {
14522                    0
14523                } else {
14524                    snapshot.indent_size_for_line(row).len
14525                };
14526
14527                let start = Point::new(row.0, indent_size);
14528
14529                let mut line_bytes = snapshot
14530                    .bytes_in_range(start..snapshot.max_point())
14531                    .flatten()
14532                    .copied();
14533
14534                // If this line currently begins with the line comment prefix, then record
14535                // the range containing the prefix.
14536                if line_bytes
14537                    .by_ref()
14538                    .take(comment_prefix.len())
14539                    .eq(comment_prefix.bytes())
14540                {
14541                    // Include any whitespace that matches the comment prefix.
14542                    let matching_whitespace_len = line_bytes
14543                        .zip(comment_prefix_whitespace.bytes())
14544                        .take_while(|(a, b)| a == b)
14545                        .count() as u32;
14546                    let end = Point::new(
14547                        start.row,
14548                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14549                    );
14550                    start..end
14551                } else {
14552                    start..start
14553                }
14554            }
14555
14556            fn comment_suffix_range(
14557                snapshot: &MultiBufferSnapshot,
14558                row: MultiBufferRow,
14559                comment_suffix: &str,
14560                comment_suffix_has_leading_space: bool,
14561            ) -> Range<Point> {
14562                let end = Point::new(row.0, snapshot.line_len(row));
14563                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14564
14565                let mut line_end_bytes = snapshot
14566                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14567                    .flatten()
14568                    .copied();
14569
14570                let leading_space_len = if suffix_start_column > 0
14571                    && line_end_bytes.next() == Some(b' ')
14572                    && comment_suffix_has_leading_space
14573                {
14574                    1
14575                } else {
14576                    0
14577                };
14578
14579                // If this line currently begins with the line comment prefix, then record
14580                // the range containing the prefix.
14581                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14582                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14583                    start..end
14584                } else {
14585                    end..end
14586                }
14587            }
14588
14589            // TODO: Handle selections that cross excerpts
14590            for selection in &mut selections {
14591                let start_column = snapshot
14592                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14593                    .len;
14594                let language = if let Some(language) =
14595                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14596                {
14597                    language
14598                } else {
14599                    continue;
14600                };
14601
14602                selection_edit_ranges.clear();
14603
14604                // If multiple selections contain a given row, avoid processing that
14605                // row more than once.
14606                let mut start_row = MultiBufferRow(selection.start.row);
14607                if last_toggled_row == Some(start_row) {
14608                    start_row = start_row.next_row();
14609                }
14610                let end_row =
14611                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14612                        MultiBufferRow(selection.end.row - 1)
14613                    } else {
14614                        MultiBufferRow(selection.end.row)
14615                    };
14616                last_toggled_row = Some(end_row);
14617
14618                if start_row > end_row {
14619                    continue;
14620                }
14621
14622                // If the language has line comments, toggle those.
14623                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14624
14625                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14626                if ignore_indent {
14627                    full_comment_prefixes = full_comment_prefixes
14628                        .into_iter()
14629                        .map(|s| Arc::from(s.trim_end()))
14630                        .collect();
14631                }
14632
14633                if !full_comment_prefixes.is_empty() {
14634                    let first_prefix = full_comment_prefixes
14635                        .first()
14636                        .expect("prefixes is non-empty");
14637                    let prefix_trimmed_lengths = full_comment_prefixes
14638                        .iter()
14639                        .map(|p| p.trim_end_matches(' ').len())
14640                        .collect::<SmallVec<[usize; 4]>>();
14641
14642                    let mut all_selection_lines_are_comments = true;
14643
14644                    for row in start_row.0..=end_row.0 {
14645                        let row = MultiBufferRow(row);
14646                        if start_row < end_row && snapshot.is_line_blank(row) {
14647                            continue;
14648                        }
14649
14650                        let prefix_range = full_comment_prefixes
14651                            .iter()
14652                            .zip(prefix_trimmed_lengths.iter().copied())
14653                            .map(|(prefix, trimmed_prefix_len)| {
14654                                comment_prefix_range(
14655                                    snapshot.deref(),
14656                                    row,
14657                                    &prefix[..trimmed_prefix_len],
14658                                    &prefix[trimmed_prefix_len..],
14659                                    ignore_indent,
14660                                )
14661                            })
14662                            .max_by_key(|range| range.end.column - range.start.column)
14663                            .expect("prefixes is non-empty");
14664
14665                        if prefix_range.is_empty() {
14666                            all_selection_lines_are_comments = false;
14667                        }
14668
14669                        selection_edit_ranges.push(prefix_range);
14670                    }
14671
14672                    if all_selection_lines_are_comments {
14673                        edits.extend(
14674                            selection_edit_ranges
14675                                .iter()
14676                                .cloned()
14677                                .map(|range| (range, empty_str.clone())),
14678                        );
14679                    } else {
14680                        let min_column = selection_edit_ranges
14681                            .iter()
14682                            .map(|range| range.start.column)
14683                            .min()
14684                            .unwrap_or(0);
14685                        edits.extend(selection_edit_ranges.iter().map(|range| {
14686                            let position = Point::new(range.start.row, min_column);
14687                            (position..position, first_prefix.clone())
14688                        }));
14689                    }
14690                } else if let Some(BlockCommentConfig {
14691                    start: full_comment_prefix,
14692                    end: comment_suffix,
14693                    ..
14694                }) = language.block_comment()
14695                {
14696                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14697                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14698                    let prefix_range = comment_prefix_range(
14699                        snapshot.deref(),
14700                        start_row,
14701                        comment_prefix,
14702                        comment_prefix_whitespace,
14703                        ignore_indent,
14704                    );
14705                    let suffix_range = comment_suffix_range(
14706                        snapshot.deref(),
14707                        end_row,
14708                        comment_suffix.trim_start_matches(' '),
14709                        comment_suffix.starts_with(' '),
14710                    );
14711
14712                    if prefix_range.is_empty() || suffix_range.is_empty() {
14713                        edits.push((
14714                            prefix_range.start..prefix_range.start,
14715                            full_comment_prefix.clone(),
14716                        ));
14717                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14718                        suffixes_inserted.push((end_row, comment_suffix.len()));
14719                    } else {
14720                        edits.push((prefix_range, empty_str.clone()));
14721                        edits.push((suffix_range, empty_str.clone()));
14722                    }
14723                } else {
14724                    continue;
14725                }
14726            }
14727
14728            drop(snapshot);
14729            this.buffer.update(cx, |buffer, cx| {
14730                buffer.edit(edits, None, cx);
14731            });
14732
14733            // Adjust selections so that they end before any comment suffixes that
14734            // were inserted.
14735            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14736            let mut selections = this.selections.all::<Point>(cx);
14737            let snapshot = this.buffer.read(cx).read(cx);
14738            for selection in &mut selections {
14739                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14740                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14741                        Ordering::Less => {
14742                            suffixes_inserted.next();
14743                            continue;
14744                        }
14745                        Ordering::Greater => break,
14746                        Ordering::Equal => {
14747                            if selection.end.column == snapshot.line_len(row) {
14748                                if selection.is_empty() {
14749                                    selection.start.column -= suffix_len as u32;
14750                                }
14751                                selection.end.column -= suffix_len as u32;
14752                            }
14753                            break;
14754                        }
14755                    }
14756                }
14757            }
14758
14759            drop(snapshot);
14760            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14761
14762            let selections = this.selections.all::<Point>(cx);
14763            let selections_on_single_row = selections.windows(2).all(|selections| {
14764                selections[0].start.row == selections[1].start.row
14765                    && selections[0].end.row == selections[1].end.row
14766                    && selections[0].start.row == selections[0].end.row
14767            });
14768            let selections_selecting = selections
14769                .iter()
14770                .any(|selection| selection.start != selection.end);
14771            let advance_downwards = action.advance_downwards
14772                && selections_on_single_row
14773                && !selections_selecting
14774                && !matches!(this.mode, EditorMode::SingleLine);
14775
14776            if advance_downwards {
14777                let snapshot = this.buffer.read(cx).snapshot(cx);
14778
14779                this.change_selections(Default::default(), window, cx, |s| {
14780                    s.move_cursors_with(|display_snapshot, display_point, _| {
14781                        let mut point = display_point.to_point(display_snapshot);
14782                        point.row += 1;
14783                        point = snapshot.clip_point(point, Bias::Left);
14784                        let display_point = point.to_display_point(display_snapshot);
14785                        let goal = SelectionGoal::HorizontalPosition(
14786                            display_snapshot
14787                                .x_for_display_point(display_point, text_layout_details)
14788                                .into(),
14789                        );
14790                        (display_point, goal)
14791                    })
14792                });
14793            }
14794        });
14795    }
14796
14797    pub fn select_enclosing_symbol(
14798        &mut self,
14799        _: &SelectEnclosingSymbol,
14800        window: &mut Window,
14801        cx: &mut Context<Self>,
14802    ) {
14803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14804
14805        let buffer = self.buffer.read(cx).snapshot(cx);
14806        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14807
14808        fn update_selection(
14809            selection: &Selection<usize>,
14810            buffer_snap: &MultiBufferSnapshot,
14811        ) -> Option<Selection<usize>> {
14812            let cursor = selection.head();
14813            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14814            for symbol in symbols.iter().rev() {
14815                let start = symbol.range.start.to_offset(buffer_snap);
14816                let end = symbol.range.end.to_offset(buffer_snap);
14817                let new_range = start..end;
14818                if start < selection.start || end > selection.end {
14819                    return Some(Selection {
14820                        id: selection.id,
14821                        start: new_range.start,
14822                        end: new_range.end,
14823                        goal: SelectionGoal::None,
14824                        reversed: selection.reversed,
14825                    });
14826                }
14827            }
14828            None
14829        }
14830
14831        let mut selected_larger_symbol = false;
14832        let new_selections = old_selections
14833            .iter()
14834            .map(|selection| match update_selection(selection, &buffer) {
14835                Some(new_selection) => {
14836                    if new_selection.range() != selection.range() {
14837                        selected_larger_symbol = true;
14838                    }
14839                    new_selection
14840                }
14841                None => selection.clone(),
14842            })
14843            .collect::<Vec<_>>();
14844
14845        if selected_larger_symbol {
14846            self.change_selections(Default::default(), window, cx, |s| {
14847                s.select(new_selections);
14848            });
14849        }
14850    }
14851
14852    pub fn select_larger_syntax_node(
14853        &mut self,
14854        _: &SelectLargerSyntaxNode,
14855        window: &mut Window,
14856        cx: &mut Context<Self>,
14857    ) {
14858        let Some(visible_row_count) = self.visible_row_count() else {
14859            return;
14860        };
14861        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14862        if old_selections.is_empty() {
14863            return;
14864        }
14865
14866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14867
14868        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14869        let buffer = self.buffer.read(cx).snapshot(cx);
14870
14871        let mut selected_larger_node = false;
14872        let mut new_selections = old_selections
14873            .iter()
14874            .map(|selection| {
14875                let old_range = selection.start..selection.end;
14876
14877                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14878                    // manually select word at selection
14879                    if ["string_content", "inline"].contains(&node.kind()) {
14880                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14881                        // ignore if word is already selected
14882                        if !word_range.is_empty() && old_range != word_range {
14883                            let (last_word_range, _) =
14884                                buffer.surrounding_word(old_range.end, false);
14885                            // only select word if start and end point belongs to same word
14886                            if word_range == last_word_range {
14887                                selected_larger_node = true;
14888                                return Selection {
14889                                    id: selection.id,
14890                                    start: word_range.start,
14891                                    end: word_range.end,
14892                                    goal: SelectionGoal::None,
14893                                    reversed: selection.reversed,
14894                                };
14895                            }
14896                        }
14897                    }
14898                }
14899
14900                let mut new_range = old_range.clone();
14901                while let Some((_node, containing_range)) =
14902                    buffer.syntax_ancestor(new_range.clone())
14903                {
14904                    new_range = match containing_range {
14905                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14906                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14907                    };
14908                    if !display_map.intersects_fold(new_range.start)
14909                        && !display_map.intersects_fold(new_range.end)
14910                    {
14911                        break;
14912                    }
14913                }
14914
14915                selected_larger_node |= new_range != old_range;
14916                Selection {
14917                    id: selection.id,
14918                    start: new_range.start,
14919                    end: new_range.end,
14920                    goal: SelectionGoal::None,
14921                    reversed: selection.reversed,
14922                }
14923            })
14924            .collect::<Vec<_>>();
14925
14926        if !selected_larger_node {
14927            return; // don't put this call in the history
14928        }
14929
14930        // scroll based on transformation done to the last selection created by the user
14931        let (last_old, last_new) = old_selections
14932            .last()
14933            .zip(new_selections.last().cloned())
14934            .expect("old_selections isn't empty");
14935
14936        // revert selection
14937        let is_selection_reversed = {
14938            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14939            new_selections.last_mut().expect("checked above").reversed =
14940                should_newest_selection_be_reversed;
14941            should_newest_selection_be_reversed
14942        };
14943
14944        if selected_larger_node {
14945            self.select_syntax_node_history.disable_clearing = true;
14946            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14947                s.select(new_selections.clone());
14948            });
14949            self.select_syntax_node_history.disable_clearing = false;
14950        }
14951
14952        let start_row = last_new.start.to_display_point(&display_map).row().0;
14953        let end_row = last_new.end.to_display_point(&display_map).row().0;
14954        let selection_height = end_row - start_row + 1;
14955        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14956
14957        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14958        let scroll_behavior = if fits_on_the_screen {
14959            self.request_autoscroll(Autoscroll::fit(), cx);
14960            SelectSyntaxNodeScrollBehavior::FitSelection
14961        } else if is_selection_reversed {
14962            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14963            SelectSyntaxNodeScrollBehavior::CursorTop
14964        } else {
14965            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14966            SelectSyntaxNodeScrollBehavior::CursorBottom
14967        };
14968
14969        self.select_syntax_node_history.push((
14970            old_selections,
14971            scroll_behavior,
14972            is_selection_reversed,
14973        ));
14974    }
14975
14976    pub fn select_smaller_syntax_node(
14977        &mut self,
14978        _: &SelectSmallerSyntaxNode,
14979        window: &mut Window,
14980        cx: &mut Context<Self>,
14981    ) {
14982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14983
14984        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14985            self.select_syntax_node_history.pop()
14986        {
14987            if let Some(selection) = selections.last_mut() {
14988                selection.reversed = is_selection_reversed;
14989            }
14990
14991            self.select_syntax_node_history.disable_clearing = true;
14992            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14993                s.select(selections.to_vec());
14994            });
14995            self.select_syntax_node_history.disable_clearing = false;
14996
14997            match scroll_behavior {
14998                SelectSyntaxNodeScrollBehavior::CursorTop => {
14999                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15000                }
15001                SelectSyntaxNodeScrollBehavior::FitSelection => {
15002                    self.request_autoscroll(Autoscroll::fit(), cx);
15003                }
15004                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15005                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15006                }
15007            }
15008        }
15009    }
15010
15011    pub fn unwrap_syntax_node(
15012        &mut self,
15013        _: &UnwrapSyntaxNode,
15014        window: &mut Window,
15015        cx: &mut Context<Self>,
15016    ) {
15017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15018
15019        let buffer = self.buffer.read(cx).snapshot(cx);
15020        let selections = self
15021            .selections
15022            .all::<usize>(cx)
15023            .into_iter()
15024            // subtracting the offset requires sorting
15025            .sorted_by_key(|i| i.start);
15026
15027        let full_edits = selections
15028            .into_iter()
15029            .filter_map(|selection| {
15030                // Only requires two branches once if-let-chains stabilize (#53667)
15031                let child = if !selection.is_empty() {
15032                    selection.range()
15033                } else if let Some((_, ancestor_range)) =
15034                    buffer.syntax_ancestor(selection.start..selection.end)
15035                {
15036                    match ancestor_range {
15037                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15038                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15039                    }
15040                } else {
15041                    selection.range()
15042                };
15043
15044                let mut parent = child.clone();
15045                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15046                    parent = match ancestor_range {
15047                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15048                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15049                    };
15050                    if parent.start < child.start || parent.end > child.end {
15051                        break;
15052                    }
15053                }
15054
15055                if parent == child {
15056                    return None;
15057                }
15058                let text = buffer.text_for_range(child).collect::<String>();
15059                Some((selection.id, parent, text))
15060            })
15061            .collect::<Vec<_>>();
15062
15063        self.transact(window, cx, |this, window, cx| {
15064            this.buffer.update(cx, |buffer, cx| {
15065                buffer.edit(
15066                    full_edits
15067                        .iter()
15068                        .map(|(_, p, t)| (p.clone(), t.clone()))
15069                        .collect::<Vec<_>>(),
15070                    None,
15071                    cx,
15072                );
15073            });
15074            this.change_selections(Default::default(), window, cx, |s| {
15075                let mut offset = 0;
15076                let mut selections = vec![];
15077                for (id, parent, text) in full_edits {
15078                    let start = parent.start - offset;
15079                    offset += parent.len() - text.len();
15080                    selections.push(Selection {
15081                        id,
15082                        start,
15083                        end: start + text.len(),
15084                        reversed: false,
15085                        goal: Default::default(),
15086                    });
15087                }
15088                s.select(selections);
15089            });
15090        });
15091    }
15092
15093    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15094        if !EditorSettings::get_global(cx).gutter.runnables {
15095            self.clear_tasks();
15096            return Task::ready(());
15097        }
15098        let project = self.project().map(Entity::downgrade);
15099        let task_sources = self.lsp_task_sources(cx);
15100        let multi_buffer = self.buffer.downgrade();
15101        cx.spawn_in(window, async move |editor, cx| {
15102            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15103            let Some(project) = project.and_then(|p| p.upgrade()) else {
15104                return;
15105            };
15106            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15107                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15108            }) else {
15109                return;
15110            };
15111
15112            let hide_runnables = project
15113                .update(cx, |project, _| project.is_via_collab())
15114                .unwrap_or(true);
15115            if hide_runnables {
15116                return;
15117            }
15118            let new_rows =
15119                cx.background_spawn({
15120                    let snapshot = display_snapshot.clone();
15121                    async move {
15122                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15123                    }
15124                })
15125                    .await;
15126            let Ok(lsp_tasks) =
15127                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15128            else {
15129                return;
15130            };
15131            let lsp_tasks = lsp_tasks.await;
15132
15133            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15134                lsp_tasks
15135                    .into_iter()
15136                    .flat_map(|(kind, tasks)| {
15137                        tasks.into_iter().filter_map(move |(location, task)| {
15138                            Some((kind.clone(), location?, task))
15139                        })
15140                    })
15141                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15142                        let buffer = location.target.buffer;
15143                        let buffer_snapshot = buffer.read(cx).snapshot();
15144                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15145                            |(excerpt_id, snapshot, _)| {
15146                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15147                                    display_snapshot
15148                                        .buffer_snapshot
15149                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15150                                } else {
15151                                    None
15152                                }
15153                            },
15154                        );
15155                        if let Some(offset) = offset {
15156                            let task_buffer_range =
15157                                location.target.range.to_point(&buffer_snapshot);
15158                            let context_buffer_range =
15159                                task_buffer_range.to_offset(&buffer_snapshot);
15160                            let context_range = BufferOffset(context_buffer_range.start)
15161                                ..BufferOffset(context_buffer_range.end);
15162
15163                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15164                                .or_insert_with(|| RunnableTasks {
15165                                    templates: Vec::new(),
15166                                    offset,
15167                                    column: task_buffer_range.start.column,
15168                                    extra_variables: HashMap::default(),
15169                                    context_range,
15170                                })
15171                                .templates
15172                                .push((kind, task.original_task().clone()));
15173                        }
15174
15175                        acc
15176                    })
15177            }) else {
15178                return;
15179            };
15180
15181            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15182                buffer.language_settings(cx).tasks.prefer_lsp
15183            }) else {
15184                return;
15185            };
15186
15187            let rows = Self::runnable_rows(
15188                project,
15189                display_snapshot,
15190                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15191                new_rows,
15192                cx.clone(),
15193            )
15194            .await;
15195            editor
15196                .update(cx, |editor, _| {
15197                    editor.clear_tasks();
15198                    for (key, mut value) in rows {
15199                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15200                            value.templates.extend(lsp_tasks.templates);
15201                        }
15202
15203                        editor.insert_tasks(key, value);
15204                    }
15205                    for (key, value) in lsp_tasks_by_rows {
15206                        editor.insert_tasks(key, value);
15207                    }
15208                })
15209                .ok();
15210        })
15211    }
15212    fn fetch_runnable_ranges(
15213        snapshot: &DisplaySnapshot,
15214        range: Range<Anchor>,
15215    ) -> Vec<language::RunnableRange> {
15216        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15217    }
15218
15219    fn runnable_rows(
15220        project: Entity<Project>,
15221        snapshot: DisplaySnapshot,
15222        prefer_lsp: bool,
15223        runnable_ranges: Vec<RunnableRange>,
15224        cx: AsyncWindowContext,
15225    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15226        cx.spawn(async move |cx| {
15227            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15228            for mut runnable in runnable_ranges {
15229                let Some(tasks) = cx
15230                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15231                    .ok()
15232                else {
15233                    continue;
15234                };
15235                let mut tasks = tasks.await;
15236
15237                if prefer_lsp {
15238                    tasks.retain(|(task_kind, _)| {
15239                        !matches!(task_kind, TaskSourceKind::Language { .. })
15240                    });
15241                }
15242                if tasks.is_empty() {
15243                    continue;
15244                }
15245
15246                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15247                let Some(row) = snapshot
15248                    .buffer_snapshot
15249                    .buffer_line_for_row(MultiBufferRow(point.row))
15250                    .map(|(_, range)| range.start.row)
15251                else {
15252                    continue;
15253                };
15254
15255                let context_range =
15256                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15257                runnable_rows.push((
15258                    (runnable.buffer_id, row),
15259                    RunnableTasks {
15260                        templates: tasks,
15261                        offset: snapshot
15262                            .buffer_snapshot
15263                            .anchor_before(runnable.run_range.start),
15264                        context_range,
15265                        column: point.column,
15266                        extra_variables: runnable.extra_captures,
15267                    },
15268                ));
15269            }
15270            runnable_rows
15271        })
15272    }
15273
15274    fn templates_with_tags(
15275        project: &Entity<Project>,
15276        runnable: &mut Runnable,
15277        cx: &mut App,
15278    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15279        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15280            let (worktree_id, file) = project
15281                .buffer_for_id(runnable.buffer, cx)
15282                .and_then(|buffer| buffer.read(cx).file())
15283                .map(|file| (file.worktree_id(cx), file.clone()))
15284                .unzip();
15285
15286            (
15287                project.task_store().read(cx).task_inventory().cloned(),
15288                worktree_id,
15289                file,
15290            )
15291        });
15292
15293        let tags = mem::take(&mut runnable.tags);
15294        let language = runnable.language.clone();
15295        cx.spawn(async move |cx| {
15296            let mut templates_with_tags = Vec::new();
15297            if let Some(inventory) = inventory {
15298                for RunnableTag(tag) in tags {
15299                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15300                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15301                    }) else {
15302                        return templates_with_tags;
15303                    };
15304                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15305                        move |(_, template)| {
15306                            template.tags.iter().any(|source_tag| source_tag == &tag)
15307                        },
15308                    ));
15309                }
15310            }
15311            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15312
15313            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15314                // Strongest source wins; if we have worktree tag binding, prefer that to
15315                // global and language bindings;
15316                // if we have a global binding, prefer that to language binding.
15317                let first_mismatch = templates_with_tags
15318                    .iter()
15319                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15320                if let Some(index) = first_mismatch {
15321                    templates_with_tags.truncate(index);
15322                }
15323            }
15324
15325            templates_with_tags
15326        })
15327    }
15328
15329    pub fn move_to_enclosing_bracket(
15330        &mut self,
15331        _: &MoveToEnclosingBracket,
15332        window: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) {
15335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15336        self.change_selections(Default::default(), window, cx, |s| {
15337            s.move_offsets_with(|snapshot, selection| {
15338                let Some(enclosing_bracket_ranges) =
15339                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15340                else {
15341                    return;
15342                };
15343
15344                let mut best_length = usize::MAX;
15345                let mut best_inside = false;
15346                let mut best_in_bracket_range = false;
15347                let mut best_destination = None;
15348                for (open, close) in enclosing_bracket_ranges {
15349                    let close = close.to_inclusive();
15350                    let length = close.end() - open.start;
15351                    let inside = selection.start >= open.end && selection.end <= *close.start();
15352                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15353                        || close.contains(&selection.head());
15354
15355                    // If best is next to a bracket and current isn't, skip
15356                    if !in_bracket_range && best_in_bracket_range {
15357                        continue;
15358                    }
15359
15360                    // Prefer smaller lengths unless best is inside and current isn't
15361                    if length > best_length && (best_inside || !inside) {
15362                        continue;
15363                    }
15364
15365                    best_length = length;
15366                    best_inside = inside;
15367                    best_in_bracket_range = in_bracket_range;
15368                    best_destination = Some(
15369                        if close.contains(&selection.start) && close.contains(&selection.end) {
15370                            if inside { open.end } else { open.start }
15371                        } else if inside {
15372                            *close.start()
15373                        } else {
15374                            *close.end()
15375                        },
15376                    );
15377                }
15378
15379                if let Some(destination) = best_destination {
15380                    selection.collapse_to(destination, SelectionGoal::None);
15381                }
15382            })
15383        });
15384    }
15385
15386    pub fn undo_selection(
15387        &mut self,
15388        _: &UndoSelection,
15389        window: &mut Window,
15390        cx: &mut Context<Self>,
15391    ) {
15392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15393        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15394            self.selection_history.mode = SelectionHistoryMode::Undoing;
15395            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15396                this.end_selection(window, cx);
15397                this.change_selections(
15398                    SelectionEffects::scroll(Autoscroll::newest()),
15399                    window,
15400                    cx,
15401                    |s| s.select_anchors(entry.selections.to_vec()),
15402                );
15403            });
15404            self.selection_history.mode = SelectionHistoryMode::Normal;
15405
15406            self.select_next_state = entry.select_next_state;
15407            self.select_prev_state = entry.select_prev_state;
15408            self.add_selections_state = entry.add_selections_state;
15409        }
15410    }
15411
15412    pub fn redo_selection(
15413        &mut self,
15414        _: &RedoSelection,
15415        window: &mut Window,
15416        cx: &mut Context<Self>,
15417    ) {
15418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15419        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15420            self.selection_history.mode = SelectionHistoryMode::Redoing;
15421            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15422                this.end_selection(window, cx);
15423                this.change_selections(
15424                    SelectionEffects::scroll(Autoscroll::newest()),
15425                    window,
15426                    cx,
15427                    |s| s.select_anchors(entry.selections.to_vec()),
15428                );
15429            });
15430            self.selection_history.mode = SelectionHistoryMode::Normal;
15431
15432            self.select_next_state = entry.select_next_state;
15433            self.select_prev_state = entry.select_prev_state;
15434            self.add_selections_state = entry.add_selections_state;
15435        }
15436    }
15437
15438    pub fn expand_excerpts(
15439        &mut self,
15440        action: &ExpandExcerpts,
15441        _: &mut Window,
15442        cx: &mut Context<Self>,
15443    ) {
15444        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15445    }
15446
15447    pub fn expand_excerpts_down(
15448        &mut self,
15449        action: &ExpandExcerptsDown,
15450        _: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) {
15453        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15454    }
15455
15456    pub fn expand_excerpts_up(
15457        &mut self,
15458        action: &ExpandExcerptsUp,
15459        _: &mut Window,
15460        cx: &mut Context<Self>,
15461    ) {
15462        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15463    }
15464
15465    pub fn expand_excerpts_for_direction(
15466        &mut self,
15467        lines: u32,
15468        direction: ExpandExcerptDirection,
15469
15470        cx: &mut Context<Self>,
15471    ) {
15472        let selections = self.selections.disjoint_anchors();
15473
15474        let lines = if lines == 0 {
15475            EditorSettings::get_global(cx).expand_excerpt_lines
15476        } else {
15477            lines
15478        };
15479
15480        self.buffer.update(cx, |buffer, cx| {
15481            let snapshot = buffer.snapshot(cx);
15482            let mut excerpt_ids = selections
15483                .iter()
15484                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15485                .collect::<Vec<_>>();
15486            excerpt_ids.sort();
15487            excerpt_ids.dedup();
15488            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15489        })
15490    }
15491
15492    pub fn expand_excerpt(
15493        &mut self,
15494        excerpt: ExcerptId,
15495        direction: ExpandExcerptDirection,
15496        window: &mut Window,
15497        cx: &mut Context<Self>,
15498    ) {
15499        let current_scroll_position = self.scroll_position(cx);
15500        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15501        let mut should_scroll_up = false;
15502
15503        if direction == ExpandExcerptDirection::Down {
15504            let multi_buffer = self.buffer.read(cx);
15505            let snapshot = multi_buffer.snapshot(cx);
15506            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15507                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15508                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15509            {
15510                let buffer_snapshot = buffer.read(cx).snapshot();
15511                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15512                let last_row = buffer_snapshot.max_point().row;
15513                let lines_below = last_row.saturating_sub(excerpt_end_row);
15514                should_scroll_up = lines_below >= lines_to_expand;
15515            }
15516        }
15517
15518        self.buffer.update(cx, |buffer, cx| {
15519            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15520        });
15521
15522        if should_scroll_up {
15523            let new_scroll_position =
15524                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15525            self.set_scroll_position(new_scroll_position, window, cx);
15526        }
15527    }
15528
15529    pub fn go_to_singleton_buffer_point(
15530        &mut self,
15531        point: Point,
15532        window: &mut Window,
15533        cx: &mut Context<Self>,
15534    ) {
15535        self.go_to_singleton_buffer_range(point..point, window, cx);
15536    }
15537
15538    pub fn go_to_singleton_buffer_range(
15539        &mut self,
15540        range: Range<Point>,
15541        window: &mut Window,
15542        cx: &mut Context<Self>,
15543    ) {
15544        let multibuffer = self.buffer().read(cx);
15545        let Some(buffer) = multibuffer.as_singleton() else {
15546            return;
15547        };
15548        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15549            return;
15550        };
15551        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15552            return;
15553        };
15554        self.change_selections(
15555            SelectionEffects::default().nav_history(true),
15556            window,
15557            cx,
15558            |s| s.select_anchor_ranges([start..end]),
15559        );
15560    }
15561
15562    pub fn go_to_diagnostic(
15563        &mut self,
15564        action: &GoToDiagnostic,
15565        window: &mut Window,
15566        cx: &mut Context<Self>,
15567    ) {
15568        if !self.diagnostics_enabled() {
15569            return;
15570        }
15571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15572        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15573    }
15574
15575    pub fn go_to_prev_diagnostic(
15576        &mut self,
15577        action: &GoToPreviousDiagnostic,
15578        window: &mut Window,
15579        cx: &mut Context<Self>,
15580    ) {
15581        if !self.diagnostics_enabled() {
15582            return;
15583        }
15584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15585        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15586    }
15587
15588    pub fn go_to_diagnostic_impl(
15589        &mut self,
15590        direction: Direction,
15591        severity: GoToDiagnosticSeverityFilter,
15592        window: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) {
15595        let buffer = self.buffer.read(cx).snapshot(cx);
15596        let selection = self.selections.newest::<usize>(cx);
15597
15598        let mut active_group_id = None;
15599        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15600            && active_group.active_range.start.to_offset(&buffer) == selection.start
15601        {
15602            active_group_id = Some(active_group.group_id);
15603        }
15604
15605        fn filtered(
15606            snapshot: EditorSnapshot,
15607            severity: GoToDiagnosticSeverityFilter,
15608            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15609        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15610            diagnostics
15611                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15612                .filter(|entry| entry.range.start != entry.range.end)
15613                .filter(|entry| !entry.diagnostic.is_unnecessary)
15614                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15615        }
15616
15617        let snapshot = self.snapshot(window, cx);
15618        let before = filtered(
15619            snapshot.clone(),
15620            severity,
15621            buffer
15622                .diagnostics_in_range(0..selection.start)
15623                .filter(|entry| entry.range.start <= selection.start),
15624        );
15625        let after = filtered(
15626            snapshot,
15627            severity,
15628            buffer
15629                .diagnostics_in_range(selection.start..buffer.len())
15630                .filter(|entry| entry.range.start >= selection.start),
15631        );
15632
15633        let mut found: Option<DiagnosticEntry<usize>> = None;
15634        if direction == Direction::Prev {
15635            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15636            {
15637                for diagnostic in prev_diagnostics.into_iter().rev() {
15638                    if diagnostic.range.start != selection.start
15639                        || active_group_id
15640                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15641                    {
15642                        found = Some(diagnostic);
15643                        break 'outer;
15644                    }
15645                }
15646            }
15647        } else {
15648            for diagnostic in after.chain(before) {
15649                if diagnostic.range.start != selection.start
15650                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15651                {
15652                    found = Some(diagnostic);
15653                    break;
15654                }
15655            }
15656        }
15657        let Some(next_diagnostic) = found else {
15658            return;
15659        };
15660
15661        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15662        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15663            return;
15664        };
15665        self.change_selections(Default::default(), window, cx, |s| {
15666            s.select_ranges(vec![
15667                next_diagnostic.range.start..next_diagnostic.range.start,
15668            ])
15669        });
15670        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15671        self.refresh_edit_prediction(false, true, window, cx);
15672    }
15673
15674    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15676        let snapshot = self.snapshot(window, cx);
15677        let selection = self.selections.newest::<Point>(cx);
15678        self.go_to_hunk_before_or_after_position(
15679            &snapshot,
15680            selection.head(),
15681            Direction::Next,
15682            window,
15683            cx,
15684        );
15685    }
15686
15687    pub fn go_to_hunk_before_or_after_position(
15688        &mut self,
15689        snapshot: &EditorSnapshot,
15690        position: Point,
15691        direction: Direction,
15692        window: &mut Window,
15693        cx: &mut Context<Editor>,
15694    ) {
15695        let row = if direction == Direction::Next {
15696            self.hunk_after_position(snapshot, position)
15697                .map(|hunk| hunk.row_range.start)
15698        } else {
15699            self.hunk_before_position(snapshot, position)
15700        };
15701
15702        if let Some(row) = row {
15703            let destination = Point::new(row.0, 0);
15704            let autoscroll = Autoscroll::center();
15705
15706            self.unfold_ranges(&[destination..destination], false, false, cx);
15707            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15708                s.select_ranges([destination..destination]);
15709            });
15710        }
15711    }
15712
15713    fn hunk_after_position(
15714        &mut self,
15715        snapshot: &EditorSnapshot,
15716        position: Point,
15717    ) -> Option<MultiBufferDiffHunk> {
15718        snapshot
15719            .buffer_snapshot
15720            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15721            .find(|hunk| hunk.row_range.start.0 > position.row)
15722            .or_else(|| {
15723                snapshot
15724                    .buffer_snapshot
15725                    .diff_hunks_in_range(Point::zero()..position)
15726                    .find(|hunk| hunk.row_range.end.0 < position.row)
15727            })
15728    }
15729
15730    fn go_to_prev_hunk(
15731        &mut self,
15732        _: &GoToPreviousHunk,
15733        window: &mut Window,
15734        cx: &mut Context<Self>,
15735    ) {
15736        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15737        let snapshot = self.snapshot(window, cx);
15738        let selection = self.selections.newest::<Point>(cx);
15739        self.go_to_hunk_before_or_after_position(
15740            &snapshot,
15741            selection.head(),
15742            Direction::Prev,
15743            window,
15744            cx,
15745        );
15746    }
15747
15748    fn hunk_before_position(
15749        &mut self,
15750        snapshot: &EditorSnapshot,
15751        position: Point,
15752    ) -> Option<MultiBufferRow> {
15753        snapshot
15754            .buffer_snapshot
15755            .diff_hunk_before(position)
15756            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15757    }
15758
15759    fn go_to_next_change(
15760        &mut self,
15761        _: &GoToNextChange,
15762        window: &mut Window,
15763        cx: &mut Context<Self>,
15764    ) {
15765        if let Some(selections) = self
15766            .change_list
15767            .next_change(1, Direction::Next)
15768            .map(|s| s.to_vec())
15769        {
15770            self.change_selections(Default::default(), window, cx, |s| {
15771                let map = s.display_map();
15772                s.select_display_ranges(selections.iter().map(|a| {
15773                    let point = a.to_display_point(&map);
15774                    point..point
15775                }))
15776            })
15777        }
15778    }
15779
15780    fn go_to_previous_change(
15781        &mut self,
15782        _: &GoToPreviousChange,
15783        window: &mut Window,
15784        cx: &mut Context<Self>,
15785    ) {
15786        if let Some(selections) = self
15787            .change_list
15788            .next_change(1, Direction::Prev)
15789            .map(|s| s.to_vec())
15790        {
15791            self.change_selections(Default::default(), window, cx, |s| {
15792                let map = s.display_map();
15793                s.select_display_ranges(selections.iter().map(|a| {
15794                    let point = a.to_display_point(&map);
15795                    point..point
15796                }))
15797            })
15798        }
15799    }
15800
15801    fn go_to_line<T: 'static>(
15802        &mut self,
15803        position: Anchor,
15804        highlight_color: Option<Hsla>,
15805        window: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        let snapshot = self.snapshot(window, cx).display_snapshot;
15809        let position = position.to_point(&snapshot.buffer_snapshot);
15810        let start = snapshot
15811            .buffer_snapshot
15812            .clip_point(Point::new(position.row, 0), Bias::Left);
15813        let end = start + Point::new(1, 0);
15814        let start = snapshot.buffer_snapshot.anchor_before(start);
15815        let end = snapshot.buffer_snapshot.anchor_before(end);
15816
15817        self.highlight_rows::<T>(
15818            start..end,
15819            highlight_color
15820                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15821            Default::default(),
15822            cx,
15823        );
15824
15825        if self.buffer.read(cx).is_singleton() {
15826            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15827        }
15828    }
15829
15830    pub fn go_to_definition(
15831        &mut self,
15832        _: &GoToDefinition,
15833        window: &mut Window,
15834        cx: &mut Context<Self>,
15835    ) -> Task<Result<Navigated>> {
15836        let definition =
15837            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15838        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15839        cx.spawn_in(window, async move |editor, cx| {
15840            if definition.await? == Navigated::Yes {
15841                return Ok(Navigated::Yes);
15842            }
15843            match fallback_strategy {
15844                GoToDefinitionFallback::None => Ok(Navigated::No),
15845                GoToDefinitionFallback::FindAllReferences => {
15846                    match editor.update_in(cx, |editor, window, cx| {
15847                        editor.find_all_references(&FindAllReferences, window, cx)
15848                    })? {
15849                        Some(references) => references.await,
15850                        None => Ok(Navigated::No),
15851                    }
15852                }
15853            }
15854        })
15855    }
15856
15857    pub fn go_to_declaration(
15858        &mut self,
15859        _: &GoToDeclaration,
15860        window: &mut Window,
15861        cx: &mut Context<Self>,
15862    ) -> Task<Result<Navigated>> {
15863        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15864    }
15865
15866    pub fn go_to_declaration_split(
15867        &mut self,
15868        _: &GoToDeclaration,
15869        window: &mut Window,
15870        cx: &mut Context<Self>,
15871    ) -> Task<Result<Navigated>> {
15872        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15873    }
15874
15875    pub fn go_to_implementation(
15876        &mut self,
15877        _: &GoToImplementation,
15878        window: &mut Window,
15879        cx: &mut Context<Self>,
15880    ) -> Task<Result<Navigated>> {
15881        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15882    }
15883
15884    pub fn go_to_implementation_split(
15885        &mut self,
15886        _: &GoToImplementationSplit,
15887        window: &mut Window,
15888        cx: &mut Context<Self>,
15889    ) -> Task<Result<Navigated>> {
15890        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15891    }
15892
15893    pub fn go_to_type_definition(
15894        &mut self,
15895        _: &GoToTypeDefinition,
15896        window: &mut Window,
15897        cx: &mut Context<Self>,
15898    ) -> Task<Result<Navigated>> {
15899        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15900    }
15901
15902    pub fn go_to_definition_split(
15903        &mut self,
15904        _: &GoToDefinitionSplit,
15905        window: &mut Window,
15906        cx: &mut Context<Self>,
15907    ) -> Task<Result<Navigated>> {
15908        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15909    }
15910
15911    pub fn go_to_type_definition_split(
15912        &mut self,
15913        _: &GoToTypeDefinitionSplit,
15914        window: &mut Window,
15915        cx: &mut Context<Self>,
15916    ) -> Task<Result<Navigated>> {
15917        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15918    }
15919
15920    fn go_to_definition_of_kind(
15921        &mut self,
15922        kind: GotoDefinitionKind,
15923        split: bool,
15924        window: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) -> Task<Result<Navigated>> {
15927        let Some(provider) = self.semantics_provider.clone() else {
15928            return Task::ready(Ok(Navigated::No));
15929        };
15930        let head = self.selections.newest::<usize>(cx).head();
15931        let buffer = self.buffer.read(cx);
15932        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15933            return Task::ready(Ok(Navigated::No));
15934        };
15935        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15936            return Task::ready(Ok(Navigated::No));
15937        };
15938
15939        cx.spawn_in(window, async move |editor, cx| {
15940            let Some(definitions) = definitions.await? else {
15941                return Ok(Navigated::No);
15942            };
15943            let navigated = editor
15944                .update_in(cx, |editor, window, cx| {
15945                    editor.navigate_to_hover_links(
15946                        Some(kind),
15947                        definitions
15948                            .into_iter()
15949                            .filter(|location| {
15950                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15951                            })
15952                            .map(HoverLink::Text)
15953                            .collect::<Vec<_>>(),
15954                        split,
15955                        window,
15956                        cx,
15957                    )
15958                })?
15959                .await?;
15960            anyhow::Ok(navigated)
15961        })
15962    }
15963
15964    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15965        let selection = self.selections.newest_anchor();
15966        let head = selection.head();
15967        let tail = selection.tail();
15968
15969        let Some((buffer, start_position)) =
15970            self.buffer.read(cx).text_anchor_for_position(head, cx)
15971        else {
15972            return;
15973        };
15974
15975        let end_position = if head != tail {
15976            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15977                return;
15978            };
15979            Some(pos)
15980        } else {
15981            None
15982        };
15983
15984        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15985            let url = if let Some(end_pos) = end_position {
15986                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15987            } else {
15988                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15989            };
15990
15991            if let Some(url) = url {
15992                editor.update(cx, |_, cx| {
15993                    cx.open_url(&url);
15994                })
15995            } else {
15996                Ok(())
15997            }
15998        });
15999
16000        url_finder.detach();
16001    }
16002
16003    pub fn open_selected_filename(
16004        &mut self,
16005        _: &OpenSelectedFilename,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        let Some(workspace) = self.workspace() else {
16010            return;
16011        };
16012
16013        let position = self.selections.newest_anchor().head();
16014
16015        let Some((buffer, buffer_position)) =
16016            self.buffer.read(cx).text_anchor_for_position(position, cx)
16017        else {
16018            return;
16019        };
16020
16021        let project = self.project.clone();
16022
16023        cx.spawn_in(window, async move |_, cx| {
16024            let result = find_file(&buffer, project, buffer_position, cx).await;
16025
16026            if let Some((_, path)) = result {
16027                workspace
16028                    .update_in(cx, |workspace, window, cx| {
16029                        workspace.open_resolved_path(path, window, cx)
16030                    })?
16031                    .await?;
16032            }
16033            anyhow::Ok(())
16034        })
16035        .detach();
16036    }
16037
16038    pub(crate) fn navigate_to_hover_links(
16039        &mut self,
16040        kind: Option<GotoDefinitionKind>,
16041        definitions: Vec<HoverLink>,
16042        split: bool,
16043        window: &mut Window,
16044        cx: &mut Context<Editor>,
16045    ) -> Task<Result<Navigated>> {
16046        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16047        let mut first_url_or_file = None;
16048        let definitions: Vec<_> = definitions
16049            .into_iter()
16050            .filter_map(|def| match def {
16051                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16052                HoverLink::InlayHint(lsp_location, server_id) => {
16053                    let computation =
16054                        self.compute_target_location(lsp_location, server_id, window, cx);
16055                    Some(cx.background_spawn(computation))
16056                }
16057                HoverLink::Url(url) => {
16058                    first_url_or_file = Some(Either::Left(url));
16059                    None
16060                }
16061                HoverLink::File(path) => {
16062                    first_url_or_file = Some(Either::Right(path));
16063                    None
16064                }
16065            })
16066            .collect();
16067
16068        let workspace = self.workspace();
16069
16070        cx.spawn_in(window, async move |editor, acx| {
16071            let mut locations: Vec<Location> = future::join_all(definitions)
16072                .await
16073                .into_iter()
16074                .filter_map(|location| location.transpose())
16075                .collect::<Result<_>>()
16076                .context("location tasks")?;
16077
16078            if locations.len() > 1 {
16079                let Some(workspace) = workspace else {
16080                    return Ok(Navigated::No);
16081                };
16082
16083                let tab_kind = match kind {
16084                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16085                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16086                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16087                    Some(GotoDefinitionKind::Type) => "Types",
16088                };
16089                let title = editor
16090                    .update_in(acx, |_, _, cx| {
16091                        let target = locations
16092                            .iter()
16093                            .map(|location| {
16094                                location
16095                                    .buffer
16096                                    .read(cx)
16097                                    .text_for_range(location.range.clone())
16098                                    .collect::<String>()
16099                            })
16100                            .filter(|text| !text.contains('\n'))
16101                            .unique()
16102                            .take(3)
16103                            .join(", ");
16104                        if target.is_empty() {
16105                            tab_kind.to_owned()
16106                        } else {
16107                            format!("{tab_kind} for {target}")
16108                        }
16109                    })
16110                    .context("buffer title")?;
16111
16112                let opened = workspace
16113                    .update_in(acx, |workspace, window, cx| {
16114                        Self::open_locations_in_multibuffer(
16115                            workspace,
16116                            locations,
16117                            title,
16118                            split,
16119                            MultibufferSelectionMode::First,
16120                            window,
16121                            cx,
16122                        )
16123                    })
16124                    .is_ok();
16125
16126                anyhow::Ok(Navigated::from_bool(opened))
16127            } else if locations.is_empty() {
16128                // If there is one definition, just open it directly
16129                match first_url_or_file {
16130                    Some(Either::Left(url)) => {
16131                        acx.update(|_, cx| cx.open_url(&url))?;
16132                        Ok(Navigated::Yes)
16133                    }
16134                    Some(Either::Right(path)) => {
16135                        let Some(workspace) = workspace else {
16136                            return Ok(Navigated::No);
16137                        };
16138
16139                        workspace
16140                            .update_in(acx, |workspace, window, cx| {
16141                                workspace.open_resolved_path(path, window, cx)
16142                            })?
16143                            .await?;
16144                        Ok(Navigated::Yes)
16145                    }
16146                    None => Ok(Navigated::No),
16147                }
16148            } else {
16149                let Some(workspace) = workspace else {
16150                    return Ok(Navigated::No);
16151                };
16152
16153                let target = locations.pop().unwrap();
16154                editor.update_in(acx, |editor, window, cx| {
16155                    let pane = workspace.read(cx).active_pane().clone();
16156
16157                    let range = target.range.to_point(target.buffer.read(cx));
16158                    let range = editor.range_for_match(&range);
16159                    let range = collapse_multiline_range(range);
16160
16161                    if !split
16162                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16163                    {
16164                        editor.go_to_singleton_buffer_range(range, window, cx);
16165                    } else {
16166                        window.defer(cx, move |window, cx| {
16167                            let target_editor: Entity<Self> =
16168                                workspace.update(cx, |workspace, cx| {
16169                                    let pane = if split {
16170                                        workspace.adjacent_pane(window, cx)
16171                                    } else {
16172                                        workspace.active_pane().clone()
16173                                    };
16174
16175                                    workspace.open_project_item(
16176                                        pane,
16177                                        target.buffer.clone(),
16178                                        true,
16179                                        true,
16180                                        window,
16181                                        cx,
16182                                    )
16183                                });
16184                            target_editor.update(cx, |target_editor, cx| {
16185                                // When selecting a definition in a different buffer, disable the nav history
16186                                // to avoid creating a history entry at the previous cursor location.
16187                                pane.update(cx, |pane, _| pane.disable_history());
16188                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16189                                pane.update(cx, |pane, _| pane.enable_history());
16190                            });
16191                        });
16192                    }
16193                    Navigated::Yes
16194                })
16195            }
16196        })
16197    }
16198
16199    fn compute_target_location(
16200        &self,
16201        lsp_location: lsp::Location,
16202        server_id: LanguageServerId,
16203        window: &mut Window,
16204        cx: &mut Context<Self>,
16205    ) -> Task<anyhow::Result<Option<Location>>> {
16206        let Some(project) = self.project.clone() else {
16207            return Task::ready(Ok(None));
16208        };
16209
16210        cx.spawn_in(window, async move |editor, cx| {
16211            let location_task = editor.update(cx, |_, cx| {
16212                project.update(cx, |project, cx| {
16213                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16214                })
16215            })?;
16216            let location = Some({
16217                let target_buffer_handle = location_task.await.context("open local buffer")?;
16218                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16219                    let target_start = target_buffer
16220                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16221                    let target_end = target_buffer
16222                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16223                    target_buffer.anchor_after(target_start)
16224                        ..target_buffer.anchor_before(target_end)
16225                })?;
16226                Location {
16227                    buffer: target_buffer_handle,
16228                    range,
16229                }
16230            });
16231            Ok(location)
16232        })
16233    }
16234
16235    pub fn find_all_references(
16236        &mut self,
16237        _: &FindAllReferences,
16238        window: &mut Window,
16239        cx: &mut Context<Self>,
16240    ) -> Option<Task<Result<Navigated>>> {
16241        let selection = self.selections.newest::<usize>(cx);
16242        let multi_buffer = self.buffer.read(cx);
16243        let head = selection.head();
16244
16245        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16246        let head_anchor = multi_buffer_snapshot.anchor_at(
16247            head,
16248            if head < selection.tail() {
16249                Bias::Right
16250            } else {
16251                Bias::Left
16252            },
16253        );
16254
16255        match self
16256            .find_all_references_task_sources
16257            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16258        {
16259            Ok(_) => {
16260                log::info!(
16261                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16262                );
16263                return None;
16264            }
16265            Err(i) => {
16266                self.find_all_references_task_sources.insert(i, head_anchor);
16267            }
16268        }
16269
16270        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16271        let workspace = self.workspace()?;
16272        let project = workspace.read(cx).project().clone();
16273        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16274        Some(cx.spawn_in(window, async move |editor, cx| {
16275            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16276                if let Ok(i) = editor
16277                    .find_all_references_task_sources
16278                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16279                {
16280                    editor.find_all_references_task_sources.remove(i);
16281                }
16282            });
16283
16284            let Some(locations) = references.await? else {
16285                return anyhow::Ok(Navigated::No);
16286            };
16287            if locations.is_empty() {
16288                return anyhow::Ok(Navigated::No);
16289            }
16290
16291            workspace.update_in(cx, |workspace, window, cx| {
16292                let target = locations
16293                    .iter()
16294                    .map(|location| {
16295                        location
16296                            .buffer
16297                            .read(cx)
16298                            .text_for_range(location.range.clone())
16299                            .collect::<String>()
16300                    })
16301                    .filter(|text| !text.contains('\n'))
16302                    .unique()
16303                    .take(3)
16304                    .join(", ");
16305                let title = if target.is_empty() {
16306                    "References".to_owned()
16307                } else {
16308                    format!("References to {target}")
16309                };
16310                Self::open_locations_in_multibuffer(
16311                    workspace,
16312                    locations,
16313                    title,
16314                    false,
16315                    MultibufferSelectionMode::First,
16316                    window,
16317                    cx,
16318                );
16319                Navigated::Yes
16320            })
16321        }))
16322    }
16323
16324    /// Opens a multibuffer with the given project locations in it
16325    pub fn open_locations_in_multibuffer(
16326        workspace: &mut Workspace,
16327        mut locations: Vec<Location>,
16328        title: String,
16329        split: bool,
16330        multibuffer_selection_mode: MultibufferSelectionMode,
16331        window: &mut Window,
16332        cx: &mut Context<Workspace>,
16333    ) {
16334        if locations.is_empty() {
16335            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16336            return;
16337        }
16338
16339        // If there are multiple definitions, open them in a multibuffer
16340        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16341        let mut locations = locations.into_iter().peekable();
16342        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16343        let capability = workspace.project().read(cx).capability();
16344
16345        let excerpt_buffer = cx.new(|cx| {
16346            let mut multibuffer = MultiBuffer::new(capability);
16347            while let Some(location) = locations.next() {
16348                let buffer = location.buffer.read(cx);
16349                let mut ranges_for_buffer = Vec::new();
16350                let range = location.range.to_point(buffer);
16351                ranges_for_buffer.push(range.clone());
16352
16353                while let Some(next_location) = locations.peek() {
16354                    if next_location.buffer == location.buffer {
16355                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16356                        locations.next();
16357                    } else {
16358                        break;
16359                    }
16360                }
16361
16362                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16363                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16364                    PathKey::for_buffer(&location.buffer, cx),
16365                    location.buffer.clone(),
16366                    ranges_for_buffer,
16367                    multibuffer_context_lines(cx),
16368                    cx,
16369                );
16370                ranges.extend(new_ranges)
16371            }
16372
16373            multibuffer.with_title(title)
16374        });
16375
16376        let editor = cx.new(|cx| {
16377            Editor::for_multibuffer(
16378                excerpt_buffer,
16379                Some(workspace.project().clone()),
16380                window,
16381                cx,
16382            )
16383        });
16384        editor.update(cx, |editor, cx| {
16385            match multibuffer_selection_mode {
16386                MultibufferSelectionMode::First => {
16387                    if let Some(first_range) = ranges.first() {
16388                        editor.change_selections(
16389                            SelectionEffects::no_scroll(),
16390                            window,
16391                            cx,
16392                            |selections| {
16393                                selections.clear_disjoint();
16394                                selections
16395                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16396                            },
16397                        );
16398                    }
16399                    editor.highlight_background::<Self>(
16400                        &ranges,
16401                        |theme| theme.colors().editor_highlighted_line_background,
16402                        cx,
16403                    );
16404                }
16405                MultibufferSelectionMode::All => {
16406                    editor.change_selections(
16407                        SelectionEffects::no_scroll(),
16408                        window,
16409                        cx,
16410                        |selections| {
16411                            selections.clear_disjoint();
16412                            selections.select_anchor_ranges(ranges);
16413                        },
16414                    );
16415                }
16416            }
16417            editor.register_buffers_with_language_servers(cx);
16418        });
16419
16420        let item = Box::new(editor);
16421        let item_id = item.item_id();
16422
16423        if split {
16424            workspace.split_item(SplitDirection::Right, item, window, cx);
16425        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16426            let (preview_item_id, preview_item_idx) =
16427                workspace.active_pane().read_with(cx, |pane, _| {
16428                    (pane.preview_item_id(), pane.preview_item_idx())
16429                });
16430
16431            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16432
16433            if let Some(preview_item_id) = preview_item_id {
16434                workspace.active_pane().update(cx, |pane, cx| {
16435                    pane.remove_item(preview_item_id, false, false, window, cx);
16436                });
16437            }
16438        } else {
16439            workspace.add_item_to_active_pane(item, None, true, window, cx);
16440        }
16441        workspace.active_pane().update(cx, |pane, cx| {
16442            pane.set_preview_item_id(Some(item_id), cx);
16443        });
16444    }
16445
16446    pub fn rename(
16447        &mut self,
16448        _: &Rename,
16449        window: &mut Window,
16450        cx: &mut Context<Self>,
16451    ) -> Option<Task<Result<()>>> {
16452        use language::ToOffset as _;
16453
16454        let provider = self.semantics_provider.clone()?;
16455        let selection = self.selections.newest_anchor().clone();
16456        let (cursor_buffer, cursor_buffer_position) = self
16457            .buffer
16458            .read(cx)
16459            .text_anchor_for_position(selection.head(), cx)?;
16460        let (tail_buffer, cursor_buffer_position_end) = self
16461            .buffer
16462            .read(cx)
16463            .text_anchor_for_position(selection.tail(), cx)?;
16464        if tail_buffer != cursor_buffer {
16465            return None;
16466        }
16467
16468        let snapshot = cursor_buffer.read(cx).snapshot();
16469        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16470        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16471        let prepare_rename = provider
16472            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16473            .unwrap_or_else(|| Task::ready(Ok(None)));
16474        drop(snapshot);
16475
16476        Some(cx.spawn_in(window, async move |this, cx| {
16477            let rename_range = if let Some(range) = prepare_rename.await? {
16478                Some(range)
16479            } else {
16480                this.update(cx, |this, cx| {
16481                    let buffer = this.buffer.read(cx).snapshot(cx);
16482                    let mut buffer_highlights = this
16483                        .document_highlights_for_position(selection.head(), &buffer)
16484                        .filter(|highlight| {
16485                            highlight.start.excerpt_id == selection.head().excerpt_id
16486                                && highlight.end.excerpt_id == selection.head().excerpt_id
16487                        });
16488                    buffer_highlights
16489                        .next()
16490                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16491                })?
16492            };
16493            if let Some(rename_range) = rename_range {
16494                this.update_in(cx, |this, window, cx| {
16495                    let snapshot = cursor_buffer.read(cx).snapshot();
16496                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16497                    let cursor_offset_in_rename_range =
16498                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16499                    let cursor_offset_in_rename_range_end =
16500                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16501
16502                    this.take_rename(false, window, cx);
16503                    let buffer = this.buffer.read(cx).read(cx);
16504                    let cursor_offset = selection.head().to_offset(&buffer);
16505                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16506                    let rename_end = rename_start + rename_buffer_range.len();
16507                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16508                    let mut old_highlight_id = None;
16509                    let old_name: Arc<str> = buffer
16510                        .chunks(rename_start..rename_end, true)
16511                        .map(|chunk| {
16512                            if old_highlight_id.is_none() {
16513                                old_highlight_id = chunk.syntax_highlight_id;
16514                            }
16515                            chunk.text
16516                        })
16517                        .collect::<String>()
16518                        .into();
16519
16520                    drop(buffer);
16521
16522                    // Position the selection in the rename editor so that it matches the current selection.
16523                    this.show_local_selections = false;
16524                    let rename_editor = cx.new(|cx| {
16525                        let mut editor = Editor::single_line(window, cx);
16526                        editor.buffer.update(cx, |buffer, cx| {
16527                            buffer.edit([(0..0, old_name.clone())], None, cx)
16528                        });
16529                        let rename_selection_range = match cursor_offset_in_rename_range
16530                            .cmp(&cursor_offset_in_rename_range_end)
16531                        {
16532                            Ordering::Equal => {
16533                                editor.select_all(&SelectAll, window, cx);
16534                                return editor;
16535                            }
16536                            Ordering::Less => {
16537                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16538                            }
16539                            Ordering::Greater => {
16540                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16541                            }
16542                        };
16543                        if rename_selection_range.end > old_name.len() {
16544                            editor.select_all(&SelectAll, window, cx);
16545                        } else {
16546                            editor.change_selections(Default::default(), window, cx, |s| {
16547                                s.select_ranges([rename_selection_range]);
16548                            });
16549                        }
16550                        editor
16551                    });
16552                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16553                        if e == &EditorEvent::Focused {
16554                            cx.emit(EditorEvent::FocusedIn)
16555                        }
16556                    })
16557                    .detach();
16558
16559                    let write_highlights =
16560                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16561                    let read_highlights =
16562                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16563                    let ranges = write_highlights
16564                        .iter()
16565                        .flat_map(|(_, ranges)| ranges.iter())
16566                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16567                        .cloned()
16568                        .collect();
16569
16570                    this.highlight_text::<Rename>(
16571                        ranges,
16572                        HighlightStyle {
16573                            fade_out: Some(0.6),
16574                            ..Default::default()
16575                        },
16576                        cx,
16577                    );
16578                    let rename_focus_handle = rename_editor.focus_handle(cx);
16579                    window.focus(&rename_focus_handle);
16580                    let block_id = this.insert_blocks(
16581                        [BlockProperties {
16582                            style: BlockStyle::Flex,
16583                            placement: BlockPlacement::Below(range.start),
16584                            height: Some(1),
16585                            render: Arc::new({
16586                                let rename_editor = rename_editor.clone();
16587                                move |cx: &mut BlockContext| {
16588                                    let mut text_style = cx.editor_style.text.clone();
16589                                    if let Some(highlight_style) = old_highlight_id
16590                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16591                                    {
16592                                        text_style = text_style.highlight(highlight_style);
16593                                    }
16594                                    div()
16595                                        .block_mouse_except_scroll()
16596                                        .pl(cx.anchor_x)
16597                                        .child(EditorElement::new(
16598                                            &rename_editor,
16599                                            EditorStyle {
16600                                                background: cx.theme().system().transparent,
16601                                                local_player: cx.editor_style.local_player,
16602                                                text: text_style,
16603                                                scrollbar_width: cx.editor_style.scrollbar_width,
16604                                                syntax: cx.editor_style.syntax.clone(),
16605                                                status: cx.editor_style.status.clone(),
16606                                                inlay_hints_style: HighlightStyle {
16607                                                    font_weight: Some(FontWeight::BOLD),
16608                                                    ..make_inlay_hints_style(cx.app)
16609                                                },
16610                                                edit_prediction_styles: make_suggestion_styles(
16611                                                    cx.app,
16612                                                ),
16613                                                ..EditorStyle::default()
16614                                            },
16615                                        ))
16616                                        .into_any_element()
16617                                }
16618                            }),
16619                            priority: 0,
16620                        }],
16621                        Some(Autoscroll::fit()),
16622                        cx,
16623                    )[0];
16624                    this.pending_rename = Some(RenameState {
16625                        range,
16626                        old_name,
16627                        editor: rename_editor,
16628                        block_id,
16629                    });
16630                })?;
16631            }
16632
16633            Ok(())
16634        }))
16635    }
16636
16637    pub fn confirm_rename(
16638        &mut self,
16639        _: &ConfirmRename,
16640        window: &mut Window,
16641        cx: &mut Context<Self>,
16642    ) -> Option<Task<Result<()>>> {
16643        let rename = self.take_rename(false, window, cx)?;
16644        let workspace = self.workspace()?.downgrade();
16645        let (buffer, start) = self
16646            .buffer
16647            .read(cx)
16648            .text_anchor_for_position(rename.range.start, cx)?;
16649        let (end_buffer, _) = self
16650            .buffer
16651            .read(cx)
16652            .text_anchor_for_position(rename.range.end, cx)?;
16653        if buffer != end_buffer {
16654            return None;
16655        }
16656
16657        let old_name = rename.old_name;
16658        let new_name = rename.editor.read(cx).text(cx);
16659
16660        let rename = self.semantics_provider.as_ref()?.perform_rename(
16661            &buffer,
16662            start,
16663            new_name.clone(),
16664            cx,
16665        )?;
16666
16667        Some(cx.spawn_in(window, async move |editor, cx| {
16668            let project_transaction = rename.await?;
16669            Self::open_project_transaction(
16670                &editor,
16671                workspace,
16672                project_transaction,
16673                format!("Rename: {}{}", old_name, new_name),
16674                cx,
16675            )
16676            .await?;
16677
16678            editor.update(cx, |editor, cx| {
16679                editor.refresh_document_highlights(cx);
16680            })?;
16681            Ok(())
16682        }))
16683    }
16684
16685    fn take_rename(
16686        &mut self,
16687        moving_cursor: bool,
16688        window: &mut Window,
16689        cx: &mut Context<Self>,
16690    ) -> Option<RenameState> {
16691        let rename = self.pending_rename.take()?;
16692        if rename.editor.focus_handle(cx).is_focused(window) {
16693            window.focus(&self.focus_handle);
16694        }
16695
16696        self.remove_blocks(
16697            [rename.block_id].into_iter().collect(),
16698            Some(Autoscroll::fit()),
16699            cx,
16700        );
16701        self.clear_highlights::<Rename>(cx);
16702        self.show_local_selections = true;
16703
16704        if moving_cursor {
16705            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16706                editor.selections.newest::<usize>(cx).head()
16707            });
16708
16709            // Update the selection to match the position of the selection inside
16710            // the rename editor.
16711            let snapshot = self.buffer.read(cx).read(cx);
16712            let rename_range = rename.range.to_offset(&snapshot);
16713            let cursor_in_editor = snapshot
16714                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16715                .min(rename_range.end);
16716            drop(snapshot);
16717
16718            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16719                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16720            });
16721        } else {
16722            self.refresh_document_highlights(cx);
16723        }
16724
16725        Some(rename)
16726    }
16727
16728    pub fn pending_rename(&self) -> Option<&RenameState> {
16729        self.pending_rename.as_ref()
16730    }
16731
16732    fn format(
16733        &mut self,
16734        _: &Format,
16735        window: &mut Window,
16736        cx: &mut Context<Self>,
16737    ) -> Option<Task<Result<()>>> {
16738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16739
16740        let project = match &self.project {
16741            Some(project) => project.clone(),
16742            None => return None,
16743        };
16744
16745        Some(self.perform_format(
16746            project,
16747            FormatTrigger::Manual,
16748            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16749            window,
16750            cx,
16751        ))
16752    }
16753
16754    fn format_selections(
16755        &mut self,
16756        _: &FormatSelections,
16757        window: &mut Window,
16758        cx: &mut Context<Self>,
16759    ) -> Option<Task<Result<()>>> {
16760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16761
16762        let project = match &self.project {
16763            Some(project) => project.clone(),
16764            None => return None,
16765        };
16766
16767        let ranges = self
16768            .selections
16769            .all_adjusted(cx)
16770            .into_iter()
16771            .map(|selection| selection.range())
16772            .collect_vec();
16773
16774        Some(self.perform_format(
16775            project,
16776            FormatTrigger::Manual,
16777            FormatTarget::Ranges(ranges),
16778            window,
16779            cx,
16780        ))
16781    }
16782
16783    fn perform_format(
16784        &mut self,
16785        project: Entity<Project>,
16786        trigger: FormatTrigger,
16787        target: FormatTarget,
16788        window: &mut Window,
16789        cx: &mut Context<Self>,
16790    ) -> Task<Result<()>> {
16791        let buffer = self.buffer.clone();
16792        let (buffers, target) = match target {
16793            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16794            FormatTarget::Ranges(selection_ranges) => {
16795                let multi_buffer = buffer.read(cx);
16796                let snapshot = multi_buffer.read(cx);
16797                let mut buffers = HashSet::default();
16798                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16799                    BTreeMap::new();
16800                for selection_range in selection_ranges {
16801                    for (buffer, buffer_range, _) in
16802                        snapshot.range_to_buffer_ranges(selection_range)
16803                    {
16804                        let buffer_id = buffer.remote_id();
16805                        let start = buffer.anchor_before(buffer_range.start);
16806                        let end = buffer.anchor_after(buffer_range.end);
16807                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16808                        buffer_id_to_ranges
16809                            .entry(buffer_id)
16810                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16811                            .or_insert_with(|| vec![start..end]);
16812                    }
16813                }
16814                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16815            }
16816        };
16817
16818        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16819        let selections_prev = transaction_id_prev
16820            .and_then(|transaction_id_prev| {
16821                // default to selections as they were after the last edit, if we have them,
16822                // instead of how they are now.
16823                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16824                // will take you back to where you made the last edit, instead of staying where you scrolled
16825                self.selection_history
16826                    .transaction(transaction_id_prev)
16827                    .map(|t| t.0.clone())
16828            })
16829            .unwrap_or_else(|| self.selections.disjoint_anchors());
16830
16831        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16832        let format = project.update(cx, |project, cx| {
16833            project.format(buffers, target, true, trigger, cx)
16834        });
16835
16836        cx.spawn_in(window, async move |editor, cx| {
16837            let transaction = futures::select_biased! {
16838                transaction = format.log_err().fuse() => transaction,
16839                () = timeout => {
16840                    log::warn!("timed out waiting for formatting");
16841                    None
16842                }
16843            };
16844
16845            buffer
16846                .update(cx, |buffer, cx| {
16847                    if let Some(transaction) = transaction
16848                        && !buffer.is_singleton()
16849                    {
16850                        buffer.push_transaction(&transaction.0, cx);
16851                    }
16852                    cx.notify();
16853                })
16854                .ok();
16855
16856            if let Some(transaction_id_now) =
16857                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16858            {
16859                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16860                if has_new_transaction {
16861                    _ = editor.update(cx, |editor, _| {
16862                        editor
16863                            .selection_history
16864                            .insert_transaction(transaction_id_now, selections_prev);
16865                    });
16866                }
16867            }
16868
16869            Ok(())
16870        })
16871    }
16872
16873    fn organize_imports(
16874        &mut self,
16875        _: &OrganizeImports,
16876        window: &mut Window,
16877        cx: &mut Context<Self>,
16878    ) -> Option<Task<Result<()>>> {
16879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16880        let project = match &self.project {
16881            Some(project) => project.clone(),
16882            None => return None,
16883        };
16884        Some(self.perform_code_action_kind(
16885            project,
16886            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16887            window,
16888            cx,
16889        ))
16890    }
16891
16892    fn perform_code_action_kind(
16893        &mut self,
16894        project: Entity<Project>,
16895        kind: CodeActionKind,
16896        window: &mut Window,
16897        cx: &mut Context<Self>,
16898    ) -> Task<Result<()>> {
16899        let buffer = self.buffer.clone();
16900        let buffers = buffer.read(cx).all_buffers();
16901        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16902        let apply_action = project.update(cx, |project, cx| {
16903            project.apply_code_action_kind(buffers, kind, true, cx)
16904        });
16905        cx.spawn_in(window, async move |_, cx| {
16906            let transaction = futures::select_biased! {
16907                () = timeout => {
16908                    log::warn!("timed out waiting for executing code action");
16909                    None
16910                }
16911                transaction = apply_action.log_err().fuse() => transaction,
16912            };
16913            buffer
16914                .update(cx, |buffer, cx| {
16915                    // check if we need this
16916                    if let Some(transaction) = transaction
16917                        && !buffer.is_singleton()
16918                    {
16919                        buffer.push_transaction(&transaction.0, cx);
16920                    }
16921                    cx.notify();
16922                })
16923                .ok();
16924            Ok(())
16925        })
16926    }
16927
16928    pub fn restart_language_server(
16929        &mut self,
16930        _: &RestartLanguageServer,
16931        _: &mut Window,
16932        cx: &mut Context<Self>,
16933    ) {
16934        if let Some(project) = self.project.clone() {
16935            self.buffer.update(cx, |multi_buffer, cx| {
16936                project.update(cx, |project, cx| {
16937                    project.restart_language_servers_for_buffers(
16938                        multi_buffer.all_buffers().into_iter().collect(),
16939                        HashSet::default(),
16940                        cx,
16941                    );
16942                });
16943            })
16944        }
16945    }
16946
16947    pub fn stop_language_server(
16948        &mut self,
16949        _: &StopLanguageServer,
16950        _: &mut Window,
16951        cx: &mut Context<Self>,
16952    ) {
16953        if let Some(project) = self.project.clone() {
16954            self.buffer.update(cx, |multi_buffer, cx| {
16955                project.update(cx, |project, cx| {
16956                    project.stop_language_servers_for_buffers(
16957                        multi_buffer.all_buffers().into_iter().collect(),
16958                        HashSet::default(),
16959                        cx,
16960                    );
16961                    cx.emit(project::Event::RefreshInlayHints);
16962                });
16963            });
16964        }
16965    }
16966
16967    fn cancel_language_server_work(
16968        workspace: &mut Workspace,
16969        _: &actions::CancelLanguageServerWork,
16970        _: &mut Window,
16971        cx: &mut Context<Workspace>,
16972    ) {
16973        let project = workspace.project();
16974        let buffers = workspace
16975            .active_item(cx)
16976            .and_then(|item| item.act_as::<Editor>(cx))
16977            .map_or(HashSet::default(), |editor| {
16978                editor.read(cx).buffer.read(cx).all_buffers()
16979            });
16980        project.update(cx, |project, cx| {
16981            project.cancel_language_server_work_for_buffers(buffers, cx);
16982        });
16983    }
16984
16985    fn show_character_palette(
16986        &mut self,
16987        _: &ShowCharacterPalette,
16988        window: &mut Window,
16989        _: &mut Context<Self>,
16990    ) {
16991        window.show_character_palette();
16992    }
16993
16994    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16995        if !self.diagnostics_enabled() {
16996            return;
16997        }
16998
16999        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17000            let buffer = self.buffer.read(cx).snapshot(cx);
17001            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17002            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17003            let is_valid = buffer
17004                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17005                .any(|entry| {
17006                    entry.diagnostic.is_primary
17007                        && !entry.range.is_empty()
17008                        && entry.range.start == primary_range_start
17009                        && entry.diagnostic.message == active_diagnostics.active_message
17010                });
17011
17012            if !is_valid {
17013                self.dismiss_diagnostics(cx);
17014            }
17015        }
17016    }
17017
17018    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17019        match &self.active_diagnostics {
17020            ActiveDiagnostic::Group(group) => Some(group),
17021            _ => None,
17022        }
17023    }
17024
17025    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17026        if !self.diagnostics_enabled() {
17027            return;
17028        }
17029        self.dismiss_diagnostics(cx);
17030        self.active_diagnostics = ActiveDiagnostic::All;
17031    }
17032
17033    fn activate_diagnostics(
17034        &mut self,
17035        buffer_id: BufferId,
17036        diagnostic: DiagnosticEntry<usize>,
17037        window: &mut Window,
17038        cx: &mut Context<Self>,
17039    ) {
17040        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17041            return;
17042        }
17043        self.dismiss_diagnostics(cx);
17044        let snapshot = self.snapshot(window, cx);
17045        let buffer = self.buffer.read(cx).snapshot(cx);
17046        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17047            return;
17048        };
17049
17050        let diagnostic_group = buffer
17051            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17052            .collect::<Vec<_>>();
17053
17054        let blocks =
17055            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17056
17057        let blocks = self.display_map.update(cx, |display_map, cx| {
17058            display_map.insert_blocks(blocks, cx).into_iter().collect()
17059        });
17060        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17061            active_range: buffer.anchor_before(diagnostic.range.start)
17062                ..buffer.anchor_after(diagnostic.range.end),
17063            active_message: diagnostic.diagnostic.message.clone(),
17064            group_id: diagnostic.diagnostic.group_id,
17065            blocks,
17066        });
17067        cx.notify();
17068    }
17069
17070    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17071        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17072            return;
17073        };
17074
17075        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17076        if let ActiveDiagnostic::Group(group) = prev {
17077            self.display_map.update(cx, |display_map, cx| {
17078                display_map.remove_blocks(group.blocks, cx);
17079            });
17080            cx.notify();
17081        }
17082    }
17083
17084    /// Disable inline diagnostics rendering for this editor.
17085    pub fn disable_inline_diagnostics(&mut self) {
17086        self.inline_diagnostics_enabled = false;
17087        self.inline_diagnostics_update = Task::ready(());
17088        self.inline_diagnostics.clear();
17089    }
17090
17091    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17092        self.diagnostics_enabled = false;
17093        self.dismiss_diagnostics(cx);
17094        self.inline_diagnostics_update = Task::ready(());
17095        self.inline_diagnostics.clear();
17096    }
17097
17098    pub fn diagnostics_enabled(&self) -> bool {
17099        self.diagnostics_enabled && self.mode.is_full()
17100    }
17101
17102    pub fn inline_diagnostics_enabled(&self) -> bool {
17103        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17104    }
17105
17106    pub fn show_inline_diagnostics(&self) -> bool {
17107        self.show_inline_diagnostics
17108    }
17109
17110    pub fn toggle_inline_diagnostics(
17111        &mut self,
17112        _: &ToggleInlineDiagnostics,
17113        window: &mut Window,
17114        cx: &mut Context<Editor>,
17115    ) {
17116        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17117        self.refresh_inline_diagnostics(false, window, cx);
17118    }
17119
17120    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17121        self.diagnostics_max_severity = severity;
17122        self.display_map.update(cx, |display_map, _| {
17123            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17124        });
17125    }
17126
17127    pub fn toggle_diagnostics(
17128        &mut self,
17129        _: &ToggleDiagnostics,
17130        window: &mut Window,
17131        cx: &mut Context<Editor>,
17132    ) {
17133        if !self.diagnostics_enabled() {
17134            return;
17135        }
17136
17137        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17138            EditorSettings::get_global(cx)
17139                .diagnostics_max_severity
17140                .filter(|severity| severity != &DiagnosticSeverity::Off)
17141                .unwrap_or(DiagnosticSeverity::Hint)
17142        } else {
17143            DiagnosticSeverity::Off
17144        };
17145        self.set_max_diagnostics_severity(new_severity, cx);
17146        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17147            self.active_diagnostics = ActiveDiagnostic::None;
17148            self.inline_diagnostics_update = Task::ready(());
17149            self.inline_diagnostics.clear();
17150        } else {
17151            self.refresh_inline_diagnostics(false, window, cx);
17152        }
17153
17154        cx.notify();
17155    }
17156
17157    pub fn toggle_minimap(
17158        &mut self,
17159        _: &ToggleMinimap,
17160        window: &mut Window,
17161        cx: &mut Context<Editor>,
17162    ) {
17163        if self.supports_minimap(cx) {
17164            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17165        }
17166    }
17167
17168    fn refresh_inline_diagnostics(
17169        &mut self,
17170        debounce: bool,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) {
17174        let max_severity = ProjectSettings::get_global(cx)
17175            .diagnostics
17176            .inline
17177            .max_severity
17178            .unwrap_or(self.diagnostics_max_severity);
17179
17180        if !self.inline_diagnostics_enabled()
17181            || !self.show_inline_diagnostics
17182            || max_severity == DiagnosticSeverity::Off
17183        {
17184            self.inline_diagnostics_update = Task::ready(());
17185            self.inline_diagnostics.clear();
17186            return;
17187        }
17188
17189        let debounce_ms = ProjectSettings::get_global(cx)
17190            .diagnostics
17191            .inline
17192            .update_debounce_ms;
17193        let debounce = if debounce && debounce_ms > 0 {
17194            Some(Duration::from_millis(debounce_ms))
17195        } else {
17196            None
17197        };
17198        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17199            if let Some(debounce) = debounce {
17200                cx.background_executor().timer(debounce).await;
17201            }
17202            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17203                editor
17204                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17205                    .ok()
17206            }) else {
17207                return;
17208            };
17209
17210            let new_inline_diagnostics = cx
17211                .background_spawn(async move {
17212                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17213                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17214                        let message = diagnostic_entry
17215                            .diagnostic
17216                            .message
17217                            .split_once('\n')
17218                            .map(|(line, _)| line)
17219                            .map(SharedString::new)
17220                            .unwrap_or_else(|| {
17221                                SharedString::from(diagnostic_entry.diagnostic.message)
17222                            });
17223                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17224                        let (Ok(i) | Err(i)) = inline_diagnostics
17225                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17226                        inline_diagnostics.insert(
17227                            i,
17228                            (
17229                                start_anchor,
17230                                InlineDiagnostic {
17231                                    message,
17232                                    group_id: diagnostic_entry.diagnostic.group_id,
17233                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17234                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17235                                    severity: diagnostic_entry.diagnostic.severity,
17236                                },
17237                            ),
17238                        );
17239                    }
17240                    inline_diagnostics
17241                })
17242                .await;
17243
17244            editor
17245                .update(cx, |editor, cx| {
17246                    editor.inline_diagnostics = new_inline_diagnostics;
17247                    cx.notify();
17248                })
17249                .ok();
17250        });
17251    }
17252
17253    fn pull_diagnostics(
17254        &mut self,
17255        buffer_id: Option<BufferId>,
17256        window: &Window,
17257        cx: &mut Context<Self>,
17258    ) -> Option<()> {
17259        if !self.mode().is_full() {
17260            return None;
17261        }
17262        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17263            .diagnostics
17264            .lsp_pull_diagnostics;
17265        if !pull_diagnostics_settings.enabled {
17266            return None;
17267        }
17268        let project = self.project()?.downgrade();
17269        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17270        let mut buffers = self.buffer.read(cx).all_buffers();
17271        if let Some(buffer_id) = buffer_id {
17272            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17273        }
17274
17275        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17276            cx.background_executor().timer(debounce).await;
17277
17278            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17279                buffers
17280                    .into_iter()
17281                    .filter_map(|buffer| {
17282                        project
17283                            .update(cx, |project, cx| {
17284                                project.lsp_store().update(cx, |lsp_store, cx| {
17285                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17286                                })
17287                            })
17288                            .ok()
17289                    })
17290                    .collect::<FuturesUnordered<_>>()
17291            }) else {
17292                return;
17293            };
17294
17295            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17296                match pull_task {
17297                    Ok(()) => {
17298                        if editor
17299                            .update_in(cx, |editor, window, cx| {
17300                                editor.update_diagnostics_state(window, cx);
17301                            })
17302                            .is_err()
17303                        {
17304                            return;
17305                        }
17306                    }
17307                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17308                }
17309            }
17310        });
17311
17312        Some(())
17313    }
17314
17315    pub fn set_selections_from_remote(
17316        &mut self,
17317        selections: Vec<Selection<Anchor>>,
17318        pending_selection: Option<Selection<Anchor>>,
17319        window: &mut Window,
17320        cx: &mut Context<Self>,
17321    ) {
17322        let old_cursor_position = self.selections.newest_anchor().head();
17323        self.selections.change_with(cx, |s| {
17324            s.select_anchors(selections);
17325            if let Some(pending_selection) = pending_selection {
17326                s.set_pending(pending_selection, SelectMode::Character);
17327            } else {
17328                s.clear_pending();
17329            }
17330        });
17331        self.selections_did_change(
17332            false,
17333            &old_cursor_position,
17334            SelectionEffects::default(),
17335            window,
17336            cx,
17337        );
17338    }
17339
17340    pub fn transact(
17341        &mut self,
17342        window: &mut Window,
17343        cx: &mut Context<Self>,
17344        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17345    ) -> Option<TransactionId> {
17346        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17347            this.start_transaction_at(Instant::now(), window, cx);
17348            update(this, window, cx);
17349            this.end_transaction_at(Instant::now(), cx)
17350        })
17351    }
17352
17353    pub fn start_transaction_at(
17354        &mut self,
17355        now: Instant,
17356        window: &mut Window,
17357        cx: &mut Context<Self>,
17358    ) -> Option<TransactionId> {
17359        self.end_selection(window, cx);
17360        if let Some(tx_id) = self
17361            .buffer
17362            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17363        {
17364            self.selection_history
17365                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17366            cx.emit(EditorEvent::TransactionBegun {
17367                transaction_id: tx_id,
17368            });
17369            Some(tx_id)
17370        } else {
17371            None
17372        }
17373    }
17374
17375    pub fn end_transaction_at(
17376        &mut self,
17377        now: Instant,
17378        cx: &mut Context<Self>,
17379    ) -> Option<TransactionId> {
17380        if let Some(transaction_id) = self
17381            .buffer
17382            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17383        {
17384            if let Some((_, end_selections)) =
17385                self.selection_history.transaction_mut(transaction_id)
17386            {
17387                *end_selections = Some(self.selections.disjoint_anchors());
17388            } else {
17389                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17390            }
17391
17392            cx.emit(EditorEvent::Edited { transaction_id });
17393            Some(transaction_id)
17394        } else {
17395            None
17396        }
17397    }
17398
17399    pub fn modify_transaction_selection_history(
17400        &mut self,
17401        transaction_id: TransactionId,
17402        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17403    ) -> bool {
17404        self.selection_history
17405            .transaction_mut(transaction_id)
17406            .map(modify)
17407            .is_some()
17408    }
17409
17410    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17411        if self.selection_mark_mode {
17412            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17413                s.move_with(|_, sel| {
17414                    sel.collapse_to(sel.head(), SelectionGoal::None);
17415                });
17416            })
17417        }
17418        self.selection_mark_mode = true;
17419        cx.notify();
17420    }
17421
17422    pub fn swap_selection_ends(
17423        &mut self,
17424        _: &actions::SwapSelectionEnds,
17425        window: &mut Window,
17426        cx: &mut Context<Self>,
17427    ) {
17428        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17429            s.move_with(|_, sel| {
17430                if sel.start != sel.end {
17431                    sel.reversed = !sel.reversed
17432                }
17433            });
17434        });
17435        self.request_autoscroll(Autoscroll::newest(), cx);
17436        cx.notify();
17437    }
17438
17439    pub fn toggle_focus(
17440        workspace: &mut Workspace,
17441        _: &actions::ToggleFocus,
17442        window: &mut Window,
17443        cx: &mut Context<Workspace>,
17444    ) {
17445        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17446            return;
17447        };
17448        workspace.activate_item(&item, true, true, window, cx);
17449    }
17450
17451    pub fn toggle_fold(
17452        &mut self,
17453        _: &actions::ToggleFold,
17454        window: &mut Window,
17455        cx: &mut Context<Self>,
17456    ) {
17457        if self.is_singleton(cx) {
17458            let selection = self.selections.newest::<Point>(cx);
17459
17460            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17461            let range = if selection.is_empty() {
17462                let point = selection.head().to_display_point(&display_map);
17463                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17464                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17465                    .to_point(&display_map);
17466                start..end
17467            } else {
17468                selection.range()
17469            };
17470            if display_map.folds_in_range(range).next().is_some() {
17471                self.unfold_lines(&Default::default(), window, cx)
17472            } else {
17473                self.fold(&Default::default(), window, cx)
17474            }
17475        } else {
17476            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17477            let buffer_ids: HashSet<_> = self
17478                .selections
17479                .disjoint_anchor_ranges()
17480                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17481                .collect();
17482
17483            let should_unfold = buffer_ids
17484                .iter()
17485                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17486
17487            for buffer_id in buffer_ids {
17488                if should_unfold {
17489                    self.unfold_buffer(buffer_id, cx);
17490                } else {
17491                    self.fold_buffer(buffer_id, cx);
17492                }
17493            }
17494        }
17495    }
17496
17497    pub fn toggle_fold_recursive(
17498        &mut self,
17499        _: &actions::ToggleFoldRecursive,
17500        window: &mut Window,
17501        cx: &mut Context<Self>,
17502    ) {
17503        let selection = self.selections.newest::<Point>(cx);
17504
17505        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17506        let range = if selection.is_empty() {
17507            let point = selection.head().to_display_point(&display_map);
17508            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17509            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17510                .to_point(&display_map);
17511            start..end
17512        } else {
17513            selection.range()
17514        };
17515        if display_map.folds_in_range(range).next().is_some() {
17516            self.unfold_recursive(&Default::default(), window, cx)
17517        } else {
17518            self.fold_recursive(&Default::default(), window, cx)
17519        }
17520    }
17521
17522    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17523        if self.is_singleton(cx) {
17524            let mut to_fold = Vec::new();
17525            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17526            let selections = self.selections.all_adjusted(cx);
17527
17528            for selection in selections {
17529                let range = selection.range().sorted();
17530                let buffer_start_row = range.start.row;
17531
17532                if range.start.row != range.end.row {
17533                    let mut found = false;
17534                    let mut row = range.start.row;
17535                    while row <= range.end.row {
17536                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17537                        {
17538                            found = true;
17539                            row = crease.range().end.row + 1;
17540                            to_fold.push(crease);
17541                        } else {
17542                            row += 1
17543                        }
17544                    }
17545                    if found {
17546                        continue;
17547                    }
17548                }
17549
17550                for row in (0..=range.start.row).rev() {
17551                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17552                        && crease.range().end.row >= buffer_start_row
17553                    {
17554                        to_fold.push(crease);
17555                        if row <= range.start.row {
17556                            break;
17557                        }
17558                    }
17559                }
17560            }
17561
17562            self.fold_creases(to_fold, true, window, cx);
17563        } else {
17564            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17565            let buffer_ids = self
17566                .selections
17567                .disjoint_anchor_ranges()
17568                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17569                .collect::<HashSet<_>>();
17570            for buffer_id in buffer_ids {
17571                self.fold_buffer(buffer_id, cx);
17572            }
17573        }
17574    }
17575
17576    pub fn toggle_fold_all(
17577        &mut self,
17578        _: &actions::ToggleFoldAll,
17579        window: &mut Window,
17580        cx: &mut Context<Self>,
17581    ) {
17582        if self.buffer.read(cx).is_singleton() {
17583            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17584            let has_folds = display_map
17585                .folds_in_range(0..display_map.buffer_snapshot.len())
17586                .next()
17587                .is_some();
17588
17589            if has_folds {
17590                self.unfold_all(&actions::UnfoldAll, window, cx);
17591            } else {
17592                self.fold_all(&actions::FoldAll, window, cx);
17593            }
17594        } else {
17595            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17596            let should_unfold = buffer_ids
17597                .iter()
17598                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17599
17600            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17601                editor
17602                    .update_in(cx, |editor, _, cx| {
17603                        for buffer_id in buffer_ids {
17604                            if should_unfold {
17605                                editor.unfold_buffer(buffer_id, cx);
17606                            } else {
17607                                editor.fold_buffer(buffer_id, cx);
17608                            }
17609                        }
17610                    })
17611                    .ok();
17612            });
17613        }
17614    }
17615
17616    fn fold_at_level(
17617        &mut self,
17618        fold_at: &FoldAtLevel,
17619        window: &mut Window,
17620        cx: &mut Context<Self>,
17621    ) {
17622        if !self.buffer.read(cx).is_singleton() {
17623            return;
17624        }
17625
17626        let fold_at_level = fold_at.0;
17627        let snapshot = self.buffer.read(cx).snapshot(cx);
17628        let mut to_fold = Vec::new();
17629        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17630
17631        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17632            while start_row < end_row {
17633                match self
17634                    .snapshot(window, cx)
17635                    .crease_for_buffer_row(MultiBufferRow(start_row))
17636                {
17637                    Some(crease) => {
17638                        let nested_start_row = crease.range().start.row + 1;
17639                        let nested_end_row = crease.range().end.row;
17640
17641                        if current_level < fold_at_level {
17642                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17643                        } else if current_level == fold_at_level {
17644                            to_fold.push(crease);
17645                        }
17646
17647                        start_row = nested_end_row + 1;
17648                    }
17649                    None => start_row += 1,
17650                }
17651            }
17652        }
17653
17654        self.fold_creases(to_fold, true, window, cx);
17655    }
17656
17657    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17658        if self.buffer.read(cx).is_singleton() {
17659            let mut fold_ranges = Vec::new();
17660            let snapshot = self.buffer.read(cx).snapshot(cx);
17661
17662            for row in 0..snapshot.max_row().0 {
17663                if let Some(foldable_range) = self
17664                    .snapshot(window, cx)
17665                    .crease_for_buffer_row(MultiBufferRow(row))
17666                {
17667                    fold_ranges.push(foldable_range);
17668                }
17669            }
17670
17671            self.fold_creases(fold_ranges, true, window, cx);
17672        } else {
17673            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17674                editor
17675                    .update_in(cx, |editor, _, cx| {
17676                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17677                            editor.fold_buffer(buffer_id, cx);
17678                        }
17679                    })
17680                    .ok();
17681            });
17682        }
17683    }
17684
17685    pub fn fold_function_bodies(
17686        &mut self,
17687        _: &actions::FoldFunctionBodies,
17688        window: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) {
17691        let snapshot = self.buffer.read(cx).snapshot(cx);
17692
17693        let ranges = snapshot
17694            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17695            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17696            .collect::<Vec<_>>();
17697
17698        let creases = ranges
17699            .into_iter()
17700            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17701            .collect();
17702
17703        self.fold_creases(creases, true, window, cx);
17704    }
17705
17706    pub fn fold_recursive(
17707        &mut self,
17708        _: &actions::FoldRecursive,
17709        window: &mut Window,
17710        cx: &mut Context<Self>,
17711    ) {
17712        let mut to_fold = Vec::new();
17713        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17714        let selections = self.selections.all_adjusted(cx);
17715
17716        for selection in selections {
17717            let range = selection.range().sorted();
17718            let buffer_start_row = range.start.row;
17719
17720            if range.start.row != range.end.row {
17721                let mut found = false;
17722                for row in range.start.row..=range.end.row {
17723                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17724                        found = true;
17725                        to_fold.push(crease);
17726                    }
17727                }
17728                if found {
17729                    continue;
17730                }
17731            }
17732
17733            for row in (0..=range.start.row).rev() {
17734                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17735                    if crease.range().end.row >= buffer_start_row {
17736                        to_fold.push(crease);
17737                    } else {
17738                        break;
17739                    }
17740                }
17741            }
17742        }
17743
17744        self.fold_creases(to_fold, true, window, cx);
17745    }
17746
17747    pub fn fold_at(
17748        &mut self,
17749        buffer_row: MultiBufferRow,
17750        window: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) {
17753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17754
17755        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17756            let autoscroll = self
17757                .selections
17758                .all::<Point>(cx)
17759                .iter()
17760                .any(|selection| crease.range().overlaps(&selection.range()));
17761
17762            self.fold_creases(vec![crease], autoscroll, window, cx);
17763        }
17764    }
17765
17766    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17767        if self.is_singleton(cx) {
17768            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17769            let buffer = &display_map.buffer_snapshot;
17770            let selections = self.selections.all::<Point>(cx);
17771            let ranges = selections
17772                .iter()
17773                .map(|s| {
17774                    let range = s.display_range(&display_map).sorted();
17775                    let mut start = range.start.to_point(&display_map);
17776                    let mut end = range.end.to_point(&display_map);
17777                    start.column = 0;
17778                    end.column = buffer.line_len(MultiBufferRow(end.row));
17779                    start..end
17780                })
17781                .collect::<Vec<_>>();
17782
17783            self.unfold_ranges(&ranges, true, true, cx);
17784        } else {
17785            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17786            let buffer_ids = self
17787                .selections
17788                .disjoint_anchor_ranges()
17789                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17790                .collect::<HashSet<_>>();
17791            for buffer_id in buffer_ids {
17792                self.unfold_buffer(buffer_id, cx);
17793            }
17794        }
17795    }
17796
17797    pub fn unfold_recursive(
17798        &mut self,
17799        _: &UnfoldRecursive,
17800        _window: &mut Window,
17801        cx: &mut Context<Self>,
17802    ) {
17803        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17804        let selections = self.selections.all::<Point>(cx);
17805        let ranges = selections
17806            .iter()
17807            .map(|s| {
17808                let mut range = s.display_range(&display_map).sorted();
17809                *range.start.column_mut() = 0;
17810                *range.end.column_mut() = display_map.line_len(range.end.row());
17811                let start = range.start.to_point(&display_map);
17812                let end = range.end.to_point(&display_map);
17813                start..end
17814            })
17815            .collect::<Vec<_>>();
17816
17817        self.unfold_ranges(&ranges, true, true, cx);
17818    }
17819
17820    pub fn unfold_at(
17821        &mut self,
17822        buffer_row: MultiBufferRow,
17823        _window: &mut Window,
17824        cx: &mut Context<Self>,
17825    ) {
17826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17827
17828        let intersection_range = Point::new(buffer_row.0, 0)
17829            ..Point::new(
17830                buffer_row.0,
17831                display_map.buffer_snapshot.line_len(buffer_row),
17832            );
17833
17834        let autoscroll = self
17835            .selections
17836            .all::<Point>(cx)
17837            .iter()
17838            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17839
17840        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17841    }
17842
17843    pub fn unfold_all(
17844        &mut self,
17845        _: &actions::UnfoldAll,
17846        _window: &mut Window,
17847        cx: &mut Context<Self>,
17848    ) {
17849        if self.buffer.read(cx).is_singleton() {
17850            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17851            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17852        } else {
17853            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17854                editor
17855                    .update(cx, |editor, cx| {
17856                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17857                            editor.unfold_buffer(buffer_id, cx);
17858                        }
17859                    })
17860                    .ok();
17861            });
17862        }
17863    }
17864
17865    pub fn fold_selected_ranges(
17866        &mut self,
17867        _: &FoldSelectedRanges,
17868        window: &mut Window,
17869        cx: &mut Context<Self>,
17870    ) {
17871        let selections = self.selections.all_adjusted(cx);
17872        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17873        let ranges = selections
17874            .into_iter()
17875            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17876            .collect::<Vec<_>>();
17877        self.fold_creases(ranges, true, window, cx);
17878    }
17879
17880    pub fn fold_ranges<T: ToOffset + Clone>(
17881        &mut self,
17882        ranges: Vec<Range<T>>,
17883        auto_scroll: bool,
17884        window: &mut Window,
17885        cx: &mut Context<Self>,
17886    ) {
17887        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17888        let ranges = ranges
17889            .into_iter()
17890            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17891            .collect::<Vec<_>>();
17892        self.fold_creases(ranges, auto_scroll, window, cx);
17893    }
17894
17895    pub fn fold_creases<T: ToOffset + Clone>(
17896        &mut self,
17897        creases: Vec<Crease<T>>,
17898        auto_scroll: bool,
17899        _window: &mut Window,
17900        cx: &mut Context<Self>,
17901    ) {
17902        if creases.is_empty() {
17903            return;
17904        }
17905
17906        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17907
17908        if auto_scroll {
17909            self.request_autoscroll(Autoscroll::fit(), cx);
17910        }
17911
17912        cx.notify();
17913
17914        self.scrollbar_marker_state.dirty = true;
17915        self.folds_did_change(cx);
17916    }
17917
17918    /// Removes any folds whose ranges intersect any of the given ranges.
17919    pub fn unfold_ranges<T: ToOffset + Clone>(
17920        &mut self,
17921        ranges: &[Range<T>],
17922        inclusive: bool,
17923        auto_scroll: bool,
17924        cx: &mut Context<Self>,
17925    ) {
17926        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17927            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17928        });
17929        self.folds_did_change(cx);
17930    }
17931
17932    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17933        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17934            return;
17935        }
17936        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17937        self.display_map.update(cx, |display_map, cx| {
17938            display_map.fold_buffers([buffer_id], cx)
17939        });
17940        cx.emit(EditorEvent::BufferFoldToggled {
17941            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17942            folded: true,
17943        });
17944        cx.notify();
17945    }
17946
17947    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17948        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17949            return;
17950        }
17951        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17952        self.display_map.update(cx, |display_map, cx| {
17953            display_map.unfold_buffers([buffer_id], cx);
17954        });
17955        cx.emit(EditorEvent::BufferFoldToggled {
17956            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17957            folded: false,
17958        });
17959        cx.notify();
17960    }
17961
17962    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17963        self.display_map.read(cx).is_buffer_folded(buffer)
17964    }
17965
17966    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17967        self.display_map.read(cx).folded_buffers()
17968    }
17969
17970    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17971        self.display_map.update(cx, |display_map, cx| {
17972            display_map.disable_header_for_buffer(buffer_id, cx);
17973        });
17974        cx.notify();
17975    }
17976
17977    /// Removes any folds with the given ranges.
17978    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17979        &mut self,
17980        ranges: &[Range<T>],
17981        type_id: TypeId,
17982        auto_scroll: bool,
17983        cx: &mut Context<Self>,
17984    ) {
17985        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17986            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17987        });
17988        self.folds_did_change(cx);
17989    }
17990
17991    fn remove_folds_with<T: ToOffset + Clone>(
17992        &mut self,
17993        ranges: &[Range<T>],
17994        auto_scroll: bool,
17995        cx: &mut Context<Self>,
17996        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17997    ) {
17998        if ranges.is_empty() {
17999            return;
18000        }
18001
18002        let mut buffers_affected = HashSet::default();
18003        let multi_buffer = self.buffer().read(cx);
18004        for range in ranges {
18005            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18006                buffers_affected.insert(buffer.read(cx).remote_id());
18007            };
18008        }
18009
18010        self.display_map.update(cx, update);
18011
18012        if auto_scroll {
18013            self.request_autoscroll(Autoscroll::fit(), cx);
18014        }
18015
18016        cx.notify();
18017        self.scrollbar_marker_state.dirty = true;
18018        self.active_indent_guides_state.dirty = true;
18019    }
18020
18021    pub fn update_renderer_widths(
18022        &mut self,
18023        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18024        cx: &mut Context<Self>,
18025    ) -> bool {
18026        self.display_map
18027            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18028    }
18029
18030    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18031        self.display_map.read(cx).fold_placeholder.clone()
18032    }
18033
18034    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18035        self.buffer.update(cx, |buffer, cx| {
18036            buffer.set_all_diff_hunks_expanded(cx);
18037        });
18038    }
18039
18040    pub fn expand_all_diff_hunks(
18041        &mut self,
18042        _: &ExpandAllDiffHunks,
18043        _window: &mut Window,
18044        cx: &mut Context<Self>,
18045    ) {
18046        self.buffer.update(cx, |buffer, cx| {
18047            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18048        });
18049    }
18050
18051    pub fn toggle_selected_diff_hunks(
18052        &mut self,
18053        _: &ToggleSelectedDiffHunks,
18054        _window: &mut Window,
18055        cx: &mut Context<Self>,
18056    ) {
18057        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18058        self.toggle_diff_hunks_in_ranges(ranges, cx);
18059    }
18060
18061    pub fn diff_hunks_in_ranges<'a>(
18062        &'a self,
18063        ranges: &'a [Range<Anchor>],
18064        buffer: &'a MultiBufferSnapshot,
18065    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18066        ranges.iter().flat_map(move |range| {
18067            let end_excerpt_id = range.end.excerpt_id;
18068            let range = range.to_point(buffer);
18069            let mut peek_end = range.end;
18070            if range.end.row < buffer.max_row().0 {
18071                peek_end = Point::new(range.end.row + 1, 0);
18072            }
18073            buffer
18074                .diff_hunks_in_range(range.start..peek_end)
18075                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18076        })
18077    }
18078
18079    pub fn has_stageable_diff_hunks_in_ranges(
18080        &self,
18081        ranges: &[Range<Anchor>],
18082        snapshot: &MultiBufferSnapshot,
18083    ) -> bool {
18084        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18085        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18086    }
18087
18088    pub fn toggle_staged_selected_diff_hunks(
18089        &mut self,
18090        _: &::git::ToggleStaged,
18091        _: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        let snapshot = self.buffer.read(cx).snapshot(cx);
18095        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18096        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18097        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18098    }
18099
18100    pub fn set_render_diff_hunk_controls(
18101        &mut self,
18102        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18103        cx: &mut Context<Self>,
18104    ) {
18105        self.render_diff_hunk_controls = render_diff_hunk_controls;
18106        cx.notify();
18107    }
18108
18109    pub fn stage_and_next(
18110        &mut self,
18111        _: &::git::StageAndNext,
18112        window: &mut Window,
18113        cx: &mut Context<Self>,
18114    ) {
18115        self.do_stage_or_unstage_and_next(true, window, cx);
18116    }
18117
18118    pub fn unstage_and_next(
18119        &mut self,
18120        _: &::git::UnstageAndNext,
18121        window: &mut Window,
18122        cx: &mut Context<Self>,
18123    ) {
18124        self.do_stage_or_unstage_and_next(false, window, cx);
18125    }
18126
18127    pub fn stage_or_unstage_diff_hunks(
18128        &mut self,
18129        stage: bool,
18130        ranges: Vec<Range<Anchor>>,
18131        cx: &mut Context<Self>,
18132    ) {
18133        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18134        cx.spawn(async move |this, cx| {
18135            task.await?;
18136            this.update(cx, |this, cx| {
18137                let snapshot = this.buffer.read(cx).snapshot(cx);
18138                let chunk_by = this
18139                    .diff_hunks_in_ranges(&ranges, &snapshot)
18140                    .chunk_by(|hunk| hunk.buffer_id);
18141                for (buffer_id, hunks) in &chunk_by {
18142                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18143                }
18144            })
18145        })
18146        .detach_and_log_err(cx);
18147    }
18148
18149    fn save_buffers_for_ranges_if_needed(
18150        &mut self,
18151        ranges: &[Range<Anchor>],
18152        cx: &mut Context<Editor>,
18153    ) -> Task<Result<()>> {
18154        let multibuffer = self.buffer.read(cx);
18155        let snapshot = multibuffer.read(cx);
18156        let buffer_ids: HashSet<_> = ranges
18157            .iter()
18158            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18159            .collect();
18160        drop(snapshot);
18161
18162        let mut buffers = HashSet::default();
18163        for buffer_id in buffer_ids {
18164            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18165                let buffer = buffer_entity.read(cx);
18166                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18167                {
18168                    buffers.insert(buffer_entity);
18169                }
18170            }
18171        }
18172
18173        if let Some(project) = &self.project {
18174            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18175        } else {
18176            Task::ready(Ok(()))
18177        }
18178    }
18179
18180    fn do_stage_or_unstage_and_next(
18181        &mut self,
18182        stage: bool,
18183        window: &mut Window,
18184        cx: &mut Context<Self>,
18185    ) {
18186        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18187
18188        if ranges.iter().any(|range| range.start != range.end) {
18189            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18190            return;
18191        }
18192
18193        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18194        let snapshot = self.snapshot(window, cx);
18195        let position = self.selections.newest::<Point>(cx).head();
18196        let mut row = snapshot
18197            .buffer_snapshot
18198            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18199            .find(|hunk| hunk.row_range.start.0 > position.row)
18200            .map(|hunk| hunk.row_range.start);
18201
18202        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18203        // Outside of the project diff editor, wrap around to the beginning.
18204        if !all_diff_hunks_expanded {
18205            row = row.or_else(|| {
18206                snapshot
18207                    .buffer_snapshot
18208                    .diff_hunks_in_range(Point::zero()..position)
18209                    .find(|hunk| hunk.row_range.end.0 < position.row)
18210                    .map(|hunk| hunk.row_range.start)
18211            });
18212        }
18213
18214        if let Some(row) = row {
18215            let destination = Point::new(row.0, 0);
18216            let autoscroll = Autoscroll::center();
18217
18218            self.unfold_ranges(&[destination..destination], false, false, cx);
18219            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18220                s.select_ranges([destination..destination]);
18221            });
18222        }
18223    }
18224
18225    fn do_stage_or_unstage(
18226        &self,
18227        stage: bool,
18228        buffer_id: BufferId,
18229        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18230        cx: &mut App,
18231    ) -> Option<()> {
18232        let project = self.project()?;
18233        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18234        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18235        let buffer_snapshot = buffer.read(cx).snapshot();
18236        let file_exists = buffer_snapshot
18237            .file()
18238            .is_some_and(|file| file.disk_state().exists());
18239        diff.update(cx, |diff, cx| {
18240            diff.stage_or_unstage_hunks(
18241                stage,
18242                &hunks
18243                    .map(|hunk| buffer_diff::DiffHunk {
18244                        buffer_range: hunk.buffer_range,
18245                        diff_base_byte_range: hunk.diff_base_byte_range,
18246                        secondary_status: hunk.secondary_status,
18247                        range: Point::zero()..Point::zero(), // unused
18248                    })
18249                    .collect::<Vec<_>>(),
18250                &buffer_snapshot,
18251                file_exists,
18252                cx,
18253            )
18254        });
18255        None
18256    }
18257
18258    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18259        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18260        self.buffer
18261            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18262    }
18263
18264    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18265        self.buffer.update(cx, |buffer, cx| {
18266            let ranges = vec![Anchor::min()..Anchor::max()];
18267            if !buffer.all_diff_hunks_expanded()
18268                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18269            {
18270                buffer.collapse_diff_hunks(ranges, cx);
18271                true
18272            } else {
18273                false
18274            }
18275        })
18276    }
18277
18278    fn toggle_diff_hunks_in_ranges(
18279        &mut self,
18280        ranges: Vec<Range<Anchor>>,
18281        cx: &mut Context<Editor>,
18282    ) {
18283        self.buffer.update(cx, |buffer, cx| {
18284            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18285            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18286        })
18287    }
18288
18289    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18290        self.buffer.update(cx, |buffer, cx| {
18291            let snapshot = buffer.snapshot(cx);
18292            let excerpt_id = range.end.excerpt_id;
18293            let point_range = range.to_point(&snapshot);
18294            let expand = !buffer.single_hunk_is_expanded(range, cx);
18295            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18296        })
18297    }
18298
18299    pub(crate) fn apply_all_diff_hunks(
18300        &mut self,
18301        _: &ApplyAllDiffHunks,
18302        window: &mut Window,
18303        cx: &mut Context<Self>,
18304    ) {
18305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18306
18307        let buffers = self.buffer.read(cx).all_buffers();
18308        for branch_buffer in buffers {
18309            branch_buffer.update(cx, |branch_buffer, cx| {
18310                branch_buffer.merge_into_base(Vec::new(), cx);
18311            });
18312        }
18313
18314        if let Some(project) = self.project.clone() {
18315            self.save(
18316                SaveOptions {
18317                    format: true,
18318                    autosave: false,
18319                },
18320                project,
18321                window,
18322                cx,
18323            )
18324            .detach_and_log_err(cx);
18325        }
18326    }
18327
18328    pub(crate) fn apply_selected_diff_hunks(
18329        &mut self,
18330        _: &ApplyDiffHunk,
18331        window: &mut Window,
18332        cx: &mut Context<Self>,
18333    ) {
18334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18335        let snapshot = self.snapshot(window, cx);
18336        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18337        let mut ranges_by_buffer = HashMap::default();
18338        self.transact(window, cx, |editor, _window, cx| {
18339            for hunk in hunks {
18340                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18341                    ranges_by_buffer
18342                        .entry(buffer.clone())
18343                        .or_insert_with(Vec::new)
18344                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18345                }
18346            }
18347
18348            for (buffer, ranges) in ranges_by_buffer {
18349                buffer.update(cx, |buffer, cx| {
18350                    buffer.merge_into_base(ranges, cx);
18351                });
18352            }
18353        });
18354
18355        if let Some(project) = self.project.clone() {
18356            self.save(
18357                SaveOptions {
18358                    format: true,
18359                    autosave: false,
18360                },
18361                project,
18362                window,
18363                cx,
18364            )
18365            .detach_and_log_err(cx);
18366        }
18367    }
18368
18369    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18370        if hovered != self.gutter_hovered {
18371            self.gutter_hovered = hovered;
18372            cx.notify();
18373        }
18374    }
18375
18376    pub fn insert_blocks(
18377        &mut self,
18378        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18379        autoscroll: Option<Autoscroll>,
18380        cx: &mut Context<Self>,
18381    ) -> Vec<CustomBlockId> {
18382        let blocks = self
18383            .display_map
18384            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18385        if let Some(autoscroll) = autoscroll {
18386            self.request_autoscroll(autoscroll, cx);
18387        }
18388        cx.notify();
18389        blocks
18390    }
18391
18392    pub fn resize_blocks(
18393        &mut self,
18394        heights: HashMap<CustomBlockId, u32>,
18395        autoscroll: Option<Autoscroll>,
18396        cx: &mut Context<Self>,
18397    ) {
18398        self.display_map
18399            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18400        if let Some(autoscroll) = autoscroll {
18401            self.request_autoscroll(autoscroll, cx);
18402        }
18403        cx.notify();
18404    }
18405
18406    pub fn replace_blocks(
18407        &mut self,
18408        renderers: HashMap<CustomBlockId, RenderBlock>,
18409        autoscroll: Option<Autoscroll>,
18410        cx: &mut Context<Self>,
18411    ) {
18412        self.display_map
18413            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18414        if let Some(autoscroll) = autoscroll {
18415            self.request_autoscroll(autoscroll, cx);
18416        }
18417        cx.notify();
18418    }
18419
18420    pub fn remove_blocks(
18421        &mut self,
18422        block_ids: HashSet<CustomBlockId>,
18423        autoscroll: Option<Autoscroll>,
18424        cx: &mut Context<Self>,
18425    ) {
18426        self.display_map.update(cx, |display_map, cx| {
18427            display_map.remove_blocks(block_ids, cx)
18428        });
18429        if let Some(autoscroll) = autoscroll {
18430            self.request_autoscroll(autoscroll, cx);
18431        }
18432        cx.notify();
18433    }
18434
18435    pub fn row_for_block(
18436        &self,
18437        block_id: CustomBlockId,
18438        cx: &mut Context<Self>,
18439    ) -> Option<DisplayRow> {
18440        self.display_map
18441            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18442    }
18443
18444    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18445        self.focused_block = Some(focused_block);
18446    }
18447
18448    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18449        self.focused_block.take()
18450    }
18451
18452    pub fn insert_creases(
18453        &mut self,
18454        creases: impl IntoIterator<Item = Crease<Anchor>>,
18455        cx: &mut Context<Self>,
18456    ) -> Vec<CreaseId> {
18457        self.display_map
18458            .update(cx, |map, cx| map.insert_creases(creases, cx))
18459    }
18460
18461    pub fn remove_creases(
18462        &mut self,
18463        ids: impl IntoIterator<Item = CreaseId>,
18464        cx: &mut Context<Self>,
18465    ) -> Vec<(CreaseId, Range<Anchor>)> {
18466        self.display_map
18467            .update(cx, |map, cx| map.remove_creases(ids, cx))
18468    }
18469
18470    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18471        self.display_map
18472            .update(cx, |map, cx| map.snapshot(cx))
18473            .longest_row()
18474    }
18475
18476    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18477        self.display_map
18478            .update(cx, |map, cx| map.snapshot(cx))
18479            .max_point()
18480    }
18481
18482    pub fn text(&self, cx: &App) -> String {
18483        self.buffer.read(cx).read(cx).text()
18484    }
18485
18486    pub fn is_empty(&self, cx: &App) -> bool {
18487        self.buffer.read(cx).read(cx).is_empty()
18488    }
18489
18490    pub fn text_option(&self, cx: &App) -> Option<String> {
18491        let text = self.text(cx);
18492        let text = text.trim();
18493
18494        if text.is_empty() {
18495            return None;
18496        }
18497
18498        Some(text.to_string())
18499    }
18500
18501    pub fn set_text(
18502        &mut self,
18503        text: impl Into<Arc<str>>,
18504        window: &mut Window,
18505        cx: &mut Context<Self>,
18506    ) {
18507        self.transact(window, cx, |this, _, cx| {
18508            this.buffer
18509                .read(cx)
18510                .as_singleton()
18511                .expect("you can only call set_text on editors for singleton buffers")
18512                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18513        });
18514    }
18515
18516    pub fn display_text(&self, cx: &mut App) -> String {
18517        self.display_map
18518            .update(cx, |map, cx| map.snapshot(cx))
18519            .text()
18520    }
18521
18522    fn create_minimap(
18523        &self,
18524        minimap_settings: MinimapSettings,
18525        window: &mut Window,
18526        cx: &mut Context<Self>,
18527    ) -> Option<Entity<Self>> {
18528        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18529            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18530    }
18531
18532    fn initialize_new_minimap(
18533        &self,
18534        minimap_settings: MinimapSettings,
18535        window: &mut Window,
18536        cx: &mut Context<Self>,
18537    ) -> Entity<Self> {
18538        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18539
18540        let mut minimap = Editor::new_internal(
18541            EditorMode::Minimap {
18542                parent: cx.weak_entity(),
18543            },
18544            self.buffer.clone(),
18545            None,
18546            Some(self.display_map.clone()),
18547            window,
18548            cx,
18549        );
18550        minimap.scroll_manager.clone_state(&self.scroll_manager);
18551        minimap.set_text_style_refinement(TextStyleRefinement {
18552            font_size: Some(MINIMAP_FONT_SIZE),
18553            font_weight: Some(MINIMAP_FONT_WEIGHT),
18554            ..Default::default()
18555        });
18556        minimap.update_minimap_configuration(minimap_settings, cx);
18557        cx.new(|_| minimap)
18558    }
18559
18560    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18561        let current_line_highlight = minimap_settings
18562            .current_line_highlight
18563            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18564        self.set_current_line_highlight(Some(current_line_highlight));
18565    }
18566
18567    pub fn minimap(&self) -> Option<&Entity<Self>> {
18568        self.minimap
18569            .as_ref()
18570            .filter(|_| self.minimap_visibility.visible())
18571    }
18572
18573    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18574        let mut wrap_guides = smallvec![];
18575
18576        if self.show_wrap_guides == Some(false) {
18577            return wrap_guides;
18578        }
18579
18580        let settings = self.buffer.read(cx).language_settings(cx);
18581        if settings.show_wrap_guides {
18582            match self.soft_wrap_mode(cx) {
18583                SoftWrap::Column(soft_wrap) => {
18584                    wrap_guides.push((soft_wrap as usize, true));
18585                }
18586                SoftWrap::Bounded(soft_wrap) => {
18587                    wrap_guides.push((soft_wrap as usize, true));
18588                }
18589                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18590            }
18591            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18592        }
18593
18594        wrap_guides
18595    }
18596
18597    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18598        let settings = self.buffer.read(cx).language_settings(cx);
18599        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18600        match mode {
18601            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18602                SoftWrap::None
18603            }
18604            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18605            language_settings::SoftWrap::PreferredLineLength => {
18606                SoftWrap::Column(settings.preferred_line_length)
18607            }
18608            language_settings::SoftWrap::Bounded => {
18609                SoftWrap::Bounded(settings.preferred_line_length)
18610            }
18611        }
18612    }
18613
18614    pub fn set_soft_wrap_mode(
18615        &mut self,
18616        mode: language_settings::SoftWrap,
18617
18618        cx: &mut Context<Self>,
18619    ) {
18620        self.soft_wrap_mode_override = Some(mode);
18621        cx.notify();
18622    }
18623
18624    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18625        self.hard_wrap = hard_wrap;
18626        cx.notify();
18627    }
18628
18629    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18630        self.text_style_refinement = Some(style);
18631    }
18632
18633    /// called by the Element so we know what style we were most recently rendered with.
18634    pub(crate) fn set_style(
18635        &mut self,
18636        style: EditorStyle,
18637        window: &mut Window,
18638        cx: &mut Context<Self>,
18639    ) {
18640        // We intentionally do not inform the display map about the minimap style
18641        // so that wrapping is not recalculated and stays consistent for the editor
18642        // and its linked minimap.
18643        if !self.mode.is_minimap() {
18644            let rem_size = window.rem_size();
18645            self.display_map.update(cx, |map, cx| {
18646                map.set_font(
18647                    style.text.font(),
18648                    style.text.font_size.to_pixels(rem_size),
18649                    cx,
18650                )
18651            });
18652        }
18653        self.style = Some(style);
18654    }
18655
18656    pub fn style(&self) -> Option<&EditorStyle> {
18657        self.style.as_ref()
18658    }
18659
18660    // Called by the element. This method is not designed to be called outside of the editor
18661    // element's layout code because it does not notify when rewrapping is computed synchronously.
18662    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18663        self.display_map
18664            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18665    }
18666
18667    pub fn set_soft_wrap(&mut self) {
18668        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18669    }
18670
18671    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18672        if self.soft_wrap_mode_override.is_some() {
18673            self.soft_wrap_mode_override.take();
18674        } else {
18675            let soft_wrap = match self.soft_wrap_mode(cx) {
18676                SoftWrap::GitDiff => return,
18677                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18678                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18679                    language_settings::SoftWrap::None
18680                }
18681            };
18682            self.soft_wrap_mode_override = Some(soft_wrap);
18683        }
18684        cx.notify();
18685    }
18686
18687    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18688        let Some(workspace) = self.workspace() else {
18689            return;
18690        };
18691        let fs = workspace.read(cx).app_state().fs.clone();
18692        let current_show = TabBarSettings::get_global(cx).show;
18693        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18694            setting.show = Some(!current_show);
18695        });
18696    }
18697
18698    pub fn toggle_indent_guides(
18699        &mut self,
18700        _: &ToggleIndentGuides,
18701        _: &mut Window,
18702        cx: &mut Context<Self>,
18703    ) {
18704        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18705            self.buffer
18706                .read(cx)
18707                .language_settings(cx)
18708                .indent_guides
18709                .enabled
18710        });
18711        self.show_indent_guides = Some(!currently_enabled);
18712        cx.notify();
18713    }
18714
18715    fn should_show_indent_guides(&self) -> Option<bool> {
18716        self.show_indent_guides
18717    }
18718
18719    pub fn toggle_line_numbers(
18720        &mut self,
18721        _: &ToggleLineNumbers,
18722        _: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        let mut editor_settings = EditorSettings::get_global(cx).clone();
18726        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18727        EditorSettings::override_global(editor_settings, cx);
18728    }
18729
18730    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18731        if let Some(show_line_numbers) = self.show_line_numbers {
18732            return show_line_numbers;
18733        }
18734        EditorSettings::get_global(cx).gutter.line_numbers
18735    }
18736
18737    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18738        self.use_relative_line_numbers
18739            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18740    }
18741
18742    pub fn toggle_relative_line_numbers(
18743        &mut self,
18744        _: &ToggleRelativeLineNumbers,
18745        _: &mut Window,
18746        cx: &mut Context<Self>,
18747    ) {
18748        let is_relative = self.should_use_relative_line_numbers(cx);
18749        self.set_relative_line_number(Some(!is_relative), cx)
18750    }
18751
18752    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18753        self.use_relative_line_numbers = is_relative;
18754        cx.notify();
18755    }
18756
18757    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18758        self.show_gutter = show_gutter;
18759        cx.notify();
18760    }
18761
18762    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18763        self.show_scrollbars = ScrollbarAxes {
18764            horizontal: show,
18765            vertical: show,
18766        };
18767        cx.notify();
18768    }
18769
18770    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18771        self.show_scrollbars.vertical = show;
18772        cx.notify();
18773    }
18774
18775    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18776        self.show_scrollbars.horizontal = show;
18777        cx.notify();
18778    }
18779
18780    pub fn set_minimap_visibility(
18781        &mut self,
18782        minimap_visibility: MinimapVisibility,
18783        window: &mut Window,
18784        cx: &mut Context<Self>,
18785    ) {
18786        if self.minimap_visibility != minimap_visibility {
18787            if minimap_visibility.visible() && self.minimap.is_none() {
18788                let minimap_settings = EditorSettings::get_global(cx).minimap;
18789                self.minimap =
18790                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18791            }
18792            self.minimap_visibility = minimap_visibility;
18793            cx.notify();
18794        }
18795    }
18796
18797    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18798        self.set_show_scrollbars(false, cx);
18799        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18800    }
18801
18802    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18803        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18804    }
18805
18806    /// Normally the text in full mode and auto height editors is padded on the
18807    /// left side by roughly half a character width for improved hit testing.
18808    ///
18809    /// Use this method to disable this for cases where this is not wanted (e.g.
18810    /// if you want to align the editor text with some other text above or below)
18811    /// or if you want to add this padding to single-line editors.
18812    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18813        self.offset_content = offset_content;
18814        cx.notify();
18815    }
18816
18817    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18818        self.show_line_numbers = Some(show_line_numbers);
18819        cx.notify();
18820    }
18821
18822    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18823        self.disable_expand_excerpt_buttons = true;
18824        cx.notify();
18825    }
18826
18827    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18828        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18829        cx.notify();
18830    }
18831
18832    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18833        self.show_code_actions = Some(show_code_actions);
18834        cx.notify();
18835    }
18836
18837    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18838        self.show_runnables = Some(show_runnables);
18839        cx.notify();
18840    }
18841
18842    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18843        self.show_breakpoints = Some(show_breakpoints);
18844        cx.notify();
18845    }
18846
18847    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18848        if self.display_map.read(cx).masked != masked {
18849            self.display_map.update(cx, |map, _| map.masked = masked);
18850        }
18851        cx.notify()
18852    }
18853
18854    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18855        self.show_wrap_guides = Some(show_wrap_guides);
18856        cx.notify();
18857    }
18858
18859    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18860        self.show_indent_guides = Some(show_indent_guides);
18861        cx.notify();
18862    }
18863
18864    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18865        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18866            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18867                && let Some(dir) = file.abs_path(cx).parent()
18868            {
18869                return Some(dir.to_owned());
18870            }
18871
18872            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18873                return Some(project_path.path.to_path_buf());
18874            }
18875        }
18876
18877        None
18878    }
18879
18880    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18881        self.active_excerpt(cx)?
18882            .1
18883            .read(cx)
18884            .file()
18885            .and_then(|f| f.as_local())
18886    }
18887
18888    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18889        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18890            let buffer = buffer.read(cx);
18891            if let Some(project_path) = buffer.project_path(cx) {
18892                let project = self.project()?.read(cx);
18893                project.absolute_path(&project_path, cx)
18894            } else {
18895                buffer
18896                    .file()
18897                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18898            }
18899        })
18900    }
18901
18902    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18903        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18904            let project_path = buffer.read(cx).project_path(cx)?;
18905            let project = self.project()?.read(cx);
18906            let entry = project.entry_for_path(&project_path, cx)?;
18907            let path = entry.path.to_path_buf();
18908            Some(path)
18909        })
18910    }
18911
18912    pub fn reveal_in_finder(
18913        &mut self,
18914        _: &RevealInFileManager,
18915        _window: &mut Window,
18916        cx: &mut Context<Self>,
18917    ) {
18918        if let Some(target) = self.target_file(cx) {
18919            cx.reveal_path(&target.abs_path(cx));
18920        }
18921    }
18922
18923    pub fn copy_path(
18924        &mut self,
18925        _: &zed_actions::workspace::CopyPath,
18926        _window: &mut Window,
18927        cx: &mut Context<Self>,
18928    ) {
18929        if let Some(path) = self.target_file_abs_path(cx)
18930            && let Some(path) = path.to_str()
18931        {
18932            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18933        }
18934    }
18935
18936    pub fn copy_relative_path(
18937        &mut self,
18938        _: &zed_actions::workspace::CopyRelativePath,
18939        _window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) {
18942        if let Some(path) = self.target_file_path(cx)
18943            && let Some(path) = path.to_str()
18944        {
18945            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18946        }
18947    }
18948
18949    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18950        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18951            buffer.read(cx).project_path(cx)
18952        } else {
18953            None
18954        }
18955    }
18956
18957    // Returns true if the editor handled a go-to-line request
18958    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18959        maybe!({
18960            let breakpoint_store = self.breakpoint_store.as_ref()?;
18961
18962            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18963            else {
18964                self.clear_row_highlights::<ActiveDebugLine>();
18965                return None;
18966            };
18967
18968            let position = active_stack_frame.position;
18969            let buffer_id = position.buffer_id?;
18970            let snapshot = self
18971                .project
18972                .as_ref()?
18973                .read(cx)
18974                .buffer_for_id(buffer_id, cx)?
18975                .read(cx)
18976                .snapshot();
18977
18978            let mut handled = false;
18979            for (id, ExcerptRange { context, .. }) in
18980                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18981            {
18982                if context.start.cmp(&position, &snapshot).is_ge()
18983                    || context.end.cmp(&position, &snapshot).is_lt()
18984                {
18985                    continue;
18986                }
18987                let snapshot = self.buffer.read(cx).snapshot(cx);
18988                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18989
18990                handled = true;
18991                self.clear_row_highlights::<ActiveDebugLine>();
18992
18993                self.go_to_line::<ActiveDebugLine>(
18994                    multibuffer_anchor,
18995                    Some(cx.theme().colors().editor_debugger_active_line_background),
18996                    window,
18997                    cx,
18998                );
18999
19000                cx.notify();
19001            }
19002
19003            handled.then_some(())
19004        })
19005        .is_some()
19006    }
19007
19008    pub fn copy_file_name_without_extension(
19009        &mut self,
19010        _: &CopyFileNameWithoutExtension,
19011        _: &mut Window,
19012        cx: &mut Context<Self>,
19013    ) {
19014        if let Some(file) = self.target_file(cx)
19015            && let Some(file_stem) = file.path().file_stem()
19016            && let Some(name) = file_stem.to_str()
19017        {
19018            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19019        }
19020    }
19021
19022    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19023        if let Some(file) = self.target_file(cx)
19024            && let Some(file_name) = file.path().file_name()
19025            && let Some(name) = file_name.to_str()
19026        {
19027            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19028        }
19029    }
19030
19031    pub fn toggle_git_blame(
19032        &mut self,
19033        _: &::git::Blame,
19034        window: &mut Window,
19035        cx: &mut Context<Self>,
19036    ) {
19037        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19038
19039        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19040            self.start_git_blame(true, window, cx);
19041        }
19042
19043        cx.notify();
19044    }
19045
19046    pub fn toggle_git_blame_inline(
19047        &mut self,
19048        _: &ToggleGitBlameInline,
19049        window: &mut Window,
19050        cx: &mut Context<Self>,
19051    ) {
19052        self.toggle_git_blame_inline_internal(true, window, cx);
19053        cx.notify();
19054    }
19055
19056    pub fn open_git_blame_commit(
19057        &mut self,
19058        _: &OpenGitBlameCommit,
19059        window: &mut Window,
19060        cx: &mut Context<Self>,
19061    ) {
19062        self.open_git_blame_commit_internal(window, cx);
19063    }
19064
19065    fn open_git_blame_commit_internal(
19066        &mut self,
19067        window: &mut Window,
19068        cx: &mut Context<Self>,
19069    ) -> Option<()> {
19070        let blame = self.blame.as_ref()?;
19071        let snapshot = self.snapshot(window, cx);
19072        let cursor = self.selections.newest::<Point>(cx).head();
19073        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19074        let blame_entry = blame
19075            .update(cx, |blame, cx| {
19076                blame
19077                    .blame_for_rows(
19078                        &[RowInfo {
19079                            buffer_id: Some(buffer.remote_id()),
19080                            buffer_row: Some(point.row),
19081                            ..Default::default()
19082                        }],
19083                        cx,
19084                    )
19085                    .next()
19086            })
19087            .flatten()?;
19088        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19089        let repo = blame.read(cx).repository(cx)?;
19090        let workspace = self.workspace()?.downgrade();
19091        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19092        None
19093    }
19094
19095    pub fn git_blame_inline_enabled(&self) -> bool {
19096        self.git_blame_inline_enabled
19097    }
19098
19099    pub fn toggle_selection_menu(
19100        &mut self,
19101        _: &ToggleSelectionMenu,
19102        _: &mut Window,
19103        cx: &mut Context<Self>,
19104    ) {
19105        self.show_selection_menu = self
19106            .show_selection_menu
19107            .map(|show_selections_menu| !show_selections_menu)
19108            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19109
19110        cx.notify();
19111    }
19112
19113    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19114        self.show_selection_menu
19115            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19116    }
19117
19118    fn start_git_blame(
19119        &mut self,
19120        user_triggered: bool,
19121        window: &mut Window,
19122        cx: &mut Context<Self>,
19123    ) {
19124        if let Some(project) = self.project() {
19125            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
19126                return;
19127            };
19128
19129            if buffer.read(cx).file().is_none() {
19130                return;
19131            }
19132
19133            let focused = self.focus_handle(cx).contains_focused(window, cx);
19134
19135            let project = project.clone();
19136            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
19137            self.blame_subscription =
19138                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19139            self.blame = Some(blame);
19140        }
19141    }
19142
19143    fn toggle_git_blame_inline_internal(
19144        &mut self,
19145        user_triggered: bool,
19146        window: &mut Window,
19147        cx: &mut Context<Self>,
19148    ) {
19149        if self.git_blame_inline_enabled {
19150            self.git_blame_inline_enabled = false;
19151            self.show_git_blame_inline = false;
19152            self.show_git_blame_inline_delay_task.take();
19153        } else {
19154            self.git_blame_inline_enabled = true;
19155            self.start_git_blame_inline(user_triggered, window, cx);
19156        }
19157
19158        cx.notify();
19159    }
19160
19161    fn start_git_blame_inline(
19162        &mut self,
19163        user_triggered: bool,
19164        window: &mut Window,
19165        cx: &mut Context<Self>,
19166    ) {
19167        self.start_git_blame(user_triggered, window, cx);
19168
19169        if ProjectSettings::get_global(cx)
19170            .git
19171            .inline_blame_delay()
19172            .is_some()
19173        {
19174            self.start_inline_blame_timer(window, cx);
19175        } else {
19176            self.show_git_blame_inline = true
19177        }
19178    }
19179
19180    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19181        self.blame.as_ref()
19182    }
19183
19184    pub fn show_git_blame_gutter(&self) -> bool {
19185        self.show_git_blame_gutter
19186    }
19187
19188    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19189        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19190    }
19191
19192    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19193        self.show_git_blame_inline
19194            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19195            && !self.newest_selection_head_on_empty_line(cx)
19196            && self.has_blame_entries(cx)
19197    }
19198
19199    fn has_blame_entries(&self, cx: &App) -> bool {
19200        self.blame()
19201            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19202    }
19203
19204    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19205        let cursor_anchor = self.selections.newest_anchor().head();
19206
19207        let snapshot = self.buffer.read(cx).snapshot(cx);
19208        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19209
19210        snapshot.line_len(buffer_row) == 0
19211    }
19212
19213    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19214        let buffer_and_selection = maybe!({
19215            let selection = self.selections.newest::<Point>(cx);
19216            let selection_range = selection.range();
19217
19218            let multi_buffer = self.buffer().read(cx);
19219            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19220            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19221
19222            let (buffer, range, _) = if selection.reversed {
19223                buffer_ranges.first()
19224            } else {
19225                buffer_ranges.last()
19226            }?;
19227
19228            let selection = text::ToPoint::to_point(&range.start, buffer).row
19229                ..text::ToPoint::to_point(&range.end, buffer).row;
19230            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19231        });
19232
19233        let Some((buffer, selection)) = buffer_and_selection else {
19234            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19235        };
19236
19237        let Some(project) = self.project() else {
19238            return Task::ready(Err(anyhow!("editor does not have project")));
19239        };
19240
19241        project.update(cx, |project, cx| {
19242            project.get_permalink_to_line(&buffer, selection, cx)
19243        })
19244    }
19245
19246    pub fn copy_permalink_to_line(
19247        &mut self,
19248        _: &CopyPermalinkToLine,
19249        window: &mut Window,
19250        cx: &mut Context<Self>,
19251    ) {
19252        let permalink_task = self.get_permalink_to_line(cx);
19253        let workspace = self.workspace();
19254
19255        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19256            Ok(permalink) => {
19257                cx.update(|_, cx| {
19258                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19259                })
19260                .ok();
19261            }
19262            Err(err) => {
19263                let message = format!("Failed to copy permalink: {err}");
19264
19265                anyhow::Result::<()>::Err(err).log_err();
19266
19267                if let Some(workspace) = workspace {
19268                    workspace
19269                        .update_in(cx, |workspace, _, cx| {
19270                            struct CopyPermalinkToLine;
19271
19272                            workspace.show_toast(
19273                                Toast::new(
19274                                    NotificationId::unique::<CopyPermalinkToLine>(),
19275                                    message,
19276                                ),
19277                                cx,
19278                            )
19279                        })
19280                        .ok();
19281                }
19282            }
19283        })
19284        .detach();
19285    }
19286
19287    pub fn copy_file_location(
19288        &mut self,
19289        _: &CopyFileLocation,
19290        _: &mut Window,
19291        cx: &mut Context<Self>,
19292    ) {
19293        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19294        if let Some(file) = self.target_file(cx)
19295            && let Some(path) = file.path().to_str()
19296        {
19297            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19298        }
19299    }
19300
19301    pub fn open_permalink_to_line(
19302        &mut self,
19303        _: &OpenPermalinkToLine,
19304        window: &mut Window,
19305        cx: &mut Context<Self>,
19306    ) {
19307        let permalink_task = self.get_permalink_to_line(cx);
19308        let workspace = self.workspace();
19309
19310        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19311            Ok(permalink) => {
19312                cx.update(|_, cx| {
19313                    cx.open_url(permalink.as_ref());
19314                })
19315                .ok();
19316            }
19317            Err(err) => {
19318                let message = format!("Failed to open permalink: {err}");
19319
19320                anyhow::Result::<()>::Err(err).log_err();
19321
19322                if let Some(workspace) = workspace {
19323                    workspace
19324                        .update(cx, |workspace, cx| {
19325                            struct OpenPermalinkToLine;
19326
19327                            workspace.show_toast(
19328                                Toast::new(
19329                                    NotificationId::unique::<OpenPermalinkToLine>(),
19330                                    message,
19331                                ),
19332                                cx,
19333                            )
19334                        })
19335                        .ok();
19336                }
19337            }
19338        })
19339        .detach();
19340    }
19341
19342    pub fn insert_uuid_v4(
19343        &mut self,
19344        _: &InsertUuidV4,
19345        window: &mut Window,
19346        cx: &mut Context<Self>,
19347    ) {
19348        self.insert_uuid(UuidVersion::V4, window, cx);
19349    }
19350
19351    pub fn insert_uuid_v7(
19352        &mut self,
19353        _: &InsertUuidV7,
19354        window: &mut Window,
19355        cx: &mut Context<Self>,
19356    ) {
19357        self.insert_uuid(UuidVersion::V7, window, cx);
19358    }
19359
19360    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19361        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19362        self.transact(window, cx, |this, window, cx| {
19363            let edits = this
19364                .selections
19365                .all::<Point>(cx)
19366                .into_iter()
19367                .map(|selection| {
19368                    let uuid = match version {
19369                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19370                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19371                    };
19372
19373                    (selection.range(), uuid.to_string())
19374                });
19375            this.edit(edits, cx);
19376            this.refresh_edit_prediction(true, false, window, cx);
19377        });
19378    }
19379
19380    pub fn open_selections_in_multibuffer(
19381        &mut self,
19382        _: &OpenSelectionsInMultibuffer,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        let multibuffer = self.buffer.read(cx);
19387
19388        let Some(buffer) = multibuffer.as_singleton() else {
19389            return;
19390        };
19391
19392        let Some(workspace) = self.workspace() else {
19393            return;
19394        };
19395
19396        let title = multibuffer.title(cx).to_string();
19397
19398        let locations = self
19399            .selections
19400            .all_anchors(cx)
19401            .iter()
19402            .map(|selection| Location {
19403                buffer: buffer.clone(),
19404                range: selection.start.text_anchor..selection.end.text_anchor,
19405            })
19406            .collect::<Vec<_>>();
19407
19408        cx.spawn_in(window, async move |_, cx| {
19409            workspace.update_in(cx, |workspace, window, cx| {
19410                Self::open_locations_in_multibuffer(
19411                    workspace,
19412                    locations,
19413                    format!("Selections for '{title}'"),
19414                    false,
19415                    MultibufferSelectionMode::All,
19416                    window,
19417                    cx,
19418                );
19419            })
19420        })
19421        .detach();
19422    }
19423
19424    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19425    /// last highlight added will be used.
19426    ///
19427    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19428    pub fn highlight_rows<T: 'static>(
19429        &mut self,
19430        range: Range<Anchor>,
19431        color: Hsla,
19432        options: RowHighlightOptions,
19433        cx: &mut Context<Self>,
19434    ) {
19435        let snapshot = self.buffer().read(cx).snapshot(cx);
19436        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19437        let ix = row_highlights.binary_search_by(|highlight| {
19438            Ordering::Equal
19439                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19440                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19441        });
19442
19443        if let Err(mut ix) = ix {
19444            let index = post_inc(&mut self.highlight_order);
19445
19446            // If this range intersects with the preceding highlight, then merge it with
19447            // the preceding highlight. Otherwise insert a new highlight.
19448            let mut merged = false;
19449            if ix > 0 {
19450                let prev_highlight = &mut row_highlights[ix - 1];
19451                if prev_highlight
19452                    .range
19453                    .end
19454                    .cmp(&range.start, &snapshot)
19455                    .is_ge()
19456                {
19457                    ix -= 1;
19458                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19459                        prev_highlight.range.end = range.end;
19460                    }
19461                    merged = true;
19462                    prev_highlight.index = index;
19463                    prev_highlight.color = color;
19464                    prev_highlight.options = options;
19465                }
19466            }
19467
19468            if !merged {
19469                row_highlights.insert(
19470                    ix,
19471                    RowHighlight {
19472                        range,
19473                        index,
19474                        color,
19475                        options,
19476                        type_id: TypeId::of::<T>(),
19477                    },
19478                );
19479            }
19480
19481            // If any of the following highlights intersect with this one, merge them.
19482            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19483                let highlight = &row_highlights[ix];
19484                if next_highlight
19485                    .range
19486                    .start
19487                    .cmp(&highlight.range.end, &snapshot)
19488                    .is_le()
19489                {
19490                    if next_highlight
19491                        .range
19492                        .end
19493                        .cmp(&highlight.range.end, &snapshot)
19494                        .is_gt()
19495                    {
19496                        row_highlights[ix].range.end = next_highlight.range.end;
19497                    }
19498                    row_highlights.remove(ix + 1);
19499                } else {
19500                    break;
19501                }
19502            }
19503        }
19504    }
19505
19506    /// Remove any highlighted row ranges of the given type that intersect the
19507    /// given ranges.
19508    pub fn remove_highlighted_rows<T: 'static>(
19509        &mut self,
19510        ranges_to_remove: Vec<Range<Anchor>>,
19511        cx: &mut Context<Self>,
19512    ) {
19513        let snapshot = self.buffer().read(cx).snapshot(cx);
19514        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19515        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19516        row_highlights.retain(|highlight| {
19517            while let Some(range_to_remove) = ranges_to_remove.peek() {
19518                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19519                    Ordering::Less | Ordering::Equal => {
19520                        ranges_to_remove.next();
19521                    }
19522                    Ordering::Greater => {
19523                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19524                            Ordering::Less | Ordering::Equal => {
19525                                return false;
19526                            }
19527                            Ordering::Greater => break,
19528                        }
19529                    }
19530                }
19531            }
19532
19533            true
19534        })
19535    }
19536
19537    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19538    pub fn clear_row_highlights<T: 'static>(&mut self) {
19539        self.highlighted_rows.remove(&TypeId::of::<T>());
19540    }
19541
19542    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19543    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19544        self.highlighted_rows
19545            .get(&TypeId::of::<T>())
19546            .map_or(&[] as &[_], |vec| vec.as_slice())
19547            .iter()
19548            .map(|highlight| (highlight.range.clone(), highlight.color))
19549    }
19550
19551    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19552    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19553    /// Allows to ignore certain kinds of highlights.
19554    pub fn highlighted_display_rows(
19555        &self,
19556        window: &mut Window,
19557        cx: &mut App,
19558    ) -> BTreeMap<DisplayRow, LineHighlight> {
19559        let snapshot = self.snapshot(window, cx);
19560        let mut used_highlight_orders = HashMap::default();
19561        self.highlighted_rows
19562            .iter()
19563            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19564            .fold(
19565                BTreeMap::<DisplayRow, LineHighlight>::new(),
19566                |mut unique_rows, highlight| {
19567                    let start = highlight.range.start.to_display_point(&snapshot);
19568                    let end = highlight.range.end.to_display_point(&snapshot);
19569                    let start_row = start.row().0;
19570                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19571                        && end.column() == 0
19572                    {
19573                        end.row().0.saturating_sub(1)
19574                    } else {
19575                        end.row().0
19576                    };
19577                    for row in start_row..=end_row {
19578                        let used_index =
19579                            used_highlight_orders.entry(row).or_insert(highlight.index);
19580                        if highlight.index >= *used_index {
19581                            *used_index = highlight.index;
19582                            unique_rows.insert(
19583                                DisplayRow(row),
19584                                LineHighlight {
19585                                    include_gutter: highlight.options.include_gutter,
19586                                    border: None,
19587                                    background: highlight.color.into(),
19588                                    type_id: Some(highlight.type_id),
19589                                },
19590                            );
19591                        }
19592                    }
19593                    unique_rows
19594                },
19595            )
19596    }
19597
19598    pub fn highlighted_display_row_for_autoscroll(
19599        &self,
19600        snapshot: &DisplaySnapshot,
19601    ) -> Option<DisplayRow> {
19602        self.highlighted_rows
19603            .values()
19604            .flat_map(|highlighted_rows| highlighted_rows.iter())
19605            .filter_map(|highlight| {
19606                if highlight.options.autoscroll {
19607                    Some(highlight.range.start.to_display_point(snapshot).row())
19608                } else {
19609                    None
19610                }
19611            })
19612            .min()
19613    }
19614
19615    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19616        self.highlight_background::<SearchWithinRange>(
19617            ranges,
19618            |colors| colors.colors().editor_document_highlight_read_background,
19619            cx,
19620        )
19621    }
19622
19623    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19624        self.breadcrumb_header = Some(new_header);
19625    }
19626
19627    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19628        self.clear_background_highlights::<SearchWithinRange>(cx);
19629    }
19630
19631    pub fn highlight_background<T: 'static>(
19632        &mut self,
19633        ranges: &[Range<Anchor>],
19634        color_fetcher: fn(&Theme) -> Hsla,
19635        cx: &mut Context<Self>,
19636    ) {
19637        self.background_highlights.insert(
19638            HighlightKey::Type(TypeId::of::<T>()),
19639            (color_fetcher, Arc::from(ranges)),
19640        );
19641        self.scrollbar_marker_state.dirty = true;
19642        cx.notify();
19643    }
19644
19645    pub fn highlight_background_key<T: 'static>(
19646        &mut self,
19647        key: usize,
19648        ranges: &[Range<Anchor>],
19649        color_fetcher: fn(&Theme) -> Hsla,
19650        cx: &mut Context<Self>,
19651    ) {
19652        self.background_highlights.insert(
19653            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19654            (color_fetcher, Arc::from(ranges)),
19655        );
19656        self.scrollbar_marker_state.dirty = true;
19657        cx.notify();
19658    }
19659
19660    pub fn clear_background_highlights<T: 'static>(
19661        &mut self,
19662        cx: &mut Context<Self>,
19663    ) -> Option<BackgroundHighlight> {
19664        let text_highlights = self
19665            .background_highlights
19666            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19667        if !text_highlights.1.is_empty() {
19668            self.scrollbar_marker_state.dirty = true;
19669            cx.notify();
19670        }
19671        Some(text_highlights)
19672    }
19673
19674    pub fn highlight_gutter<T: 'static>(
19675        &mut self,
19676        ranges: impl Into<Vec<Range<Anchor>>>,
19677        color_fetcher: fn(&App) -> Hsla,
19678        cx: &mut Context<Self>,
19679    ) {
19680        self.gutter_highlights
19681            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19682        cx.notify();
19683    }
19684
19685    pub fn clear_gutter_highlights<T: 'static>(
19686        &mut self,
19687        cx: &mut Context<Self>,
19688    ) -> Option<GutterHighlight> {
19689        cx.notify();
19690        self.gutter_highlights.remove(&TypeId::of::<T>())
19691    }
19692
19693    pub fn insert_gutter_highlight<T: 'static>(
19694        &mut self,
19695        range: Range<Anchor>,
19696        color_fetcher: fn(&App) -> Hsla,
19697        cx: &mut Context<Self>,
19698    ) {
19699        let snapshot = self.buffer().read(cx).snapshot(cx);
19700        let mut highlights = self
19701            .gutter_highlights
19702            .remove(&TypeId::of::<T>())
19703            .map(|(_, highlights)| highlights)
19704            .unwrap_or_default();
19705        let ix = highlights.binary_search_by(|highlight| {
19706            Ordering::Equal
19707                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19708                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19709        });
19710        if let Err(ix) = ix {
19711            highlights.insert(ix, range);
19712        }
19713        self.gutter_highlights
19714            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19715    }
19716
19717    pub fn remove_gutter_highlights<T: 'static>(
19718        &mut self,
19719        ranges_to_remove: Vec<Range<Anchor>>,
19720        cx: &mut Context<Self>,
19721    ) {
19722        let snapshot = self.buffer().read(cx).snapshot(cx);
19723        let Some((color_fetcher, mut gutter_highlights)) =
19724            self.gutter_highlights.remove(&TypeId::of::<T>())
19725        else {
19726            return;
19727        };
19728        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19729        gutter_highlights.retain(|highlight| {
19730            while let Some(range_to_remove) = ranges_to_remove.peek() {
19731                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19732                    Ordering::Less | Ordering::Equal => {
19733                        ranges_to_remove.next();
19734                    }
19735                    Ordering::Greater => {
19736                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19737                            Ordering::Less | Ordering::Equal => {
19738                                return false;
19739                            }
19740                            Ordering::Greater => break,
19741                        }
19742                    }
19743                }
19744            }
19745
19746            true
19747        });
19748        self.gutter_highlights
19749            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19750    }
19751
19752    #[cfg(feature = "test-support")]
19753    pub fn all_text_highlights(
19754        &self,
19755        window: &mut Window,
19756        cx: &mut Context<Self>,
19757    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19758        let snapshot = self.snapshot(window, cx);
19759        self.display_map.update(cx, |display_map, _| {
19760            display_map
19761                .all_text_highlights()
19762                .map(|highlight| {
19763                    let (style, ranges) = highlight.as_ref();
19764                    (
19765                        *style,
19766                        ranges
19767                            .iter()
19768                            .map(|range| range.clone().to_display_points(&snapshot))
19769                            .collect(),
19770                    )
19771                })
19772                .collect()
19773        })
19774    }
19775
19776    #[cfg(feature = "test-support")]
19777    pub fn all_text_background_highlights(
19778        &self,
19779        window: &mut Window,
19780        cx: &mut Context<Self>,
19781    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19782        let snapshot = self.snapshot(window, cx);
19783        let buffer = &snapshot.buffer_snapshot;
19784        let start = buffer.anchor_before(0);
19785        let end = buffer.anchor_after(buffer.len());
19786        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19787    }
19788
19789    #[cfg(feature = "test-support")]
19790    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19791        let snapshot = self.buffer().read(cx).snapshot(cx);
19792
19793        let highlights = self
19794            .background_highlights
19795            .get(&HighlightKey::Type(TypeId::of::<
19796                items::BufferSearchHighlights,
19797            >()));
19798
19799        if let Some((_color, ranges)) = highlights {
19800            ranges
19801                .iter()
19802                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19803                .collect_vec()
19804        } else {
19805            vec![]
19806        }
19807    }
19808
19809    fn document_highlights_for_position<'a>(
19810        &'a self,
19811        position: Anchor,
19812        buffer: &'a MultiBufferSnapshot,
19813    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19814        let read_highlights = self
19815            .background_highlights
19816            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19817            .map(|h| &h.1);
19818        let write_highlights = self
19819            .background_highlights
19820            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19821            .map(|h| &h.1);
19822        let left_position = position.bias_left(buffer);
19823        let right_position = position.bias_right(buffer);
19824        read_highlights
19825            .into_iter()
19826            .chain(write_highlights)
19827            .flat_map(move |ranges| {
19828                let start_ix = match ranges.binary_search_by(|probe| {
19829                    let cmp = probe.end.cmp(&left_position, buffer);
19830                    if cmp.is_ge() {
19831                        Ordering::Greater
19832                    } else {
19833                        Ordering::Less
19834                    }
19835                }) {
19836                    Ok(i) | Err(i) => i,
19837                };
19838
19839                ranges[start_ix..]
19840                    .iter()
19841                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19842            })
19843    }
19844
19845    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19846        self.background_highlights
19847            .get(&HighlightKey::Type(TypeId::of::<T>()))
19848            .is_some_and(|(_, highlights)| !highlights.is_empty())
19849    }
19850
19851    pub fn background_highlights_in_range(
19852        &self,
19853        search_range: Range<Anchor>,
19854        display_snapshot: &DisplaySnapshot,
19855        theme: &Theme,
19856    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19857        let mut results = Vec::new();
19858        for (color_fetcher, ranges) in self.background_highlights.values() {
19859            let color = color_fetcher(theme);
19860            let start_ix = match ranges.binary_search_by(|probe| {
19861                let cmp = probe
19862                    .end
19863                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19864                if cmp.is_gt() {
19865                    Ordering::Greater
19866                } else {
19867                    Ordering::Less
19868                }
19869            }) {
19870                Ok(i) | Err(i) => i,
19871            };
19872            for range in &ranges[start_ix..] {
19873                if range
19874                    .start
19875                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19876                    .is_ge()
19877                {
19878                    break;
19879                }
19880
19881                let start = range.start.to_display_point(display_snapshot);
19882                let end = range.end.to_display_point(display_snapshot);
19883                results.push((start..end, color))
19884            }
19885        }
19886        results
19887    }
19888
19889    pub fn background_highlight_row_ranges<T: 'static>(
19890        &self,
19891        search_range: Range<Anchor>,
19892        display_snapshot: &DisplaySnapshot,
19893        count: usize,
19894    ) -> Vec<RangeInclusive<DisplayPoint>> {
19895        let mut results = Vec::new();
19896        let Some((_, ranges)) = self
19897            .background_highlights
19898            .get(&HighlightKey::Type(TypeId::of::<T>()))
19899        else {
19900            return vec![];
19901        };
19902
19903        let start_ix = match ranges.binary_search_by(|probe| {
19904            let cmp = probe
19905                .end
19906                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19907            if cmp.is_gt() {
19908                Ordering::Greater
19909            } else {
19910                Ordering::Less
19911            }
19912        }) {
19913            Ok(i) | Err(i) => i,
19914        };
19915        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19916            if let (Some(start_display), Some(end_display)) = (start, end) {
19917                results.push(
19918                    start_display.to_display_point(display_snapshot)
19919                        ..=end_display.to_display_point(display_snapshot),
19920                );
19921            }
19922        };
19923        let mut start_row: Option<Point> = None;
19924        let mut end_row: Option<Point> = None;
19925        if ranges.len() > count {
19926            return Vec::new();
19927        }
19928        for range in &ranges[start_ix..] {
19929            if range
19930                .start
19931                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19932                .is_ge()
19933            {
19934                break;
19935            }
19936            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19937            if let Some(current_row) = &end_row
19938                && end.row == current_row.row
19939            {
19940                continue;
19941            }
19942            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19943            if start_row.is_none() {
19944                assert_eq!(end_row, None);
19945                start_row = Some(start);
19946                end_row = Some(end);
19947                continue;
19948            }
19949            if let Some(current_end) = end_row.as_mut() {
19950                if start.row > current_end.row + 1 {
19951                    push_region(start_row, end_row);
19952                    start_row = Some(start);
19953                    end_row = Some(end);
19954                } else {
19955                    // Merge two hunks.
19956                    *current_end = end;
19957                }
19958            } else {
19959                unreachable!();
19960            }
19961        }
19962        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19963        push_region(start_row, end_row);
19964        results
19965    }
19966
19967    pub fn gutter_highlights_in_range(
19968        &self,
19969        search_range: Range<Anchor>,
19970        display_snapshot: &DisplaySnapshot,
19971        cx: &App,
19972    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19973        let mut results = Vec::new();
19974        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19975            let color = color_fetcher(cx);
19976            let start_ix = match ranges.binary_search_by(|probe| {
19977                let cmp = probe
19978                    .end
19979                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19980                if cmp.is_gt() {
19981                    Ordering::Greater
19982                } else {
19983                    Ordering::Less
19984                }
19985            }) {
19986                Ok(i) | Err(i) => i,
19987            };
19988            for range in &ranges[start_ix..] {
19989                if range
19990                    .start
19991                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19992                    .is_ge()
19993                {
19994                    break;
19995                }
19996
19997                let start = range.start.to_display_point(display_snapshot);
19998                let end = range.end.to_display_point(display_snapshot);
19999                results.push((start..end, color))
20000            }
20001        }
20002        results
20003    }
20004
20005    /// Get the text ranges corresponding to the redaction query
20006    pub fn redacted_ranges(
20007        &self,
20008        search_range: Range<Anchor>,
20009        display_snapshot: &DisplaySnapshot,
20010        cx: &App,
20011    ) -> Vec<Range<DisplayPoint>> {
20012        display_snapshot
20013            .buffer_snapshot
20014            .redacted_ranges(search_range, |file| {
20015                if let Some(file) = file {
20016                    file.is_private()
20017                        && EditorSettings::get(
20018                            Some(SettingsLocation {
20019                                worktree_id: file.worktree_id(cx),
20020                                path: file.path().as_ref(),
20021                            }),
20022                            cx,
20023                        )
20024                        .redact_private_values
20025                } else {
20026                    false
20027                }
20028            })
20029            .map(|range| {
20030                range.start.to_display_point(display_snapshot)
20031                    ..range.end.to_display_point(display_snapshot)
20032            })
20033            .collect()
20034    }
20035
20036    pub fn highlight_text_key<T: 'static>(
20037        &mut self,
20038        key: usize,
20039        ranges: Vec<Range<Anchor>>,
20040        style: HighlightStyle,
20041        cx: &mut Context<Self>,
20042    ) {
20043        self.display_map.update(cx, |map, _| {
20044            map.highlight_text(
20045                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20046                ranges,
20047                style,
20048            );
20049        });
20050        cx.notify();
20051    }
20052
20053    pub fn highlight_text<T: 'static>(
20054        &mut self,
20055        ranges: Vec<Range<Anchor>>,
20056        style: HighlightStyle,
20057        cx: &mut Context<Self>,
20058    ) {
20059        self.display_map.update(cx, |map, _| {
20060            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20061        });
20062        cx.notify();
20063    }
20064
20065    pub(crate) fn highlight_inlays<T: 'static>(
20066        &mut self,
20067        highlights: Vec<InlayHighlight>,
20068        style: HighlightStyle,
20069        cx: &mut Context<Self>,
20070    ) {
20071        self.display_map.update(cx, |map, _| {
20072            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20073        });
20074        cx.notify();
20075    }
20076
20077    pub fn text_highlights<'a, T: 'static>(
20078        &'a self,
20079        cx: &'a App,
20080    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20081        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20082    }
20083
20084    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20085        let cleared = self
20086            .display_map
20087            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20088        if cleared {
20089            cx.notify();
20090        }
20091    }
20092
20093    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20094        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20095            && self.focus_handle.is_focused(window)
20096    }
20097
20098    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20099        self.show_cursor_when_unfocused = is_enabled;
20100        cx.notify();
20101    }
20102
20103    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20104        cx.notify();
20105    }
20106
20107    fn on_debug_session_event(
20108        &mut self,
20109        _session: Entity<Session>,
20110        event: &SessionEvent,
20111        cx: &mut Context<Self>,
20112    ) {
20113        if let SessionEvent::InvalidateInlineValue = event {
20114            self.refresh_inline_values(cx);
20115        }
20116    }
20117
20118    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20119        let Some(project) = self.project.clone() else {
20120            return;
20121        };
20122
20123        if !self.inline_value_cache.enabled {
20124            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20125            self.splice_inlays(&inlays, Vec::new(), cx);
20126            return;
20127        }
20128
20129        let current_execution_position = self
20130            .highlighted_rows
20131            .get(&TypeId::of::<ActiveDebugLine>())
20132            .and_then(|lines| lines.last().map(|line| line.range.end));
20133
20134        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20135            let inline_values = editor
20136                .update(cx, |editor, cx| {
20137                    let Some(current_execution_position) = current_execution_position else {
20138                        return Some(Task::ready(Ok(Vec::new())));
20139                    };
20140
20141                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20142                        let snapshot = buffer.snapshot(cx);
20143
20144                        let excerpt = snapshot.excerpt_containing(
20145                            current_execution_position..current_execution_position,
20146                        )?;
20147
20148                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20149                    })?;
20150
20151                    let range =
20152                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20153
20154                    project.inline_values(buffer, range, cx)
20155                })
20156                .ok()
20157                .flatten()?
20158                .await
20159                .context("refreshing debugger inlays")
20160                .log_err()?;
20161
20162            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20163
20164            for (buffer_id, inline_value) in inline_values
20165                .into_iter()
20166                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20167            {
20168                buffer_inline_values
20169                    .entry(buffer_id)
20170                    .or_default()
20171                    .push(inline_value);
20172            }
20173
20174            editor
20175                .update(cx, |editor, cx| {
20176                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20177                    let mut new_inlays = Vec::default();
20178
20179                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20180                        let buffer_id = buffer_snapshot.remote_id();
20181                        buffer_inline_values
20182                            .get(&buffer_id)
20183                            .into_iter()
20184                            .flatten()
20185                            .for_each(|hint| {
20186                                let inlay = Inlay::debugger(
20187                                    post_inc(&mut editor.next_inlay_id),
20188                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20189                                    hint.text(),
20190                                );
20191                                if !inlay.text.chars().contains(&'\n') {
20192                                    new_inlays.push(inlay);
20193                                }
20194                            });
20195                    }
20196
20197                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20198                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20199
20200                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20201                })
20202                .ok()?;
20203            Some(())
20204        });
20205    }
20206
20207    fn on_buffer_event(
20208        &mut self,
20209        multibuffer: &Entity<MultiBuffer>,
20210        event: &multi_buffer::Event,
20211        window: &mut Window,
20212        cx: &mut Context<Self>,
20213    ) {
20214        match event {
20215            multi_buffer::Event::Edited {
20216                singleton_buffer_edited,
20217                edited_buffer,
20218            } => {
20219                self.scrollbar_marker_state.dirty = true;
20220                self.active_indent_guides_state.dirty = true;
20221                self.refresh_active_diagnostics(cx);
20222                self.refresh_code_actions(window, cx);
20223                self.refresh_selected_text_highlights(true, window, cx);
20224                self.refresh_single_line_folds(window, cx);
20225                refresh_matching_bracket_highlights(self, window, cx);
20226                if self.has_active_edit_prediction() {
20227                    self.update_visible_edit_prediction(window, cx);
20228                }
20229                if let Some(project) = self.project.as_ref()
20230                    && let Some(edited_buffer) = edited_buffer
20231                {
20232                    project.update(cx, |project, cx| {
20233                        self.registered_buffers
20234                            .entry(edited_buffer.read(cx).remote_id())
20235                            .or_insert_with(|| {
20236                                project.register_buffer_with_language_servers(edited_buffer, cx)
20237                            });
20238                    });
20239                }
20240                cx.emit(EditorEvent::BufferEdited);
20241                cx.emit(SearchEvent::MatchesInvalidated);
20242
20243                if let Some(buffer) = edited_buffer {
20244                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20245                }
20246
20247                if *singleton_buffer_edited {
20248                    if let Some(buffer) = edited_buffer
20249                        && buffer.read(cx).file().is_none()
20250                    {
20251                        cx.emit(EditorEvent::TitleChanged);
20252                    }
20253                    if let Some(project) = &self.project {
20254                        #[allow(clippy::mutable_key_type)]
20255                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20256                            multibuffer
20257                                .all_buffers()
20258                                .into_iter()
20259                                .filter_map(|buffer| {
20260                                    buffer.update(cx, |buffer, cx| {
20261                                        let language = buffer.language()?;
20262                                        let should_discard = project.update(cx, |project, cx| {
20263                                            project.is_local()
20264                                                && !project.has_language_servers_for(buffer, cx)
20265                                        });
20266                                        should_discard.not().then_some(language.clone())
20267                                    })
20268                                })
20269                                .collect::<HashSet<_>>()
20270                        });
20271                        if !languages_affected.is_empty() {
20272                            self.refresh_inlay_hints(
20273                                InlayHintRefreshReason::BufferEdited(languages_affected),
20274                                cx,
20275                            );
20276                        }
20277                    }
20278                }
20279
20280                let Some(project) = &self.project else { return };
20281                let (telemetry, is_via_ssh) = {
20282                    let project = project.read(cx);
20283                    let telemetry = project.client().telemetry().clone();
20284                    let is_via_ssh = project.is_via_remote_server();
20285                    (telemetry, is_via_ssh)
20286                };
20287                refresh_linked_ranges(self, window, cx);
20288                telemetry.log_edit_event("editor", is_via_ssh);
20289            }
20290            multi_buffer::Event::ExcerptsAdded {
20291                buffer,
20292                predecessor,
20293                excerpts,
20294            } => {
20295                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20296                let buffer_id = buffer.read(cx).remote_id();
20297                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20298                    && let Some(project) = &self.project
20299                {
20300                    update_uncommitted_diff_for_buffer(
20301                        cx.entity(),
20302                        project,
20303                        [buffer.clone()],
20304                        self.buffer.clone(),
20305                        cx,
20306                    )
20307                    .detach();
20308                }
20309                self.update_lsp_data(false, Some(buffer_id), window, cx);
20310                cx.emit(EditorEvent::ExcerptsAdded {
20311                    buffer: buffer.clone(),
20312                    predecessor: *predecessor,
20313                    excerpts: excerpts.clone(),
20314                });
20315                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20316            }
20317            multi_buffer::Event::ExcerptsRemoved {
20318                ids,
20319                removed_buffer_ids,
20320            } => {
20321                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20322                let buffer = self.buffer.read(cx);
20323                self.registered_buffers
20324                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20325                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20326                cx.emit(EditorEvent::ExcerptsRemoved {
20327                    ids: ids.clone(),
20328                    removed_buffer_ids: removed_buffer_ids.clone(),
20329                });
20330            }
20331            multi_buffer::Event::ExcerptsEdited {
20332                excerpt_ids,
20333                buffer_ids,
20334            } => {
20335                self.display_map.update(cx, |map, cx| {
20336                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20337                });
20338                cx.emit(EditorEvent::ExcerptsEdited {
20339                    ids: excerpt_ids.clone(),
20340                });
20341            }
20342            multi_buffer::Event::ExcerptsExpanded { ids } => {
20343                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20344                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20345            }
20346            multi_buffer::Event::Reparsed(buffer_id) => {
20347                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20348                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20349
20350                cx.emit(EditorEvent::Reparsed(*buffer_id));
20351            }
20352            multi_buffer::Event::DiffHunksToggled => {
20353                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20354            }
20355            multi_buffer::Event::LanguageChanged(buffer_id) => {
20356                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20357                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20358                cx.emit(EditorEvent::Reparsed(*buffer_id));
20359                cx.notify();
20360            }
20361            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20362            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20363            multi_buffer::Event::FileHandleChanged
20364            | multi_buffer::Event::Reloaded
20365            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20366            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20367            multi_buffer::Event::DiagnosticsUpdated => {
20368                self.update_diagnostics_state(window, cx);
20369            }
20370            _ => {}
20371        };
20372    }
20373
20374    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20375        if !self.diagnostics_enabled() {
20376            return;
20377        }
20378        self.refresh_active_diagnostics(cx);
20379        self.refresh_inline_diagnostics(true, window, cx);
20380        self.scrollbar_marker_state.dirty = true;
20381        cx.notify();
20382    }
20383
20384    pub fn start_temporary_diff_override(&mut self) {
20385        self.load_diff_task.take();
20386        self.temporary_diff_override = true;
20387    }
20388
20389    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20390        self.temporary_diff_override = false;
20391        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20392        self.buffer.update(cx, |buffer, cx| {
20393            buffer.set_all_diff_hunks_collapsed(cx);
20394        });
20395
20396        if let Some(project) = self.project.clone() {
20397            self.load_diff_task = Some(
20398                update_uncommitted_diff_for_buffer(
20399                    cx.entity(),
20400                    &project,
20401                    self.buffer.read(cx).all_buffers(),
20402                    self.buffer.clone(),
20403                    cx,
20404                )
20405                .shared(),
20406            );
20407        }
20408    }
20409
20410    fn on_display_map_changed(
20411        &mut self,
20412        _: Entity<DisplayMap>,
20413        _: &mut Window,
20414        cx: &mut Context<Self>,
20415    ) {
20416        cx.notify();
20417    }
20418
20419    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20420        if self.diagnostics_enabled() {
20421            let new_severity = EditorSettings::get_global(cx)
20422                .diagnostics_max_severity
20423                .unwrap_or(DiagnosticSeverity::Hint);
20424            self.set_max_diagnostics_severity(new_severity, cx);
20425        }
20426        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20427        self.update_edit_prediction_settings(cx);
20428        self.refresh_edit_prediction(true, false, window, cx);
20429        self.refresh_inline_values(cx);
20430        self.refresh_inlay_hints(
20431            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20432                self.selections.newest_anchor().head(),
20433                &self.buffer.read(cx).snapshot(cx),
20434                cx,
20435            )),
20436            cx,
20437        );
20438
20439        let old_cursor_shape = self.cursor_shape;
20440        let old_show_breadcrumbs = self.show_breadcrumbs;
20441
20442        {
20443            let editor_settings = EditorSettings::get_global(cx);
20444            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20445            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20446            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20447            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20448        }
20449
20450        if old_cursor_shape != self.cursor_shape {
20451            cx.emit(EditorEvent::CursorShapeChanged);
20452        }
20453
20454        if old_show_breadcrumbs != self.show_breadcrumbs {
20455            cx.emit(EditorEvent::BreadcrumbsChanged);
20456        }
20457
20458        let project_settings = ProjectSettings::get_global(cx);
20459        self.serialize_dirty_buffers =
20460            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20461
20462        if self.mode.is_full() {
20463            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20464            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20465            if self.show_inline_diagnostics != show_inline_diagnostics {
20466                self.show_inline_diagnostics = show_inline_diagnostics;
20467                self.refresh_inline_diagnostics(false, window, cx);
20468            }
20469
20470            if self.git_blame_inline_enabled != inline_blame_enabled {
20471                self.toggle_git_blame_inline_internal(false, window, cx);
20472            }
20473
20474            let minimap_settings = EditorSettings::get_global(cx).minimap;
20475            if self.minimap_visibility != MinimapVisibility::Disabled {
20476                if self.minimap_visibility.settings_visibility()
20477                    != minimap_settings.minimap_enabled()
20478                {
20479                    self.set_minimap_visibility(
20480                        MinimapVisibility::for_mode(self.mode(), cx),
20481                        window,
20482                        cx,
20483                    );
20484                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20485                    minimap_entity.update(cx, |minimap_editor, cx| {
20486                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20487                    })
20488                }
20489            }
20490        }
20491
20492        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20493            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20494        }) {
20495            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20496                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20497            }
20498            self.refresh_colors(false, None, window, cx);
20499        }
20500
20501        cx.notify();
20502    }
20503
20504    pub fn set_searchable(&mut self, searchable: bool) {
20505        self.searchable = searchable;
20506    }
20507
20508    pub fn searchable(&self) -> bool {
20509        self.searchable
20510    }
20511
20512    fn open_proposed_changes_editor(
20513        &mut self,
20514        _: &OpenProposedChangesEditor,
20515        window: &mut Window,
20516        cx: &mut Context<Self>,
20517    ) {
20518        let Some(workspace) = self.workspace() else {
20519            cx.propagate();
20520            return;
20521        };
20522
20523        let selections = self.selections.all::<usize>(cx);
20524        let multi_buffer = self.buffer.read(cx);
20525        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20526        let mut new_selections_by_buffer = HashMap::default();
20527        for selection in selections {
20528            for (buffer, range, _) in
20529                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20530            {
20531                let mut range = range.to_point(buffer);
20532                range.start.column = 0;
20533                range.end.column = buffer.line_len(range.end.row);
20534                new_selections_by_buffer
20535                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20536                    .or_insert(Vec::new())
20537                    .push(range)
20538            }
20539        }
20540
20541        let proposed_changes_buffers = new_selections_by_buffer
20542            .into_iter()
20543            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20544            .collect::<Vec<_>>();
20545        let proposed_changes_editor = cx.new(|cx| {
20546            ProposedChangesEditor::new(
20547                "Proposed changes",
20548                proposed_changes_buffers,
20549                self.project.clone(),
20550                window,
20551                cx,
20552            )
20553        });
20554
20555        window.defer(cx, move |window, cx| {
20556            workspace.update(cx, |workspace, cx| {
20557                workspace.active_pane().update(cx, |pane, cx| {
20558                    pane.add_item(
20559                        Box::new(proposed_changes_editor),
20560                        true,
20561                        true,
20562                        None,
20563                        window,
20564                        cx,
20565                    );
20566                });
20567            });
20568        });
20569    }
20570
20571    pub fn open_excerpts_in_split(
20572        &mut self,
20573        _: &OpenExcerptsSplit,
20574        window: &mut Window,
20575        cx: &mut Context<Self>,
20576    ) {
20577        self.open_excerpts_common(None, true, window, cx)
20578    }
20579
20580    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20581        self.open_excerpts_common(None, false, window, cx)
20582    }
20583
20584    fn open_excerpts_common(
20585        &mut self,
20586        jump_data: Option<JumpData>,
20587        split: bool,
20588        window: &mut Window,
20589        cx: &mut Context<Self>,
20590    ) {
20591        let Some(workspace) = self.workspace() else {
20592            cx.propagate();
20593            return;
20594        };
20595
20596        if self.buffer.read(cx).is_singleton() {
20597            cx.propagate();
20598            return;
20599        }
20600
20601        let mut new_selections_by_buffer = HashMap::default();
20602        match &jump_data {
20603            Some(JumpData::MultiBufferPoint {
20604                excerpt_id,
20605                position,
20606                anchor,
20607                line_offset_from_top,
20608            }) => {
20609                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20610                if let Some(buffer) = multi_buffer_snapshot
20611                    .buffer_id_for_excerpt(*excerpt_id)
20612                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20613                {
20614                    let buffer_snapshot = buffer.read(cx).snapshot();
20615                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20616                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20617                    } else {
20618                        buffer_snapshot.clip_point(*position, Bias::Left)
20619                    };
20620                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20621                    new_selections_by_buffer.insert(
20622                        buffer,
20623                        (
20624                            vec![jump_to_offset..jump_to_offset],
20625                            Some(*line_offset_from_top),
20626                        ),
20627                    );
20628                }
20629            }
20630            Some(JumpData::MultiBufferRow {
20631                row,
20632                line_offset_from_top,
20633            }) => {
20634                let point = MultiBufferPoint::new(row.0, 0);
20635                if let Some((buffer, buffer_point, _)) =
20636                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20637                {
20638                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20639                    new_selections_by_buffer
20640                        .entry(buffer)
20641                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20642                        .0
20643                        .push(buffer_offset..buffer_offset)
20644                }
20645            }
20646            None => {
20647                let selections = self.selections.all::<usize>(cx);
20648                let multi_buffer = self.buffer.read(cx);
20649                for selection in selections {
20650                    for (snapshot, range, _, anchor) in multi_buffer
20651                        .snapshot(cx)
20652                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20653                    {
20654                        if let Some(anchor) = anchor {
20655                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20656                            else {
20657                                continue;
20658                            };
20659                            let offset = text::ToOffset::to_offset(
20660                                &anchor.text_anchor,
20661                                &buffer_handle.read(cx).snapshot(),
20662                            );
20663                            let range = offset..offset;
20664                            new_selections_by_buffer
20665                                .entry(buffer_handle)
20666                                .or_insert((Vec::new(), None))
20667                                .0
20668                                .push(range)
20669                        } else {
20670                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20671                            else {
20672                                continue;
20673                            };
20674                            new_selections_by_buffer
20675                                .entry(buffer_handle)
20676                                .or_insert((Vec::new(), None))
20677                                .0
20678                                .push(range)
20679                        }
20680                    }
20681                }
20682            }
20683        }
20684
20685        new_selections_by_buffer
20686            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20687
20688        if new_selections_by_buffer.is_empty() {
20689            return;
20690        }
20691
20692        // We defer the pane interaction because we ourselves are a workspace item
20693        // and activating a new item causes the pane to call a method on us reentrantly,
20694        // which panics if we're on the stack.
20695        window.defer(cx, move |window, cx| {
20696            workspace.update(cx, |workspace, cx| {
20697                let pane = if split {
20698                    workspace.adjacent_pane(window, cx)
20699                } else {
20700                    workspace.active_pane().clone()
20701                };
20702
20703                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20704                    let editor = buffer
20705                        .read(cx)
20706                        .file()
20707                        .is_none()
20708                        .then(|| {
20709                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20710                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20711                            // Instead, we try to activate the existing editor in the pane first.
20712                            let (editor, pane_item_index) =
20713                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20714                                    let editor = item.downcast::<Editor>()?;
20715                                    let singleton_buffer =
20716                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20717                                    if singleton_buffer == buffer {
20718                                        Some((editor, i))
20719                                    } else {
20720                                        None
20721                                    }
20722                                })?;
20723                            pane.update(cx, |pane, cx| {
20724                                pane.activate_item(pane_item_index, true, true, window, cx)
20725                            });
20726                            Some(editor)
20727                        })
20728                        .flatten()
20729                        .unwrap_or_else(|| {
20730                            workspace.open_project_item::<Self>(
20731                                pane.clone(),
20732                                buffer,
20733                                true,
20734                                true,
20735                                window,
20736                                cx,
20737                            )
20738                        });
20739
20740                    editor.update(cx, |editor, cx| {
20741                        let autoscroll = match scroll_offset {
20742                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20743                            None => Autoscroll::newest(),
20744                        };
20745                        let nav_history = editor.nav_history.take();
20746                        editor.change_selections(
20747                            SelectionEffects::scroll(autoscroll),
20748                            window,
20749                            cx,
20750                            |s| {
20751                                s.select_ranges(ranges);
20752                            },
20753                        );
20754                        editor.nav_history = nav_history;
20755                    });
20756                }
20757            })
20758        });
20759    }
20760
20761    // For now, don't allow opening excerpts in buffers that aren't backed by
20762    // regular project files.
20763    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20764        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20765    }
20766
20767    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20768        let snapshot = self.buffer.read(cx).read(cx);
20769        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20770        Some(
20771            ranges
20772                .iter()
20773                .map(move |range| {
20774                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20775                })
20776                .collect(),
20777        )
20778    }
20779
20780    fn selection_replacement_ranges(
20781        &self,
20782        range: Range<OffsetUtf16>,
20783        cx: &mut App,
20784    ) -> Vec<Range<OffsetUtf16>> {
20785        let selections = self.selections.all::<OffsetUtf16>(cx);
20786        let newest_selection = selections
20787            .iter()
20788            .max_by_key(|selection| selection.id)
20789            .unwrap();
20790        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20791        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20792        let snapshot = self.buffer.read(cx).read(cx);
20793        selections
20794            .into_iter()
20795            .map(|mut selection| {
20796                selection.start.0 =
20797                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20798                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20799                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20800                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20801            })
20802            .collect()
20803    }
20804
20805    fn report_editor_event(
20806        &self,
20807        reported_event: ReportEditorEvent,
20808        file_extension: Option<String>,
20809        cx: &App,
20810    ) {
20811        if cfg!(any(test, feature = "test-support")) {
20812            return;
20813        }
20814
20815        let Some(project) = &self.project else { return };
20816
20817        // If None, we are in a file without an extension
20818        let file = self
20819            .buffer
20820            .read(cx)
20821            .as_singleton()
20822            .and_then(|b| b.read(cx).file());
20823        let file_extension = file_extension.or(file
20824            .as_ref()
20825            .and_then(|file| Path::new(file.file_name(cx)).extension())
20826            .and_then(|e| e.to_str())
20827            .map(|a| a.to_string()));
20828
20829        let vim_mode = vim_enabled(cx);
20830
20831        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20832        let copilot_enabled = edit_predictions_provider
20833            == language::language_settings::EditPredictionProvider::Copilot;
20834        let copilot_enabled_for_language = self
20835            .buffer
20836            .read(cx)
20837            .language_settings(cx)
20838            .show_edit_predictions;
20839
20840        let project = project.read(cx);
20841        let event_type = reported_event.event_type();
20842
20843        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20844            telemetry::event!(
20845                event_type,
20846                type = if auto_saved {"autosave"} else {"manual"},
20847                file_extension,
20848                vim_mode,
20849                copilot_enabled,
20850                copilot_enabled_for_language,
20851                edit_predictions_provider,
20852                is_via_ssh = project.is_via_remote_server(),
20853            );
20854        } else {
20855            telemetry::event!(
20856                event_type,
20857                file_extension,
20858                vim_mode,
20859                copilot_enabled,
20860                copilot_enabled_for_language,
20861                edit_predictions_provider,
20862                is_via_ssh = project.is_via_remote_server(),
20863            );
20864        };
20865    }
20866
20867    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20868    /// with each line being an array of {text, highlight} objects.
20869    fn copy_highlight_json(
20870        &mut self,
20871        _: &CopyHighlightJson,
20872        window: &mut Window,
20873        cx: &mut Context<Self>,
20874    ) {
20875        #[derive(Serialize)]
20876        struct Chunk<'a> {
20877            text: String,
20878            highlight: Option<&'a str>,
20879        }
20880
20881        let snapshot = self.buffer.read(cx).snapshot(cx);
20882        let range = self
20883            .selected_text_range(false, window, cx)
20884            .and_then(|selection| {
20885                if selection.range.is_empty() {
20886                    None
20887                } else {
20888                    Some(selection.range)
20889                }
20890            })
20891            .unwrap_or_else(|| 0..snapshot.len());
20892
20893        let chunks = snapshot.chunks(range, true);
20894        let mut lines = Vec::new();
20895        let mut line: VecDeque<Chunk> = VecDeque::new();
20896
20897        let Some(style) = self.style.as_ref() else {
20898            return;
20899        };
20900
20901        for chunk in chunks {
20902            let highlight = chunk
20903                .syntax_highlight_id
20904                .and_then(|id| id.name(&style.syntax));
20905            let mut chunk_lines = chunk.text.split('\n').peekable();
20906            while let Some(text) = chunk_lines.next() {
20907                let mut merged_with_last_token = false;
20908                if let Some(last_token) = line.back_mut()
20909                    && last_token.highlight == highlight
20910                {
20911                    last_token.text.push_str(text);
20912                    merged_with_last_token = true;
20913                }
20914
20915                if !merged_with_last_token {
20916                    line.push_back(Chunk {
20917                        text: text.into(),
20918                        highlight,
20919                    });
20920                }
20921
20922                if chunk_lines.peek().is_some() {
20923                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20924                        line.pop_front();
20925                    }
20926                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20927                        line.pop_back();
20928                    }
20929
20930                    lines.push(mem::take(&mut line));
20931                }
20932            }
20933        }
20934
20935        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20936            return;
20937        };
20938        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20939    }
20940
20941    pub fn open_context_menu(
20942        &mut self,
20943        _: &OpenContextMenu,
20944        window: &mut Window,
20945        cx: &mut Context<Self>,
20946    ) {
20947        self.request_autoscroll(Autoscroll::newest(), cx);
20948        let position = self.selections.newest_display(cx).start;
20949        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20950    }
20951
20952    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20953        &self.inlay_hint_cache
20954    }
20955
20956    pub fn replay_insert_event(
20957        &mut self,
20958        text: &str,
20959        relative_utf16_range: Option<Range<isize>>,
20960        window: &mut Window,
20961        cx: &mut Context<Self>,
20962    ) {
20963        if !self.input_enabled {
20964            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20965            return;
20966        }
20967        if let Some(relative_utf16_range) = relative_utf16_range {
20968            let selections = self.selections.all::<OffsetUtf16>(cx);
20969            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20970                let new_ranges = selections.into_iter().map(|range| {
20971                    let start = OffsetUtf16(
20972                        range
20973                            .head()
20974                            .0
20975                            .saturating_add_signed(relative_utf16_range.start),
20976                    );
20977                    let end = OffsetUtf16(
20978                        range
20979                            .head()
20980                            .0
20981                            .saturating_add_signed(relative_utf16_range.end),
20982                    );
20983                    start..end
20984                });
20985                s.select_ranges(new_ranges);
20986            });
20987        }
20988
20989        self.handle_input(text, window, cx);
20990    }
20991
20992    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20993        let Some(provider) = self.semantics_provider.as_ref() else {
20994            return false;
20995        };
20996
20997        let mut supports = false;
20998        self.buffer().update(cx, |this, cx| {
20999            this.for_each_buffer(|buffer| {
21000                supports |= provider.supports_inlay_hints(buffer, cx);
21001            });
21002        });
21003
21004        supports
21005    }
21006
21007    pub fn is_focused(&self, window: &Window) -> bool {
21008        self.focus_handle.is_focused(window)
21009    }
21010
21011    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21012        cx.emit(EditorEvent::Focused);
21013
21014        if let Some(descendant) = self
21015            .last_focused_descendant
21016            .take()
21017            .and_then(|descendant| descendant.upgrade())
21018        {
21019            window.focus(&descendant);
21020        } else {
21021            if let Some(blame) = self.blame.as_ref() {
21022                blame.update(cx, GitBlame::focus)
21023            }
21024
21025            self.blink_manager.update(cx, BlinkManager::enable);
21026            self.show_cursor_names(window, cx);
21027            self.buffer.update(cx, |buffer, cx| {
21028                buffer.finalize_last_transaction(cx);
21029                if self.leader_id.is_none() {
21030                    buffer.set_active_selections(
21031                        &self.selections.disjoint_anchors(),
21032                        self.selections.line_mode,
21033                        self.cursor_shape,
21034                        cx,
21035                    );
21036                }
21037            });
21038        }
21039    }
21040
21041    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21042        cx.emit(EditorEvent::FocusedIn)
21043    }
21044
21045    fn handle_focus_out(
21046        &mut self,
21047        event: FocusOutEvent,
21048        _window: &mut Window,
21049        cx: &mut Context<Self>,
21050    ) {
21051        if event.blurred != self.focus_handle {
21052            self.last_focused_descendant = Some(event.blurred);
21053        }
21054        self.selection_drag_state = SelectionDragState::None;
21055        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21056    }
21057
21058    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21059        self.blink_manager.update(cx, BlinkManager::disable);
21060        self.buffer
21061            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21062
21063        if let Some(blame) = self.blame.as_ref() {
21064            blame.update(cx, GitBlame::blur)
21065        }
21066        if !self.hover_state.focused(window, cx) {
21067            hide_hover(self, cx);
21068        }
21069        if !self
21070            .context_menu
21071            .borrow()
21072            .as_ref()
21073            .is_some_and(|context_menu| context_menu.focused(window, cx))
21074        {
21075            self.hide_context_menu(window, cx);
21076        }
21077        self.discard_edit_prediction(false, cx);
21078        cx.emit(EditorEvent::Blurred);
21079        cx.notify();
21080    }
21081
21082    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21083        let mut pending: String = window
21084            .pending_input_keystrokes()
21085            .into_iter()
21086            .flatten()
21087            .filter_map(|keystroke| {
21088                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21089                    keystroke.key_char.clone()
21090                } else {
21091                    None
21092                }
21093            })
21094            .collect();
21095
21096        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21097            pending = "".to_string();
21098        }
21099
21100        let existing_pending = self
21101            .text_highlights::<PendingInput>(cx)
21102            .map(|(_, ranges)| ranges.to_vec());
21103        if existing_pending.is_none() && pending.is_empty() {
21104            return;
21105        }
21106        let transaction =
21107            self.transact(window, cx, |this, window, cx| {
21108                let selections = this.selections.all::<usize>(cx);
21109                let edits = selections
21110                    .iter()
21111                    .map(|selection| (selection.end..selection.end, pending.clone()));
21112                this.edit(edits, cx);
21113                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21114                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21115                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21116                    }));
21117                });
21118                if let Some(existing_ranges) = existing_pending {
21119                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21120                    this.edit(edits, cx);
21121                }
21122            });
21123
21124        let snapshot = self.snapshot(window, cx);
21125        let ranges = self
21126            .selections
21127            .all::<usize>(cx)
21128            .into_iter()
21129            .map(|selection| {
21130                snapshot.buffer_snapshot.anchor_after(selection.end)
21131                    ..snapshot
21132                        .buffer_snapshot
21133                        .anchor_before(selection.end + pending.len())
21134            })
21135            .collect();
21136
21137        if pending.is_empty() {
21138            self.clear_highlights::<PendingInput>(cx);
21139        } else {
21140            self.highlight_text::<PendingInput>(
21141                ranges,
21142                HighlightStyle {
21143                    underline: Some(UnderlineStyle {
21144                        thickness: px(1.),
21145                        color: None,
21146                        wavy: false,
21147                    }),
21148                    ..Default::default()
21149                },
21150                cx,
21151            );
21152        }
21153
21154        self.ime_transaction = self.ime_transaction.or(transaction);
21155        if let Some(transaction) = self.ime_transaction {
21156            self.buffer.update(cx, |buffer, cx| {
21157                buffer.group_until_transaction(transaction, cx);
21158            });
21159        }
21160
21161        if self.text_highlights::<PendingInput>(cx).is_none() {
21162            self.ime_transaction.take();
21163        }
21164    }
21165
21166    pub fn register_action_renderer(
21167        &mut self,
21168        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21169    ) -> Subscription {
21170        let id = self.next_editor_action_id.post_inc();
21171        self.editor_actions
21172            .borrow_mut()
21173            .insert(id, Box::new(listener));
21174
21175        let editor_actions = self.editor_actions.clone();
21176        Subscription::new(move || {
21177            editor_actions.borrow_mut().remove(&id);
21178        })
21179    }
21180
21181    pub fn register_action<A: Action>(
21182        &mut self,
21183        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21184    ) -> Subscription {
21185        let id = self.next_editor_action_id.post_inc();
21186        let listener = Arc::new(listener);
21187        self.editor_actions.borrow_mut().insert(
21188            id,
21189            Box::new(move |_, window, _| {
21190                let listener = listener.clone();
21191                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21192                    let action = action.downcast_ref().unwrap();
21193                    if phase == DispatchPhase::Bubble {
21194                        listener(action, window, cx)
21195                    }
21196                })
21197            }),
21198        );
21199
21200        let editor_actions = self.editor_actions.clone();
21201        Subscription::new(move || {
21202            editor_actions.borrow_mut().remove(&id);
21203        })
21204    }
21205
21206    pub fn file_header_size(&self) -> u32 {
21207        FILE_HEADER_HEIGHT
21208    }
21209
21210    pub fn restore(
21211        &mut self,
21212        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21213        window: &mut Window,
21214        cx: &mut Context<Self>,
21215    ) {
21216        let workspace = self.workspace();
21217        let project = self.project();
21218        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21219            let mut tasks = Vec::new();
21220            for (buffer_id, changes) in revert_changes {
21221                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21222                    buffer.update(cx, |buffer, cx| {
21223                        buffer.edit(
21224                            changes
21225                                .into_iter()
21226                                .map(|(range, text)| (range, text.to_string())),
21227                            None,
21228                            cx,
21229                        );
21230                    });
21231
21232                    if let Some(project) =
21233                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21234                    {
21235                        project.update(cx, |project, cx| {
21236                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21237                        })
21238                    }
21239                }
21240            }
21241            tasks
21242        });
21243        cx.spawn_in(window, async move |_, cx| {
21244            for (buffer, task) in save_tasks {
21245                let result = task.await;
21246                if result.is_err() {
21247                    let Some(path) = buffer
21248                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21249                        .ok()
21250                    else {
21251                        continue;
21252                    };
21253                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21254                        let Some(task) = cx
21255                            .update_window_entity(workspace, |workspace, window, cx| {
21256                                workspace
21257                                    .open_path_preview(path, None, false, false, false, window, cx)
21258                            })
21259                            .ok()
21260                        else {
21261                            continue;
21262                        };
21263                        task.await.log_err();
21264                    }
21265                }
21266            }
21267        })
21268        .detach();
21269        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21270            selections.refresh()
21271        });
21272    }
21273
21274    pub fn to_pixel_point(
21275        &self,
21276        source: multi_buffer::Anchor,
21277        editor_snapshot: &EditorSnapshot,
21278        window: &mut Window,
21279    ) -> Option<gpui::Point<Pixels>> {
21280        let source_point = source.to_display_point(editor_snapshot);
21281        self.display_to_pixel_point(source_point, editor_snapshot, window)
21282    }
21283
21284    pub fn display_to_pixel_point(
21285        &self,
21286        source: DisplayPoint,
21287        editor_snapshot: &EditorSnapshot,
21288        window: &mut Window,
21289    ) -> Option<gpui::Point<Pixels>> {
21290        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21291        let text_layout_details = self.text_layout_details(window);
21292        let scroll_top = text_layout_details
21293            .scroll_anchor
21294            .scroll_position(editor_snapshot)
21295            .y;
21296
21297        if source.row().as_f32() < scroll_top.floor() {
21298            return None;
21299        }
21300        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21301        let source_y = line_height * (source.row().as_f32() - scroll_top);
21302        Some(gpui::Point::new(source_x, source_y))
21303    }
21304
21305    pub fn has_visible_completions_menu(&self) -> bool {
21306        !self.edit_prediction_preview_is_active()
21307            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21308                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21309            })
21310    }
21311
21312    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21313        if self.mode.is_minimap() {
21314            return;
21315        }
21316        self.addons
21317            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21318    }
21319
21320    pub fn unregister_addon<T: Addon>(&mut self) {
21321        self.addons.remove(&std::any::TypeId::of::<T>());
21322    }
21323
21324    pub fn addon<T: Addon>(&self) -> Option<&T> {
21325        let type_id = std::any::TypeId::of::<T>();
21326        self.addons
21327            .get(&type_id)
21328            .and_then(|item| item.to_any().downcast_ref::<T>())
21329    }
21330
21331    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21332        let type_id = std::any::TypeId::of::<T>();
21333        self.addons
21334            .get_mut(&type_id)
21335            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21336    }
21337
21338    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21339        let text_layout_details = self.text_layout_details(window);
21340        let style = &text_layout_details.editor_style;
21341        let font_id = window.text_system().resolve_font(&style.text.font());
21342        let font_size = style.text.font_size.to_pixels(window.rem_size());
21343        let line_height = style.text.line_height_in_pixels(window.rem_size());
21344        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21345        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21346
21347        CharacterDimensions {
21348            em_width,
21349            em_advance,
21350            line_height,
21351        }
21352    }
21353
21354    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21355        self.load_diff_task.clone()
21356    }
21357
21358    fn read_metadata_from_db(
21359        &mut self,
21360        item_id: u64,
21361        workspace_id: WorkspaceId,
21362        window: &mut Window,
21363        cx: &mut Context<Editor>,
21364    ) {
21365        if self.is_singleton(cx)
21366            && !self.mode.is_minimap()
21367            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21368        {
21369            let buffer_snapshot = OnceCell::new();
21370
21371            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21372                && !folds.is_empty()
21373            {
21374                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21375                self.fold_ranges(
21376                    folds
21377                        .into_iter()
21378                        .map(|(start, end)| {
21379                            snapshot.clip_offset(start, Bias::Left)
21380                                ..snapshot.clip_offset(end, Bias::Right)
21381                        })
21382                        .collect(),
21383                    false,
21384                    window,
21385                    cx,
21386                );
21387            }
21388
21389            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21390                && !selections.is_empty()
21391            {
21392                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21393                // skip adding the initial selection to selection history
21394                self.selection_history.mode = SelectionHistoryMode::Skipping;
21395                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21396                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21397                        snapshot.clip_offset(start, Bias::Left)
21398                            ..snapshot.clip_offset(end, Bias::Right)
21399                    }));
21400                });
21401                self.selection_history.mode = SelectionHistoryMode::Normal;
21402            };
21403        }
21404
21405        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21406    }
21407
21408    fn update_lsp_data(
21409        &mut self,
21410        ignore_cache: bool,
21411        for_buffer: Option<BufferId>,
21412        window: &mut Window,
21413        cx: &mut Context<'_, Self>,
21414    ) {
21415        self.pull_diagnostics(for_buffer, window, cx);
21416        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21417    }
21418}
21419
21420fn vim_enabled(cx: &App) -> bool {
21421    cx.global::<SettingsStore>()
21422        .raw_user_settings()
21423        .get("vim_mode")
21424        == Some(&serde_json::Value::Bool(true))
21425}
21426
21427fn process_completion_for_edit(
21428    completion: &Completion,
21429    intent: CompletionIntent,
21430    buffer: &Entity<Buffer>,
21431    cursor_position: &text::Anchor,
21432    cx: &mut Context<Editor>,
21433) -> CompletionEdit {
21434    let buffer = buffer.read(cx);
21435    let buffer_snapshot = buffer.snapshot();
21436    let (snippet, new_text) = if completion.is_snippet() {
21437        // Workaround for typescript language server issues so that methods don't expand within
21438        // strings and functions with type expressions. The previous point is used because the query
21439        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21440        let mut snippet_source = completion.new_text.clone();
21441        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21442        previous_point.column = previous_point.column.saturating_sub(1);
21443        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21444            && scope.prefers_label_for_snippet_in_completion()
21445            && let Some(label) = completion.label()
21446            && matches!(
21447                completion.kind(),
21448                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21449            )
21450        {
21451            snippet_source = label;
21452        }
21453        match Snippet::parse(&snippet_source).log_err() {
21454            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21455            None => (None, completion.new_text.clone()),
21456        }
21457    } else {
21458        (None, completion.new_text.clone())
21459    };
21460
21461    let mut range_to_replace = {
21462        let replace_range = &completion.replace_range;
21463        if let CompletionSource::Lsp {
21464            insert_range: Some(insert_range),
21465            ..
21466        } = &completion.source
21467        {
21468            debug_assert_eq!(
21469                insert_range.start, replace_range.start,
21470                "insert_range and replace_range should start at the same position"
21471            );
21472            debug_assert!(
21473                insert_range
21474                    .start
21475                    .cmp(cursor_position, &buffer_snapshot)
21476                    .is_le(),
21477                "insert_range should start before or at cursor position"
21478            );
21479            debug_assert!(
21480                replace_range
21481                    .start
21482                    .cmp(cursor_position, &buffer_snapshot)
21483                    .is_le(),
21484                "replace_range should start before or at cursor position"
21485            );
21486
21487            let should_replace = match intent {
21488                CompletionIntent::CompleteWithInsert => false,
21489                CompletionIntent::CompleteWithReplace => true,
21490                CompletionIntent::Complete | CompletionIntent::Compose => {
21491                    let insert_mode =
21492                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21493                            .completions
21494                            .lsp_insert_mode;
21495                    match insert_mode {
21496                        LspInsertMode::Insert => false,
21497                        LspInsertMode::Replace => true,
21498                        LspInsertMode::ReplaceSubsequence => {
21499                            let mut text_to_replace = buffer.chars_for_range(
21500                                buffer.anchor_before(replace_range.start)
21501                                    ..buffer.anchor_after(replace_range.end),
21502                            );
21503                            let mut current_needle = text_to_replace.next();
21504                            for haystack_ch in completion.label.text.chars() {
21505                                if let Some(needle_ch) = current_needle
21506                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21507                                {
21508                                    current_needle = text_to_replace.next();
21509                                }
21510                            }
21511                            current_needle.is_none()
21512                        }
21513                        LspInsertMode::ReplaceSuffix => {
21514                            if replace_range
21515                                .end
21516                                .cmp(cursor_position, &buffer_snapshot)
21517                                .is_gt()
21518                            {
21519                                let range_after_cursor = *cursor_position..replace_range.end;
21520                                let text_after_cursor = buffer
21521                                    .text_for_range(
21522                                        buffer.anchor_before(range_after_cursor.start)
21523                                            ..buffer.anchor_after(range_after_cursor.end),
21524                                    )
21525                                    .collect::<String>()
21526                                    .to_ascii_lowercase();
21527                                completion
21528                                    .label
21529                                    .text
21530                                    .to_ascii_lowercase()
21531                                    .ends_with(&text_after_cursor)
21532                            } else {
21533                                true
21534                            }
21535                        }
21536                    }
21537                }
21538            };
21539
21540            if should_replace {
21541                replace_range.clone()
21542            } else {
21543                insert_range.clone()
21544            }
21545        } else {
21546            replace_range.clone()
21547        }
21548    };
21549
21550    if range_to_replace
21551        .end
21552        .cmp(cursor_position, &buffer_snapshot)
21553        .is_lt()
21554    {
21555        range_to_replace.end = *cursor_position;
21556    }
21557
21558    CompletionEdit {
21559        new_text,
21560        replace_range: range_to_replace.to_offset(buffer),
21561        snippet,
21562    }
21563}
21564
21565struct CompletionEdit {
21566    new_text: String,
21567    replace_range: Range<usize>,
21568    snippet: Option<Snippet>,
21569}
21570
21571fn insert_extra_newline_brackets(
21572    buffer: &MultiBufferSnapshot,
21573    range: Range<usize>,
21574    language: &language::LanguageScope,
21575) -> bool {
21576    let leading_whitespace_len = buffer
21577        .reversed_chars_at(range.start)
21578        .take_while(|c| c.is_whitespace() && *c != '\n')
21579        .map(|c| c.len_utf8())
21580        .sum::<usize>();
21581    let trailing_whitespace_len = buffer
21582        .chars_at(range.end)
21583        .take_while(|c| c.is_whitespace() && *c != '\n')
21584        .map(|c| c.len_utf8())
21585        .sum::<usize>();
21586    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21587
21588    language.brackets().any(|(pair, enabled)| {
21589        let pair_start = pair.start.trim_end();
21590        let pair_end = pair.end.trim_start();
21591
21592        enabled
21593            && pair.newline
21594            && buffer.contains_str_at(range.end, pair_end)
21595            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21596    })
21597}
21598
21599fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21600    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21601        [(buffer, range, _)] => (*buffer, range.clone()),
21602        _ => return false,
21603    };
21604    let pair = {
21605        let mut result: Option<BracketMatch> = None;
21606
21607        for pair in buffer
21608            .all_bracket_ranges(range.clone())
21609            .filter(move |pair| {
21610                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21611            })
21612        {
21613            let len = pair.close_range.end - pair.open_range.start;
21614
21615            if let Some(existing) = &result {
21616                let existing_len = existing.close_range.end - existing.open_range.start;
21617                if len > existing_len {
21618                    continue;
21619                }
21620            }
21621
21622            result = Some(pair);
21623        }
21624
21625        result
21626    };
21627    let Some(pair) = pair else {
21628        return false;
21629    };
21630    pair.newline_only
21631        && buffer
21632            .chars_for_range(pair.open_range.end..range.start)
21633            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21634            .all(|c| c.is_whitespace() && c != '\n')
21635}
21636
21637fn update_uncommitted_diff_for_buffer(
21638    editor: Entity<Editor>,
21639    project: &Entity<Project>,
21640    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21641    buffer: Entity<MultiBuffer>,
21642    cx: &mut App,
21643) -> Task<()> {
21644    let mut tasks = Vec::new();
21645    project.update(cx, |project, cx| {
21646        for buffer in buffers {
21647            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21648                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21649            }
21650        }
21651    });
21652    cx.spawn(async move |cx| {
21653        let diffs = future::join_all(tasks).await;
21654        if editor
21655            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21656            .unwrap_or(false)
21657        {
21658            return;
21659        }
21660
21661        buffer
21662            .update(cx, |buffer, cx| {
21663                for diff in diffs.into_iter().flatten() {
21664                    buffer.add_diff(diff, cx);
21665                }
21666            })
21667            .ok();
21668    })
21669}
21670
21671fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21672    let tab_size = tab_size.get() as usize;
21673    let mut width = offset;
21674
21675    for ch in text.chars() {
21676        width += if ch == '\t' {
21677            tab_size - (width % tab_size)
21678        } else {
21679            1
21680        };
21681    }
21682
21683    width - offset
21684}
21685
21686#[cfg(test)]
21687mod tests {
21688    use super::*;
21689
21690    #[test]
21691    fn test_string_size_with_expanded_tabs() {
21692        let nz = |val| NonZeroU32::new(val).unwrap();
21693        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21694        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21695        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21696        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21697        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21698        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21699        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21700        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21701    }
21702}
21703
21704/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21705struct WordBreakingTokenizer<'a> {
21706    input: &'a str,
21707}
21708
21709impl<'a> WordBreakingTokenizer<'a> {
21710    fn new(input: &'a str) -> Self {
21711        Self { input }
21712    }
21713}
21714
21715fn is_char_ideographic(ch: char) -> bool {
21716    use unicode_script::Script::*;
21717    use unicode_script::UnicodeScript;
21718    matches!(ch.script(), Han | Tangut | Yi)
21719}
21720
21721fn is_grapheme_ideographic(text: &str) -> bool {
21722    text.chars().any(is_char_ideographic)
21723}
21724
21725fn is_grapheme_whitespace(text: &str) -> bool {
21726    text.chars().any(|x| x.is_whitespace())
21727}
21728
21729fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21730    text.chars()
21731        .next()
21732        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21733}
21734
21735#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21736enum WordBreakToken<'a> {
21737    Word { token: &'a str, grapheme_len: usize },
21738    InlineWhitespace { token: &'a str, grapheme_len: usize },
21739    Newline,
21740}
21741
21742impl<'a> Iterator for WordBreakingTokenizer<'a> {
21743    /// Yields a span, the count of graphemes in the token, and whether it was
21744    /// whitespace. Note that it also breaks at word boundaries.
21745    type Item = WordBreakToken<'a>;
21746
21747    fn next(&mut self) -> Option<Self::Item> {
21748        use unicode_segmentation::UnicodeSegmentation;
21749        if self.input.is_empty() {
21750            return None;
21751        }
21752
21753        let mut iter = self.input.graphemes(true).peekable();
21754        let mut offset = 0;
21755        let mut grapheme_len = 0;
21756        if let Some(first_grapheme) = iter.next() {
21757            let is_newline = first_grapheme == "\n";
21758            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21759            offset += first_grapheme.len();
21760            grapheme_len += 1;
21761            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21762                if let Some(grapheme) = iter.peek().copied()
21763                    && should_stay_with_preceding_ideograph(grapheme)
21764                {
21765                    offset += grapheme.len();
21766                    grapheme_len += 1;
21767                }
21768            } else {
21769                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21770                let mut next_word_bound = words.peek().copied();
21771                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21772                    next_word_bound = words.next();
21773                }
21774                while let Some(grapheme) = iter.peek().copied() {
21775                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21776                        break;
21777                    };
21778                    if is_grapheme_whitespace(grapheme) != is_whitespace
21779                        || (grapheme == "\n") != is_newline
21780                    {
21781                        break;
21782                    };
21783                    offset += grapheme.len();
21784                    grapheme_len += 1;
21785                    iter.next();
21786                }
21787            }
21788            let token = &self.input[..offset];
21789            self.input = &self.input[offset..];
21790            if token == "\n" {
21791                Some(WordBreakToken::Newline)
21792            } else if is_whitespace {
21793                Some(WordBreakToken::InlineWhitespace {
21794                    token,
21795                    grapheme_len,
21796                })
21797            } else {
21798                Some(WordBreakToken::Word {
21799                    token,
21800                    grapheme_len,
21801                })
21802            }
21803        } else {
21804            None
21805        }
21806    }
21807}
21808
21809#[test]
21810fn test_word_breaking_tokenizer() {
21811    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21812        ("", &[]),
21813        ("  ", &[whitespace("  ", 2)]),
21814        ("Ʒ", &[word("Ʒ", 1)]),
21815        ("Ǽ", &[word("Ǽ", 1)]),
21816        ("", &[word("", 1)]),
21817        ("⋑⋑", &[word("⋑⋑", 2)]),
21818        (
21819            "原理,进而",
21820            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21821        ),
21822        (
21823            "hello world",
21824            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21825        ),
21826        (
21827            "hello, world",
21828            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21829        ),
21830        (
21831            "  hello world",
21832            &[
21833                whitespace("  ", 2),
21834                word("hello", 5),
21835                whitespace(" ", 1),
21836                word("world", 5),
21837            ],
21838        ),
21839        (
21840            "这是什么 \n 钢笔",
21841            &[
21842                word("", 1),
21843                word("", 1),
21844                word("", 1),
21845                word("", 1),
21846                whitespace(" ", 1),
21847                newline(),
21848                whitespace(" ", 1),
21849                word("", 1),
21850                word("", 1),
21851            ],
21852        ),
21853        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21854    ];
21855
21856    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21857        WordBreakToken::Word {
21858            token,
21859            grapheme_len,
21860        }
21861    }
21862
21863    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21864        WordBreakToken::InlineWhitespace {
21865            token,
21866            grapheme_len,
21867        }
21868    }
21869
21870    fn newline() -> WordBreakToken<'static> {
21871        WordBreakToken::Newline
21872    }
21873
21874    for (input, result) in tests {
21875        assert_eq!(
21876            WordBreakingTokenizer::new(input)
21877                .collect::<Vec<_>>()
21878                .as_slice(),
21879            *result,
21880        );
21881    }
21882}
21883
21884fn wrap_with_prefix(
21885    first_line_prefix: String,
21886    subsequent_lines_prefix: String,
21887    unwrapped_text: String,
21888    wrap_column: usize,
21889    tab_size: NonZeroU32,
21890    preserve_existing_whitespace: bool,
21891) -> String {
21892    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21893    let subsequent_lines_prefix_len =
21894        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21895    let mut wrapped_text = String::new();
21896    let mut current_line = first_line_prefix;
21897    let mut is_first_line = true;
21898
21899    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21900    let mut current_line_len = first_line_prefix_len;
21901    let mut in_whitespace = false;
21902    for token in tokenizer {
21903        let have_preceding_whitespace = in_whitespace;
21904        match token {
21905            WordBreakToken::Word {
21906                token,
21907                grapheme_len,
21908            } => {
21909                in_whitespace = false;
21910                let current_prefix_len = if is_first_line {
21911                    first_line_prefix_len
21912                } else {
21913                    subsequent_lines_prefix_len
21914                };
21915                if current_line_len + grapheme_len > wrap_column
21916                    && current_line_len != current_prefix_len
21917                {
21918                    wrapped_text.push_str(current_line.trim_end());
21919                    wrapped_text.push('\n');
21920                    is_first_line = false;
21921                    current_line = subsequent_lines_prefix.clone();
21922                    current_line_len = subsequent_lines_prefix_len;
21923                }
21924                current_line.push_str(token);
21925                current_line_len += grapheme_len;
21926            }
21927            WordBreakToken::InlineWhitespace {
21928                mut token,
21929                mut grapheme_len,
21930            } => {
21931                in_whitespace = true;
21932                if have_preceding_whitespace && !preserve_existing_whitespace {
21933                    continue;
21934                }
21935                if !preserve_existing_whitespace {
21936                    token = " ";
21937                    grapheme_len = 1;
21938                }
21939                let current_prefix_len = if is_first_line {
21940                    first_line_prefix_len
21941                } else {
21942                    subsequent_lines_prefix_len
21943                };
21944                if current_line_len + grapheme_len > wrap_column {
21945                    wrapped_text.push_str(current_line.trim_end());
21946                    wrapped_text.push('\n');
21947                    is_first_line = false;
21948                    current_line = subsequent_lines_prefix.clone();
21949                    current_line_len = subsequent_lines_prefix_len;
21950                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21951                    current_line.push_str(token);
21952                    current_line_len += grapheme_len;
21953                }
21954            }
21955            WordBreakToken::Newline => {
21956                in_whitespace = true;
21957                let current_prefix_len = if is_first_line {
21958                    first_line_prefix_len
21959                } else {
21960                    subsequent_lines_prefix_len
21961                };
21962                if preserve_existing_whitespace {
21963                    wrapped_text.push_str(current_line.trim_end());
21964                    wrapped_text.push('\n');
21965                    is_first_line = false;
21966                    current_line = subsequent_lines_prefix.clone();
21967                    current_line_len = subsequent_lines_prefix_len;
21968                } else if have_preceding_whitespace {
21969                    continue;
21970                } else if current_line_len + 1 > wrap_column
21971                    && current_line_len != current_prefix_len
21972                {
21973                    wrapped_text.push_str(current_line.trim_end());
21974                    wrapped_text.push('\n');
21975                    is_first_line = false;
21976                    current_line = subsequent_lines_prefix.clone();
21977                    current_line_len = subsequent_lines_prefix_len;
21978                } else if current_line_len != current_prefix_len {
21979                    current_line.push(' ');
21980                    current_line_len += 1;
21981                }
21982            }
21983        }
21984    }
21985
21986    if !current_line.is_empty() {
21987        wrapped_text.push_str(&current_line);
21988    }
21989    wrapped_text
21990}
21991
21992#[test]
21993fn test_wrap_with_prefix() {
21994    assert_eq!(
21995        wrap_with_prefix(
21996            "# ".to_string(),
21997            "# ".to_string(),
21998            "abcdefg".to_string(),
21999            4,
22000            NonZeroU32::new(4).unwrap(),
22001            false,
22002        ),
22003        "# abcdefg"
22004    );
22005    assert_eq!(
22006        wrap_with_prefix(
22007            "".to_string(),
22008            "".to_string(),
22009            "\thello world".to_string(),
22010            8,
22011            NonZeroU32::new(4).unwrap(),
22012            false,
22013        ),
22014        "hello\nworld"
22015    );
22016    assert_eq!(
22017        wrap_with_prefix(
22018            "// ".to_string(),
22019            "// ".to_string(),
22020            "xx \nyy zz aa bb cc".to_string(),
22021            12,
22022            NonZeroU32::new(4).unwrap(),
22023            false,
22024        ),
22025        "// xx yy zz\n// aa bb cc"
22026    );
22027    assert_eq!(
22028        wrap_with_prefix(
22029            String::new(),
22030            String::new(),
22031            "这是什么 \n 钢笔".to_string(),
22032            3,
22033            NonZeroU32::new(4).unwrap(),
22034            false,
22035        ),
22036        "这是什\n么 钢\n"
22037    );
22038}
22039
22040pub trait CollaborationHub {
22041    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22042    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22043    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22044}
22045
22046impl CollaborationHub for Entity<Project> {
22047    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22048        self.read(cx).collaborators()
22049    }
22050
22051    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22052        self.read(cx).user_store().read(cx).participant_indices()
22053    }
22054
22055    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22056        let this = self.read(cx);
22057        let user_ids = this.collaborators().values().map(|c| c.user_id);
22058        this.user_store().read(cx).participant_names(user_ids, cx)
22059    }
22060}
22061
22062pub trait SemanticsProvider {
22063    fn hover(
22064        &self,
22065        buffer: &Entity<Buffer>,
22066        position: text::Anchor,
22067        cx: &mut App,
22068    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22069
22070    fn inline_values(
22071        &self,
22072        buffer_handle: Entity<Buffer>,
22073        range: Range<text::Anchor>,
22074        cx: &mut App,
22075    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22076
22077    fn inlay_hints(
22078        &self,
22079        buffer_handle: Entity<Buffer>,
22080        range: Range<text::Anchor>,
22081        cx: &mut App,
22082    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22083
22084    fn resolve_inlay_hint(
22085        &self,
22086        hint: InlayHint,
22087        buffer_handle: Entity<Buffer>,
22088        server_id: LanguageServerId,
22089        cx: &mut App,
22090    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22091
22092    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22093
22094    fn document_highlights(
22095        &self,
22096        buffer: &Entity<Buffer>,
22097        position: text::Anchor,
22098        cx: &mut App,
22099    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22100
22101    fn definitions(
22102        &self,
22103        buffer: &Entity<Buffer>,
22104        position: text::Anchor,
22105        kind: GotoDefinitionKind,
22106        cx: &mut App,
22107    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22108
22109    fn range_for_rename(
22110        &self,
22111        buffer: &Entity<Buffer>,
22112        position: text::Anchor,
22113        cx: &mut App,
22114    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22115
22116    fn perform_rename(
22117        &self,
22118        buffer: &Entity<Buffer>,
22119        position: text::Anchor,
22120        new_name: String,
22121        cx: &mut App,
22122    ) -> Option<Task<Result<ProjectTransaction>>>;
22123}
22124
22125pub trait CompletionProvider {
22126    fn completions(
22127        &self,
22128        excerpt_id: ExcerptId,
22129        buffer: &Entity<Buffer>,
22130        buffer_position: text::Anchor,
22131        trigger: CompletionContext,
22132        window: &mut Window,
22133        cx: &mut Context<Editor>,
22134    ) -> Task<Result<Vec<CompletionResponse>>>;
22135
22136    fn resolve_completions(
22137        &self,
22138        _buffer: Entity<Buffer>,
22139        _completion_indices: Vec<usize>,
22140        _completions: Rc<RefCell<Box<[Completion]>>>,
22141        _cx: &mut Context<Editor>,
22142    ) -> Task<Result<bool>> {
22143        Task::ready(Ok(false))
22144    }
22145
22146    fn apply_additional_edits_for_completion(
22147        &self,
22148        _buffer: Entity<Buffer>,
22149        _completions: Rc<RefCell<Box<[Completion]>>>,
22150        _completion_index: usize,
22151        _push_to_history: bool,
22152        _cx: &mut Context<Editor>,
22153    ) -> Task<Result<Option<language::Transaction>>> {
22154        Task::ready(Ok(None))
22155    }
22156
22157    fn is_completion_trigger(
22158        &self,
22159        buffer: &Entity<Buffer>,
22160        position: language::Anchor,
22161        text: &str,
22162        trigger_in_words: bool,
22163        menu_is_open: bool,
22164        cx: &mut Context<Editor>,
22165    ) -> bool;
22166
22167    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22168
22169    fn sort_completions(&self) -> bool {
22170        true
22171    }
22172
22173    fn filter_completions(&self) -> bool {
22174        true
22175    }
22176}
22177
22178pub trait CodeActionProvider {
22179    fn id(&self) -> Arc<str>;
22180
22181    fn code_actions(
22182        &self,
22183        buffer: &Entity<Buffer>,
22184        range: Range<text::Anchor>,
22185        window: &mut Window,
22186        cx: &mut App,
22187    ) -> Task<Result<Vec<CodeAction>>>;
22188
22189    fn apply_code_action(
22190        &self,
22191        buffer_handle: Entity<Buffer>,
22192        action: CodeAction,
22193        excerpt_id: ExcerptId,
22194        push_to_history: bool,
22195        window: &mut Window,
22196        cx: &mut App,
22197    ) -> Task<Result<ProjectTransaction>>;
22198}
22199
22200impl CodeActionProvider for Entity<Project> {
22201    fn id(&self) -> Arc<str> {
22202        "project".into()
22203    }
22204
22205    fn code_actions(
22206        &self,
22207        buffer: &Entity<Buffer>,
22208        range: Range<text::Anchor>,
22209        _window: &mut Window,
22210        cx: &mut App,
22211    ) -> Task<Result<Vec<CodeAction>>> {
22212        self.update(cx, |project, cx| {
22213            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22214            let code_actions = project.code_actions(buffer, range, None, cx);
22215            cx.background_spawn(async move {
22216                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22217                Ok(code_lens_actions
22218                    .context("code lens fetch")?
22219                    .into_iter()
22220                    .flatten()
22221                    .chain(
22222                        code_actions
22223                            .context("code action fetch")?
22224                            .into_iter()
22225                            .flatten(),
22226                    )
22227                    .collect())
22228            })
22229        })
22230    }
22231
22232    fn apply_code_action(
22233        &self,
22234        buffer_handle: Entity<Buffer>,
22235        action: CodeAction,
22236        _excerpt_id: ExcerptId,
22237        push_to_history: bool,
22238        _window: &mut Window,
22239        cx: &mut App,
22240    ) -> Task<Result<ProjectTransaction>> {
22241        self.update(cx, |project, cx| {
22242            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22243        })
22244    }
22245}
22246
22247fn snippet_completions(
22248    project: &Project,
22249    buffer: &Entity<Buffer>,
22250    buffer_position: text::Anchor,
22251    cx: &mut App,
22252) -> Task<Result<CompletionResponse>> {
22253    let languages = buffer.read(cx).languages_at(buffer_position);
22254    let snippet_store = project.snippets().read(cx);
22255
22256    let scopes: Vec<_> = languages
22257        .iter()
22258        .filter_map(|language| {
22259            let language_name = language.lsp_id();
22260            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22261
22262            if snippets.is_empty() {
22263                None
22264            } else {
22265                Some((language.default_scope(), snippets))
22266            }
22267        })
22268        .collect();
22269
22270    if scopes.is_empty() {
22271        return Task::ready(Ok(CompletionResponse {
22272            completions: vec![],
22273            display_options: CompletionDisplayOptions::default(),
22274            is_incomplete: false,
22275        }));
22276    }
22277
22278    let snapshot = buffer.read(cx).text_snapshot();
22279    let chars: String = snapshot
22280        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22281        .collect();
22282    let executor = cx.background_executor().clone();
22283
22284    cx.background_spawn(async move {
22285        let mut is_incomplete = false;
22286        let mut completions: Vec<Completion> = Vec::new();
22287        for (scope, snippets) in scopes.into_iter() {
22288            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22289            let mut last_word = chars
22290                .chars()
22291                .take_while(|c| classifier.is_word(*c))
22292                .collect::<String>();
22293            last_word = last_word.chars().rev().collect();
22294
22295            if last_word.is_empty() {
22296                return Ok(CompletionResponse {
22297                    completions: vec![],
22298                    display_options: CompletionDisplayOptions::default(),
22299                    is_incomplete: true,
22300                });
22301            }
22302
22303            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22304            let to_lsp = |point: &text::Anchor| {
22305                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22306                point_to_lsp(end)
22307            };
22308            let lsp_end = to_lsp(&buffer_position);
22309
22310            let candidates = snippets
22311                .iter()
22312                .enumerate()
22313                .flat_map(|(ix, snippet)| {
22314                    snippet
22315                        .prefix
22316                        .iter()
22317                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22318                })
22319                .collect::<Vec<StringMatchCandidate>>();
22320
22321            const MAX_RESULTS: usize = 100;
22322            let mut matches = fuzzy::match_strings(
22323                &candidates,
22324                &last_word,
22325                last_word.chars().any(|c| c.is_uppercase()),
22326                true,
22327                MAX_RESULTS,
22328                &Default::default(),
22329                executor.clone(),
22330            )
22331            .await;
22332
22333            if matches.len() >= MAX_RESULTS {
22334                is_incomplete = true;
22335            }
22336
22337            // Remove all candidates where the query's start does not match the start of any word in the candidate
22338            if let Some(query_start) = last_word.chars().next() {
22339                matches.retain(|string_match| {
22340                    split_words(&string_match.string).any(|word| {
22341                        // Check that the first codepoint of the word as lowercase matches the first
22342                        // codepoint of the query as lowercase
22343                        word.chars()
22344                            .flat_map(|codepoint| codepoint.to_lowercase())
22345                            .zip(query_start.to_lowercase())
22346                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22347                    })
22348                });
22349            }
22350
22351            let matched_strings = matches
22352                .into_iter()
22353                .map(|m| m.string)
22354                .collect::<HashSet<_>>();
22355
22356            completions.extend(snippets.iter().filter_map(|snippet| {
22357                let matching_prefix = snippet
22358                    .prefix
22359                    .iter()
22360                    .find(|prefix| matched_strings.contains(*prefix))?;
22361                let start = as_offset - last_word.len();
22362                let start = snapshot.anchor_before(start);
22363                let range = start..buffer_position;
22364                let lsp_start = to_lsp(&start);
22365                let lsp_range = lsp::Range {
22366                    start: lsp_start,
22367                    end: lsp_end,
22368                };
22369                Some(Completion {
22370                    replace_range: range,
22371                    new_text: snippet.body.clone(),
22372                    source: CompletionSource::Lsp {
22373                        insert_range: None,
22374                        server_id: LanguageServerId(usize::MAX),
22375                        resolved: true,
22376                        lsp_completion: Box::new(lsp::CompletionItem {
22377                            label: snippet.prefix.first().unwrap().clone(),
22378                            kind: Some(CompletionItemKind::SNIPPET),
22379                            label_details: snippet.description.as_ref().map(|description| {
22380                                lsp::CompletionItemLabelDetails {
22381                                    detail: Some(description.clone()),
22382                                    description: None,
22383                                }
22384                            }),
22385                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22386                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22387                                lsp::InsertReplaceEdit {
22388                                    new_text: snippet.body.clone(),
22389                                    insert: lsp_range,
22390                                    replace: lsp_range,
22391                                },
22392                            )),
22393                            filter_text: Some(snippet.body.clone()),
22394                            sort_text: Some(char::MAX.to_string()),
22395                            ..lsp::CompletionItem::default()
22396                        }),
22397                        lsp_defaults: None,
22398                    },
22399                    label: CodeLabel {
22400                        text: matching_prefix.clone(),
22401                        runs: Vec::new(),
22402                        filter_range: 0..matching_prefix.len(),
22403                    },
22404                    icon_path: None,
22405                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22406                        single_line: snippet.name.clone().into(),
22407                        plain_text: snippet
22408                            .description
22409                            .clone()
22410                            .map(|description| description.into()),
22411                    }),
22412                    insert_text_mode: None,
22413                    confirm: None,
22414                })
22415            }))
22416        }
22417
22418        Ok(CompletionResponse {
22419            completions,
22420            display_options: CompletionDisplayOptions::default(),
22421            is_incomplete,
22422        })
22423    })
22424}
22425
22426impl CompletionProvider for Entity<Project> {
22427    fn completions(
22428        &self,
22429        _excerpt_id: ExcerptId,
22430        buffer: &Entity<Buffer>,
22431        buffer_position: text::Anchor,
22432        options: CompletionContext,
22433        _window: &mut Window,
22434        cx: &mut Context<Editor>,
22435    ) -> Task<Result<Vec<CompletionResponse>>> {
22436        self.update(cx, |project, cx| {
22437            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22438            let project_completions = project.completions(buffer, buffer_position, options, cx);
22439            cx.background_spawn(async move {
22440                let mut responses = project_completions.await?;
22441                let snippets = snippets.await?;
22442                if !snippets.completions.is_empty() {
22443                    responses.push(snippets);
22444                }
22445                Ok(responses)
22446            })
22447        })
22448    }
22449
22450    fn resolve_completions(
22451        &self,
22452        buffer: Entity<Buffer>,
22453        completion_indices: Vec<usize>,
22454        completions: Rc<RefCell<Box<[Completion]>>>,
22455        cx: &mut Context<Editor>,
22456    ) -> Task<Result<bool>> {
22457        self.update(cx, |project, cx| {
22458            project.lsp_store().update(cx, |lsp_store, cx| {
22459                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22460            })
22461        })
22462    }
22463
22464    fn apply_additional_edits_for_completion(
22465        &self,
22466        buffer: Entity<Buffer>,
22467        completions: Rc<RefCell<Box<[Completion]>>>,
22468        completion_index: usize,
22469        push_to_history: bool,
22470        cx: &mut Context<Editor>,
22471    ) -> Task<Result<Option<language::Transaction>>> {
22472        self.update(cx, |project, cx| {
22473            project.lsp_store().update(cx, |lsp_store, cx| {
22474                lsp_store.apply_additional_edits_for_completion(
22475                    buffer,
22476                    completions,
22477                    completion_index,
22478                    push_to_history,
22479                    cx,
22480                )
22481            })
22482        })
22483    }
22484
22485    fn is_completion_trigger(
22486        &self,
22487        buffer: &Entity<Buffer>,
22488        position: language::Anchor,
22489        text: &str,
22490        trigger_in_words: bool,
22491        menu_is_open: bool,
22492        cx: &mut Context<Editor>,
22493    ) -> bool {
22494        let mut chars = text.chars();
22495        let char = if let Some(char) = chars.next() {
22496            char
22497        } else {
22498            return false;
22499        };
22500        if chars.next().is_some() {
22501            return false;
22502        }
22503
22504        let buffer = buffer.read(cx);
22505        let snapshot = buffer.snapshot();
22506        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22507            return false;
22508        }
22509        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22510        if trigger_in_words && classifier.is_word(char) {
22511            return true;
22512        }
22513
22514        buffer.completion_triggers().contains(text)
22515    }
22516}
22517
22518impl SemanticsProvider for Entity<Project> {
22519    fn hover(
22520        &self,
22521        buffer: &Entity<Buffer>,
22522        position: text::Anchor,
22523        cx: &mut App,
22524    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22525        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22526    }
22527
22528    fn document_highlights(
22529        &self,
22530        buffer: &Entity<Buffer>,
22531        position: text::Anchor,
22532        cx: &mut App,
22533    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22534        Some(self.update(cx, |project, cx| {
22535            project.document_highlights(buffer, position, cx)
22536        }))
22537    }
22538
22539    fn definitions(
22540        &self,
22541        buffer: &Entity<Buffer>,
22542        position: text::Anchor,
22543        kind: GotoDefinitionKind,
22544        cx: &mut App,
22545    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22546        Some(self.update(cx, |project, cx| match kind {
22547            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22548            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22549            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22550            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22551        }))
22552    }
22553
22554    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22555        self.update(cx, |project, cx| {
22556            if project
22557                .active_debug_session(cx)
22558                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22559            {
22560                return true;
22561            }
22562
22563            buffer.update(cx, |buffer, cx| {
22564                project.any_language_server_supports_inlay_hints(buffer, cx)
22565            })
22566        })
22567    }
22568
22569    fn inline_values(
22570        &self,
22571        buffer_handle: Entity<Buffer>,
22572        range: Range<text::Anchor>,
22573        cx: &mut App,
22574    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22575        self.update(cx, |project, cx| {
22576            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22577
22578            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22579        })
22580    }
22581
22582    fn inlay_hints(
22583        &self,
22584        buffer_handle: Entity<Buffer>,
22585        range: Range<text::Anchor>,
22586        cx: &mut App,
22587    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22588        Some(self.update(cx, |project, cx| {
22589            project.inlay_hints(buffer_handle, range, cx)
22590        }))
22591    }
22592
22593    fn resolve_inlay_hint(
22594        &self,
22595        hint: InlayHint,
22596        buffer_handle: Entity<Buffer>,
22597        server_id: LanguageServerId,
22598        cx: &mut App,
22599    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22600        Some(self.update(cx, |project, cx| {
22601            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22602        }))
22603    }
22604
22605    fn range_for_rename(
22606        &self,
22607        buffer: &Entity<Buffer>,
22608        position: text::Anchor,
22609        cx: &mut App,
22610    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22611        Some(self.update(cx, |project, cx| {
22612            let buffer = buffer.clone();
22613            let task = project.prepare_rename(buffer.clone(), position, cx);
22614            cx.spawn(async move |_, cx| {
22615                Ok(match task.await? {
22616                    PrepareRenameResponse::Success(range) => Some(range),
22617                    PrepareRenameResponse::InvalidPosition => None,
22618                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22619                        // Fallback on using TreeSitter info to determine identifier range
22620                        buffer.read_with(cx, |buffer, _| {
22621                            let snapshot = buffer.snapshot();
22622                            let (range, kind) = snapshot.surrounding_word(position, false);
22623                            if kind != Some(CharKind::Word) {
22624                                return None;
22625                            }
22626                            Some(
22627                                snapshot.anchor_before(range.start)
22628                                    ..snapshot.anchor_after(range.end),
22629                            )
22630                        })?
22631                    }
22632                })
22633            })
22634        }))
22635    }
22636
22637    fn perform_rename(
22638        &self,
22639        buffer: &Entity<Buffer>,
22640        position: text::Anchor,
22641        new_name: String,
22642        cx: &mut App,
22643    ) -> Option<Task<Result<ProjectTransaction>>> {
22644        Some(self.update(cx, |project, cx| {
22645            project.perform_rename(buffer.clone(), position, new_name, cx)
22646        }))
22647    }
22648}
22649
22650fn inlay_hint_settings(
22651    location: Anchor,
22652    snapshot: &MultiBufferSnapshot,
22653    cx: &mut Context<Editor>,
22654) -> InlayHintSettings {
22655    let file = snapshot.file_at(location);
22656    let language = snapshot.language_at(location).map(|l| l.name());
22657    language_settings(language, file, cx).inlay_hints
22658}
22659
22660fn consume_contiguous_rows(
22661    contiguous_row_selections: &mut Vec<Selection<Point>>,
22662    selection: &Selection<Point>,
22663    display_map: &DisplaySnapshot,
22664    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22665) -> (MultiBufferRow, MultiBufferRow) {
22666    contiguous_row_selections.push(selection.clone());
22667    let start_row = starting_row(selection, display_map);
22668    let mut end_row = ending_row(selection, display_map);
22669
22670    while let Some(next_selection) = selections.peek() {
22671        if next_selection.start.row <= end_row.0 {
22672            end_row = ending_row(next_selection, display_map);
22673            contiguous_row_selections.push(selections.next().unwrap().clone());
22674        } else {
22675            break;
22676        }
22677    }
22678    (start_row, end_row)
22679}
22680
22681fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22682    if selection.start.column > 0 {
22683        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22684    } else {
22685        MultiBufferRow(selection.start.row)
22686    }
22687}
22688
22689fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22690    if next_selection.end.column > 0 || next_selection.is_empty() {
22691        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22692    } else {
22693        MultiBufferRow(next_selection.end.row)
22694    }
22695}
22696
22697impl EditorSnapshot {
22698    pub fn remote_selections_in_range<'a>(
22699        &'a self,
22700        range: &'a Range<Anchor>,
22701        collaboration_hub: &dyn CollaborationHub,
22702        cx: &'a App,
22703    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22704        let participant_names = collaboration_hub.user_names(cx);
22705        let participant_indices = collaboration_hub.user_participant_indices(cx);
22706        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22707        let collaborators_by_replica_id = collaborators_by_peer_id
22708            .values()
22709            .map(|collaborator| (collaborator.replica_id, collaborator))
22710            .collect::<HashMap<_, _>>();
22711        self.buffer_snapshot
22712            .selections_in_range(range, false)
22713            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22714                if replica_id == AGENT_REPLICA_ID {
22715                    Some(RemoteSelection {
22716                        replica_id,
22717                        selection,
22718                        cursor_shape,
22719                        line_mode,
22720                        collaborator_id: CollaboratorId::Agent,
22721                        user_name: Some("Agent".into()),
22722                        color: cx.theme().players().agent(),
22723                    })
22724                } else {
22725                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22726                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22727                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22728                    Some(RemoteSelection {
22729                        replica_id,
22730                        selection,
22731                        cursor_shape,
22732                        line_mode,
22733                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22734                        user_name,
22735                        color: if let Some(index) = participant_index {
22736                            cx.theme().players().color_for_participant(index.0)
22737                        } else {
22738                            cx.theme().players().absent()
22739                        },
22740                    })
22741                }
22742            })
22743    }
22744
22745    pub fn hunks_for_ranges(
22746        &self,
22747        ranges: impl IntoIterator<Item = Range<Point>>,
22748    ) -> Vec<MultiBufferDiffHunk> {
22749        let mut hunks = Vec::new();
22750        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22751            HashMap::default();
22752        for query_range in ranges {
22753            let query_rows =
22754                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22755            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22756                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22757            ) {
22758                // Include deleted hunks that are adjacent to the query range, because
22759                // otherwise they would be missed.
22760                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22761                if hunk.status().is_deleted() {
22762                    intersects_range |= hunk.row_range.start == query_rows.end;
22763                    intersects_range |= hunk.row_range.end == query_rows.start;
22764                }
22765                if intersects_range {
22766                    if !processed_buffer_rows
22767                        .entry(hunk.buffer_id)
22768                        .or_default()
22769                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22770                    {
22771                        continue;
22772                    }
22773                    hunks.push(hunk);
22774                }
22775            }
22776        }
22777
22778        hunks
22779    }
22780
22781    fn display_diff_hunks_for_rows<'a>(
22782        &'a self,
22783        display_rows: Range<DisplayRow>,
22784        folded_buffers: &'a HashSet<BufferId>,
22785    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22786        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22787        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22788
22789        self.buffer_snapshot
22790            .diff_hunks_in_range(buffer_start..buffer_end)
22791            .filter_map(|hunk| {
22792                if folded_buffers.contains(&hunk.buffer_id) {
22793                    return None;
22794                }
22795
22796                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22797                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22798
22799                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22800                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22801
22802                let display_hunk = if hunk_display_start.column() != 0 {
22803                    DisplayDiffHunk::Folded {
22804                        display_row: hunk_display_start.row(),
22805                    }
22806                } else {
22807                    let mut end_row = hunk_display_end.row();
22808                    if hunk_display_end.column() > 0 {
22809                        end_row.0 += 1;
22810                    }
22811                    let is_created_file = hunk.is_created_file();
22812                    DisplayDiffHunk::Unfolded {
22813                        status: hunk.status(),
22814                        diff_base_byte_range: hunk.diff_base_byte_range,
22815                        display_row_range: hunk_display_start.row()..end_row,
22816                        multi_buffer_range: Anchor::range_in_buffer(
22817                            hunk.excerpt_id,
22818                            hunk.buffer_id,
22819                            hunk.buffer_range,
22820                        ),
22821                        is_created_file,
22822                    }
22823                };
22824
22825                Some(display_hunk)
22826            })
22827    }
22828
22829    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22830        self.display_snapshot.buffer_snapshot.language_at(position)
22831    }
22832
22833    pub fn is_focused(&self) -> bool {
22834        self.is_focused
22835    }
22836
22837    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22838        self.placeholder_text.as_ref()
22839    }
22840
22841    pub fn scroll_position(&self) -> gpui::Point<f32> {
22842        self.scroll_anchor.scroll_position(&self.display_snapshot)
22843    }
22844
22845    fn gutter_dimensions(
22846        &self,
22847        font_id: FontId,
22848        font_size: Pixels,
22849        max_line_number_width: Pixels,
22850        cx: &App,
22851    ) -> Option<GutterDimensions> {
22852        if !self.show_gutter {
22853            return None;
22854        }
22855
22856        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22857        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22858
22859        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22860            matches!(
22861                ProjectSettings::get_global(cx).git.git_gutter,
22862                Some(GitGutterSetting::TrackedFiles)
22863            )
22864        });
22865        let gutter_settings = EditorSettings::get_global(cx).gutter;
22866        let show_line_numbers = self
22867            .show_line_numbers
22868            .unwrap_or(gutter_settings.line_numbers);
22869        let line_gutter_width = if show_line_numbers {
22870            // Avoid flicker-like gutter resizes when the line number gains another digit by
22871            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22872            let min_width_for_number_on_gutter =
22873                ch_advance * gutter_settings.min_line_number_digits as f32;
22874            max_line_number_width.max(min_width_for_number_on_gutter)
22875        } else {
22876            0.0.into()
22877        };
22878
22879        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22880        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22881
22882        let git_blame_entries_width =
22883            self.git_blame_gutter_max_author_length
22884                .map(|max_author_length| {
22885                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22886                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22887
22888                    /// The number of characters to dedicate to gaps and margins.
22889                    const SPACING_WIDTH: usize = 4;
22890
22891                    let max_char_count = max_author_length.min(renderer.max_author_length())
22892                        + ::git::SHORT_SHA_LENGTH
22893                        + MAX_RELATIVE_TIMESTAMP.len()
22894                        + SPACING_WIDTH;
22895
22896                    ch_advance * max_char_count
22897                });
22898
22899        let is_singleton = self.buffer_snapshot.is_singleton();
22900
22901        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22902        left_padding += if !is_singleton {
22903            ch_width * 4.0
22904        } else if show_runnables || show_breakpoints {
22905            ch_width * 3.0
22906        } else if show_git_gutter && show_line_numbers {
22907            ch_width * 2.0
22908        } else if show_git_gutter || show_line_numbers {
22909            ch_width
22910        } else {
22911            px(0.)
22912        };
22913
22914        let shows_folds = is_singleton && gutter_settings.folds;
22915
22916        let right_padding = if shows_folds && show_line_numbers {
22917            ch_width * 4.0
22918        } else if shows_folds || (!is_singleton && show_line_numbers) {
22919            ch_width * 3.0
22920        } else if show_line_numbers {
22921            ch_width
22922        } else {
22923            px(0.)
22924        };
22925
22926        Some(GutterDimensions {
22927            left_padding,
22928            right_padding,
22929            width: line_gutter_width + left_padding + right_padding,
22930            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22931            git_blame_entries_width,
22932        })
22933    }
22934
22935    pub fn render_crease_toggle(
22936        &self,
22937        buffer_row: MultiBufferRow,
22938        row_contains_cursor: bool,
22939        editor: Entity<Editor>,
22940        window: &mut Window,
22941        cx: &mut App,
22942    ) -> Option<AnyElement> {
22943        let folded = self.is_line_folded(buffer_row);
22944        let mut is_foldable = false;
22945
22946        if let Some(crease) = self
22947            .crease_snapshot
22948            .query_row(buffer_row, &self.buffer_snapshot)
22949        {
22950            is_foldable = true;
22951            match crease {
22952                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22953                    if let Some(render_toggle) = render_toggle {
22954                        let toggle_callback =
22955                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22956                                if folded {
22957                                    editor.update(cx, |editor, cx| {
22958                                        editor.fold_at(buffer_row, window, cx)
22959                                    });
22960                                } else {
22961                                    editor.update(cx, |editor, cx| {
22962                                        editor.unfold_at(buffer_row, window, cx)
22963                                    });
22964                                }
22965                            });
22966                        return Some((render_toggle)(
22967                            buffer_row,
22968                            folded,
22969                            toggle_callback,
22970                            window,
22971                            cx,
22972                        ));
22973                    }
22974                }
22975            }
22976        }
22977
22978        is_foldable |= self.starts_indent(buffer_row);
22979
22980        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22981            Some(
22982                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22983                    .toggle_state(folded)
22984                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22985                        if folded {
22986                            this.unfold_at(buffer_row, window, cx);
22987                        } else {
22988                            this.fold_at(buffer_row, window, cx);
22989                        }
22990                    }))
22991                    .into_any_element(),
22992            )
22993        } else {
22994            None
22995        }
22996    }
22997
22998    pub fn render_crease_trailer(
22999        &self,
23000        buffer_row: MultiBufferRow,
23001        window: &mut Window,
23002        cx: &mut App,
23003    ) -> Option<AnyElement> {
23004        let folded = self.is_line_folded(buffer_row);
23005        if let Crease::Inline { render_trailer, .. } = self
23006            .crease_snapshot
23007            .query_row(buffer_row, &self.buffer_snapshot)?
23008        {
23009            let render_trailer = render_trailer.as_ref()?;
23010            Some(render_trailer(buffer_row, folded, window, cx))
23011        } else {
23012            None
23013        }
23014    }
23015}
23016
23017impl Deref for EditorSnapshot {
23018    type Target = DisplaySnapshot;
23019
23020    fn deref(&self) -> &Self::Target {
23021        &self.display_snapshot
23022    }
23023}
23024
23025#[derive(Clone, Debug, PartialEq, Eq)]
23026pub enum EditorEvent {
23027    InputIgnored {
23028        text: Arc<str>,
23029    },
23030    InputHandled {
23031        utf16_range_to_replace: Option<Range<isize>>,
23032        text: Arc<str>,
23033    },
23034    ExcerptsAdded {
23035        buffer: Entity<Buffer>,
23036        predecessor: ExcerptId,
23037        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23038    },
23039    ExcerptsRemoved {
23040        ids: Vec<ExcerptId>,
23041        removed_buffer_ids: Vec<BufferId>,
23042    },
23043    BufferFoldToggled {
23044        ids: Vec<ExcerptId>,
23045        folded: bool,
23046    },
23047    ExcerptsEdited {
23048        ids: Vec<ExcerptId>,
23049    },
23050    ExcerptsExpanded {
23051        ids: Vec<ExcerptId>,
23052    },
23053    BufferEdited,
23054    Edited {
23055        transaction_id: clock::Lamport,
23056    },
23057    Reparsed(BufferId),
23058    Focused,
23059    FocusedIn,
23060    Blurred,
23061    DirtyChanged,
23062    Saved,
23063    TitleChanged,
23064    DiffBaseChanged,
23065    SelectionsChanged {
23066        local: bool,
23067    },
23068    ScrollPositionChanged {
23069        local: bool,
23070        autoscroll: bool,
23071    },
23072    Closed,
23073    TransactionUndone {
23074        transaction_id: clock::Lamport,
23075    },
23076    TransactionBegun {
23077        transaction_id: clock::Lamport,
23078    },
23079    Reloaded,
23080    CursorShapeChanged,
23081    BreadcrumbsChanged,
23082    PushedToNavHistory {
23083        anchor: Anchor,
23084        is_deactivate: bool,
23085    },
23086}
23087
23088impl EventEmitter<EditorEvent> for Editor {}
23089
23090impl Focusable for Editor {
23091    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23092        self.focus_handle.clone()
23093    }
23094}
23095
23096impl Render for Editor {
23097    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23098        let settings = ThemeSettings::get_global(cx);
23099
23100        let mut text_style = match self.mode {
23101            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23102                color: cx.theme().colors().editor_foreground,
23103                font_family: settings.ui_font.family.clone(),
23104                font_features: settings.ui_font.features.clone(),
23105                font_fallbacks: settings.ui_font.fallbacks.clone(),
23106                font_size: rems(0.875).into(),
23107                font_weight: settings.ui_font.weight,
23108                line_height: relative(settings.buffer_line_height.value()),
23109                ..Default::default()
23110            },
23111            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23112                color: cx.theme().colors().editor_foreground,
23113                font_family: settings.buffer_font.family.clone(),
23114                font_features: settings.buffer_font.features.clone(),
23115                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23116                font_size: settings.buffer_font_size(cx).into(),
23117                font_weight: settings.buffer_font.weight,
23118                line_height: relative(settings.buffer_line_height.value()),
23119                ..Default::default()
23120            },
23121        };
23122        if let Some(text_style_refinement) = &self.text_style_refinement {
23123            text_style.refine(text_style_refinement)
23124        }
23125
23126        let background = match self.mode {
23127            EditorMode::SingleLine => cx.theme().system().transparent,
23128            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23129            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23130            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23131        };
23132
23133        EditorElement::new(
23134            &cx.entity(),
23135            EditorStyle {
23136                background,
23137                border: cx.theme().colors().border,
23138                local_player: cx.theme().players().local(),
23139                text: text_style,
23140                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23141                syntax: cx.theme().syntax().clone(),
23142                status: cx.theme().status().clone(),
23143                inlay_hints_style: make_inlay_hints_style(cx),
23144                edit_prediction_styles: make_suggestion_styles(cx),
23145                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23146                show_underlines: self.diagnostics_enabled(),
23147            },
23148        )
23149    }
23150}
23151
23152impl EntityInputHandler for Editor {
23153    fn text_for_range(
23154        &mut self,
23155        range_utf16: Range<usize>,
23156        adjusted_range: &mut Option<Range<usize>>,
23157        _: &mut Window,
23158        cx: &mut Context<Self>,
23159    ) -> Option<String> {
23160        let snapshot = self.buffer.read(cx).read(cx);
23161        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23162        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23163        if (start.0..end.0) != range_utf16 {
23164            adjusted_range.replace(start.0..end.0);
23165        }
23166        Some(snapshot.text_for_range(start..end).collect())
23167    }
23168
23169    fn selected_text_range(
23170        &mut self,
23171        ignore_disabled_input: bool,
23172        _: &mut Window,
23173        cx: &mut Context<Self>,
23174    ) -> Option<UTF16Selection> {
23175        // Prevent the IME menu from appearing when holding down an alphabetic key
23176        // while input is disabled.
23177        if !ignore_disabled_input && !self.input_enabled {
23178            return None;
23179        }
23180
23181        let selection = self.selections.newest::<OffsetUtf16>(cx);
23182        let range = selection.range();
23183
23184        Some(UTF16Selection {
23185            range: range.start.0..range.end.0,
23186            reversed: selection.reversed,
23187        })
23188    }
23189
23190    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23191        let snapshot = self.buffer.read(cx).read(cx);
23192        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23193        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23194    }
23195
23196    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23197        self.clear_highlights::<InputComposition>(cx);
23198        self.ime_transaction.take();
23199    }
23200
23201    fn replace_text_in_range(
23202        &mut self,
23203        range_utf16: Option<Range<usize>>,
23204        text: &str,
23205        window: &mut Window,
23206        cx: &mut Context<Self>,
23207    ) {
23208        if !self.input_enabled {
23209            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23210            return;
23211        }
23212
23213        self.transact(window, cx, |this, window, cx| {
23214            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23215                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23216                Some(this.selection_replacement_ranges(range_utf16, cx))
23217            } else {
23218                this.marked_text_ranges(cx)
23219            };
23220
23221            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23222                let newest_selection_id = this.selections.newest_anchor().id;
23223                this.selections
23224                    .all::<OffsetUtf16>(cx)
23225                    .iter()
23226                    .zip(ranges_to_replace.iter())
23227                    .find_map(|(selection, range)| {
23228                        if selection.id == newest_selection_id {
23229                            Some(
23230                                (range.start.0 as isize - selection.head().0 as isize)
23231                                    ..(range.end.0 as isize - selection.head().0 as isize),
23232                            )
23233                        } else {
23234                            None
23235                        }
23236                    })
23237            });
23238
23239            cx.emit(EditorEvent::InputHandled {
23240                utf16_range_to_replace: range_to_replace,
23241                text: text.into(),
23242            });
23243
23244            if let Some(new_selected_ranges) = new_selected_ranges {
23245                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23246                    selections.select_ranges(new_selected_ranges)
23247                });
23248                this.backspace(&Default::default(), window, cx);
23249            }
23250
23251            this.handle_input(text, window, cx);
23252        });
23253
23254        if let Some(transaction) = self.ime_transaction {
23255            self.buffer.update(cx, |buffer, cx| {
23256                buffer.group_until_transaction(transaction, cx);
23257            });
23258        }
23259
23260        self.unmark_text(window, cx);
23261    }
23262
23263    fn replace_and_mark_text_in_range(
23264        &mut self,
23265        range_utf16: Option<Range<usize>>,
23266        text: &str,
23267        new_selected_range_utf16: Option<Range<usize>>,
23268        window: &mut Window,
23269        cx: &mut Context<Self>,
23270    ) {
23271        if !self.input_enabled {
23272            return;
23273        }
23274
23275        let transaction = self.transact(window, cx, |this, window, cx| {
23276            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23277                let snapshot = this.buffer.read(cx).read(cx);
23278                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23279                    for marked_range in &mut marked_ranges {
23280                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23281                        marked_range.start.0 += relative_range_utf16.start;
23282                        marked_range.start =
23283                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23284                        marked_range.end =
23285                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23286                    }
23287                }
23288                Some(marked_ranges)
23289            } else if let Some(range_utf16) = range_utf16 {
23290                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23291                Some(this.selection_replacement_ranges(range_utf16, cx))
23292            } else {
23293                None
23294            };
23295
23296            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23297                let newest_selection_id = this.selections.newest_anchor().id;
23298                this.selections
23299                    .all::<OffsetUtf16>(cx)
23300                    .iter()
23301                    .zip(ranges_to_replace.iter())
23302                    .find_map(|(selection, range)| {
23303                        if selection.id == newest_selection_id {
23304                            Some(
23305                                (range.start.0 as isize - selection.head().0 as isize)
23306                                    ..(range.end.0 as isize - selection.head().0 as isize),
23307                            )
23308                        } else {
23309                            None
23310                        }
23311                    })
23312            });
23313
23314            cx.emit(EditorEvent::InputHandled {
23315                utf16_range_to_replace: range_to_replace,
23316                text: text.into(),
23317            });
23318
23319            if let Some(ranges) = ranges_to_replace {
23320                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23321                    s.select_ranges(ranges)
23322                });
23323            }
23324
23325            let marked_ranges = {
23326                let snapshot = this.buffer.read(cx).read(cx);
23327                this.selections
23328                    .disjoint_anchors()
23329                    .iter()
23330                    .map(|selection| {
23331                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23332                    })
23333                    .collect::<Vec<_>>()
23334            };
23335
23336            if text.is_empty() {
23337                this.unmark_text(window, cx);
23338            } else {
23339                this.highlight_text::<InputComposition>(
23340                    marked_ranges.clone(),
23341                    HighlightStyle {
23342                        underline: Some(UnderlineStyle {
23343                            thickness: px(1.),
23344                            color: None,
23345                            wavy: false,
23346                        }),
23347                        ..Default::default()
23348                    },
23349                    cx,
23350                );
23351            }
23352
23353            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23354            let use_autoclose = this.use_autoclose;
23355            let use_auto_surround = this.use_auto_surround;
23356            this.set_use_autoclose(false);
23357            this.set_use_auto_surround(false);
23358            this.handle_input(text, window, cx);
23359            this.set_use_autoclose(use_autoclose);
23360            this.set_use_auto_surround(use_auto_surround);
23361
23362            if let Some(new_selected_range) = new_selected_range_utf16 {
23363                let snapshot = this.buffer.read(cx).read(cx);
23364                let new_selected_ranges = marked_ranges
23365                    .into_iter()
23366                    .map(|marked_range| {
23367                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23368                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23369                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23370                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23371                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23372                    })
23373                    .collect::<Vec<_>>();
23374
23375                drop(snapshot);
23376                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23377                    selections.select_ranges(new_selected_ranges)
23378                });
23379            }
23380        });
23381
23382        self.ime_transaction = self.ime_transaction.or(transaction);
23383        if let Some(transaction) = self.ime_transaction {
23384            self.buffer.update(cx, |buffer, cx| {
23385                buffer.group_until_transaction(transaction, cx);
23386            });
23387        }
23388
23389        if self.text_highlights::<InputComposition>(cx).is_none() {
23390            self.ime_transaction.take();
23391        }
23392    }
23393
23394    fn bounds_for_range(
23395        &mut self,
23396        range_utf16: Range<usize>,
23397        element_bounds: gpui::Bounds<Pixels>,
23398        window: &mut Window,
23399        cx: &mut Context<Self>,
23400    ) -> Option<gpui::Bounds<Pixels>> {
23401        let text_layout_details = self.text_layout_details(window);
23402        let CharacterDimensions {
23403            em_width,
23404            em_advance,
23405            line_height,
23406        } = self.character_dimensions(window);
23407
23408        let snapshot = self.snapshot(window, cx);
23409        let scroll_position = snapshot.scroll_position();
23410        let scroll_left = scroll_position.x * em_advance;
23411
23412        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23413        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23414            + self.gutter_dimensions.full_width();
23415        let y = line_height * (start.row().as_f32() - scroll_position.y);
23416
23417        Some(Bounds {
23418            origin: element_bounds.origin + point(x, y),
23419            size: size(em_width, line_height),
23420        })
23421    }
23422
23423    fn character_index_for_point(
23424        &mut self,
23425        point: gpui::Point<Pixels>,
23426        _window: &mut Window,
23427        _cx: &mut Context<Self>,
23428    ) -> Option<usize> {
23429        let position_map = self.last_position_map.as_ref()?;
23430        if !position_map.text_hitbox.contains(&point) {
23431            return None;
23432        }
23433        let display_point = position_map.point_for_position(point).previous_valid;
23434        let anchor = position_map
23435            .snapshot
23436            .display_point_to_anchor(display_point, Bias::Left);
23437        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23438        Some(utf16_offset.0)
23439    }
23440}
23441
23442trait SelectionExt {
23443    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23444    fn spanned_rows(
23445        &self,
23446        include_end_if_at_line_start: bool,
23447        map: &DisplaySnapshot,
23448    ) -> Range<MultiBufferRow>;
23449}
23450
23451impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23452    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23453        let start = self
23454            .start
23455            .to_point(&map.buffer_snapshot)
23456            .to_display_point(map);
23457        let end = self
23458            .end
23459            .to_point(&map.buffer_snapshot)
23460            .to_display_point(map);
23461        if self.reversed {
23462            end..start
23463        } else {
23464            start..end
23465        }
23466    }
23467
23468    fn spanned_rows(
23469        &self,
23470        include_end_if_at_line_start: bool,
23471        map: &DisplaySnapshot,
23472    ) -> Range<MultiBufferRow> {
23473        let start = self.start.to_point(&map.buffer_snapshot);
23474        let mut end = self.end.to_point(&map.buffer_snapshot);
23475        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23476            end.row -= 1;
23477        }
23478
23479        let buffer_start = map.prev_line_boundary(start).0;
23480        let buffer_end = map.next_line_boundary(end).0;
23481        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23482    }
23483}
23484
23485impl<T: InvalidationRegion> InvalidationStack<T> {
23486    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23487    where
23488        S: Clone + ToOffset,
23489    {
23490        while let Some(region) = self.last() {
23491            let all_selections_inside_invalidation_ranges =
23492                if selections.len() == region.ranges().len() {
23493                    selections
23494                        .iter()
23495                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23496                        .all(|(selection, invalidation_range)| {
23497                            let head = selection.head().to_offset(buffer);
23498                            invalidation_range.start <= head && invalidation_range.end >= head
23499                        })
23500                } else {
23501                    false
23502                };
23503
23504            if all_selections_inside_invalidation_ranges {
23505                break;
23506            } else {
23507                self.pop();
23508            }
23509        }
23510    }
23511}
23512
23513impl<T> Default for InvalidationStack<T> {
23514    fn default() -> Self {
23515        Self(Default::default())
23516    }
23517}
23518
23519impl<T> Deref for InvalidationStack<T> {
23520    type Target = Vec<T>;
23521
23522    fn deref(&self) -> &Self::Target {
23523        &self.0
23524    }
23525}
23526
23527impl<T> DerefMut for InvalidationStack<T> {
23528    fn deref_mut(&mut self) -> &mut Self::Target {
23529        &mut self.0
23530    }
23531}
23532
23533impl InvalidationRegion for SnippetState {
23534    fn ranges(&self) -> &[Range<Anchor>] {
23535        &self.ranges[self.active_index]
23536    }
23537}
23538
23539fn edit_prediction_edit_text(
23540    current_snapshot: &BufferSnapshot,
23541    edits: &[(Range<Anchor>, String)],
23542    edit_preview: &EditPreview,
23543    include_deletions: bool,
23544    cx: &App,
23545) -> HighlightedText {
23546    let edits = edits
23547        .iter()
23548        .map(|(anchor, text)| {
23549            (
23550                anchor.start.text_anchor..anchor.end.text_anchor,
23551                text.clone(),
23552            )
23553        })
23554        .collect::<Vec<_>>();
23555
23556    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23557}
23558
23559fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23560    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23561    // Just show the raw edit text with basic styling
23562    let mut text = String::new();
23563    let mut highlights = Vec::new();
23564
23565    let insertion_highlight_style = HighlightStyle {
23566        color: Some(cx.theme().colors().text),
23567        ..Default::default()
23568    };
23569
23570    for (_, edit_text) in edits {
23571        let start_offset = text.len();
23572        text.push_str(edit_text);
23573        let end_offset = text.len();
23574
23575        if start_offset < end_offset {
23576            highlights.push((start_offset..end_offset, insertion_highlight_style));
23577        }
23578    }
23579
23580    HighlightedText {
23581        text: text.into(),
23582        highlights,
23583    }
23584}
23585
23586pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23587    match severity {
23588        lsp::DiagnosticSeverity::ERROR => colors.error,
23589        lsp::DiagnosticSeverity::WARNING => colors.warning,
23590        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23591        lsp::DiagnosticSeverity::HINT => colors.info,
23592        _ => colors.ignored,
23593    }
23594}
23595
23596pub fn styled_runs_for_code_label<'a>(
23597    label: &'a CodeLabel,
23598    syntax_theme: &'a theme::SyntaxTheme,
23599) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23600    let fade_out = HighlightStyle {
23601        fade_out: Some(0.35),
23602        ..Default::default()
23603    };
23604
23605    let mut prev_end = label.filter_range.end;
23606    label
23607        .runs
23608        .iter()
23609        .enumerate()
23610        .flat_map(move |(ix, (range, highlight_id))| {
23611            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23612                style
23613            } else {
23614                return Default::default();
23615            };
23616            let mut muted_style = style;
23617            muted_style.highlight(fade_out);
23618
23619            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23620            if range.start >= label.filter_range.end {
23621                if range.start > prev_end {
23622                    runs.push((prev_end..range.start, fade_out));
23623                }
23624                runs.push((range.clone(), muted_style));
23625            } else if range.end <= label.filter_range.end {
23626                runs.push((range.clone(), style));
23627            } else {
23628                runs.push((range.start..label.filter_range.end, style));
23629                runs.push((label.filter_range.end..range.end, muted_style));
23630            }
23631            prev_end = cmp::max(prev_end, range.end);
23632
23633            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23634                runs.push((prev_end..label.text.len(), fade_out));
23635            }
23636
23637            runs
23638        })
23639}
23640
23641pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23642    let mut prev_index = 0;
23643    let mut prev_codepoint: Option<char> = None;
23644    text.char_indices()
23645        .chain([(text.len(), '\0')])
23646        .filter_map(move |(index, codepoint)| {
23647            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23648            let is_boundary = index == text.len()
23649                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23650                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23651            if is_boundary {
23652                let chunk = &text[prev_index..index];
23653                prev_index = index;
23654                Some(chunk)
23655            } else {
23656                None
23657            }
23658        })
23659}
23660
23661pub trait RangeToAnchorExt: Sized {
23662    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23663
23664    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23665        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23666        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23667    }
23668}
23669
23670impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23671    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23672        let start_offset = self.start.to_offset(snapshot);
23673        let end_offset = self.end.to_offset(snapshot);
23674        if start_offset == end_offset {
23675            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23676        } else {
23677            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23678        }
23679    }
23680}
23681
23682pub trait RowExt {
23683    fn as_f32(&self) -> f32;
23684
23685    fn next_row(&self) -> Self;
23686
23687    fn previous_row(&self) -> Self;
23688
23689    fn minus(&self, other: Self) -> u32;
23690}
23691
23692impl RowExt for DisplayRow {
23693    fn as_f32(&self) -> f32 {
23694        self.0 as f32
23695    }
23696
23697    fn next_row(&self) -> Self {
23698        Self(self.0 + 1)
23699    }
23700
23701    fn previous_row(&self) -> Self {
23702        Self(self.0.saturating_sub(1))
23703    }
23704
23705    fn minus(&self, other: Self) -> u32 {
23706        self.0 - other.0
23707    }
23708}
23709
23710impl RowExt for MultiBufferRow {
23711    fn as_f32(&self) -> f32 {
23712        self.0 as f32
23713    }
23714
23715    fn next_row(&self) -> Self {
23716        Self(self.0 + 1)
23717    }
23718
23719    fn previous_row(&self) -> Self {
23720        Self(self.0.saturating_sub(1))
23721    }
23722
23723    fn minus(&self, other: Self) -> u32 {
23724        self.0 - other.0
23725    }
23726}
23727
23728trait RowRangeExt {
23729    type Row;
23730
23731    fn len(&self) -> usize;
23732
23733    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23734}
23735
23736impl RowRangeExt for Range<MultiBufferRow> {
23737    type Row = MultiBufferRow;
23738
23739    fn len(&self) -> usize {
23740        (self.end.0 - self.start.0) as usize
23741    }
23742
23743    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23744        (self.start.0..self.end.0).map(MultiBufferRow)
23745    }
23746}
23747
23748impl RowRangeExt for Range<DisplayRow> {
23749    type Row = DisplayRow;
23750
23751    fn len(&self) -> usize {
23752        (self.end.0 - self.start.0) as usize
23753    }
23754
23755    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23756        (self.start.0..self.end.0).map(DisplayRow)
23757    }
23758}
23759
23760/// If select range has more than one line, we
23761/// just point the cursor to range.start.
23762fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23763    if range.start.row == range.end.row {
23764        range
23765    } else {
23766        range.start..range.start
23767    }
23768}
23769pub struct KillRing(ClipboardItem);
23770impl Global for KillRing {}
23771
23772const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23773
23774enum BreakpointPromptEditAction {
23775    Log,
23776    Condition,
23777    HitCondition,
23778}
23779
23780struct BreakpointPromptEditor {
23781    pub(crate) prompt: Entity<Editor>,
23782    editor: WeakEntity<Editor>,
23783    breakpoint_anchor: Anchor,
23784    breakpoint: Breakpoint,
23785    edit_action: BreakpointPromptEditAction,
23786    block_ids: HashSet<CustomBlockId>,
23787    editor_margins: Arc<Mutex<EditorMargins>>,
23788    _subscriptions: Vec<Subscription>,
23789}
23790
23791impl BreakpointPromptEditor {
23792    const MAX_LINES: u8 = 4;
23793
23794    fn new(
23795        editor: WeakEntity<Editor>,
23796        breakpoint_anchor: Anchor,
23797        breakpoint: Breakpoint,
23798        edit_action: BreakpointPromptEditAction,
23799        window: &mut Window,
23800        cx: &mut Context<Self>,
23801    ) -> Self {
23802        let base_text = match edit_action {
23803            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23804            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23805            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23806        }
23807        .map(|msg| msg.to_string())
23808        .unwrap_or_default();
23809
23810        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23811        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23812
23813        let prompt = cx.new(|cx| {
23814            let mut prompt = Editor::new(
23815                EditorMode::AutoHeight {
23816                    min_lines: 1,
23817                    max_lines: Some(Self::MAX_LINES as usize),
23818                },
23819                buffer,
23820                None,
23821                window,
23822                cx,
23823            );
23824            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23825            prompt.set_show_cursor_when_unfocused(false, cx);
23826            prompt.set_placeholder_text(
23827                match edit_action {
23828                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23829                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23830                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23831                },
23832                cx,
23833            );
23834
23835            prompt
23836        });
23837
23838        Self {
23839            prompt,
23840            editor,
23841            breakpoint_anchor,
23842            breakpoint,
23843            edit_action,
23844            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23845            block_ids: Default::default(),
23846            _subscriptions: vec![],
23847        }
23848    }
23849
23850    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23851        self.block_ids.extend(block_ids)
23852    }
23853
23854    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23855        if let Some(editor) = self.editor.upgrade() {
23856            let message = self
23857                .prompt
23858                .read(cx)
23859                .buffer
23860                .read(cx)
23861                .as_singleton()
23862                .expect("A multi buffer in breakpoint prompt isn't possible")
23863                .read(cx)
23864                .as_rope()
23865                .to_string();
23866
23867            editor.update(cx, |editor, cx| {
23868                editor.edit_breakpoint_at_anchor(
23869                    self.breakpoint_anchor,
23870                    self.breakpoint.clone(),
23871                    match self.edit_action {
23872                        BreakpointPromptEditAction::Log => {
23873                            BreakpointEditAction::EditLogMessage(message.into())
23874                        }
23875                        BreakpointPromptEditAction::Condition => {
23876                            BreakpointEditAction::EditCondition(message.into())
23877                        }
23878                        BreakpointPromptEditAction::HitCondition => {
23879                            BreakpointEditAction::EditHitCondition(message.into())
23880                        }
23881                    },
23882                    cx,
23883                );
23884
23885                editor.remove_blocks(self.block_ids.clone(), None, cx);
23886                cx.focus_self(window);
23887            });
23888        }
23889    }
23890
23891    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23892        self.editor
23893            .update(cx, |editor, cx| {
23894                editor.remove_blocks(self.block_ids.clone(), None, cx);
23895                window.focus(&editor.focus_handle);
23896            })
23897            .log_err();
23898    }
23899
23900    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23901        let settings = ThemeSettings::get_global(cx);
23902        let text_style = TextStyle {
23903            color: if self.prompt.read(cx).read_only(cx) {
23904                cx.theme().colors().text_disabled
23905            } else {
23906                cx.theme().colors().text
23907            },
23908            font_family: settings.buffer_font.family.clone(),
23909            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23910            font_size: settings.buffer_font_size(cx).into(),
23911            font_weight: settings.buffer_font.weight,
23912            line_height: relative(settings.buffer_line_height.value()),
23913            ..Default::default()
23914        };
23915        EditorElement::new(
23916            &self.prompt,
23917            EditorStyle {
23918                background: cx.theme().colors().editor_background,
23919                local_player: cx.theme().players().local(),
23920                text: text_style,
23921                ..Default::default()
23922            },
23923        )
23924    }
23925}
23926
23927impl Render for BreakpointPromptEditor {
23928    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23929        let editor_margins = *self.editor_margins.lock();
23930        let gutter_dimensions = editor_margins.gutter;
23931        h_flex()
23932            .key_context("Editor")
23933            .bg(cx.theme().colors().editor_background)
23934            .border_y_1()
23935            .border_color(cx.theme().status().info_border)
23936            .size_full()
23937            .py(window.line_height() / 2.5)
23938            .on_action(cx.listener(Self::confirm))
23939            .on_action(cx.listener(Self::cancel))
23940            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23941            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23942    }
23943}
23944
23945impl Focusable for BreakpointPromptEditor {
23946    fn focus_handle(&self, cx: &App) -> FocusHandle {
23947        self.prompt.focus_handle(cx)
23948    }
23949}
23950
23951fn all_edits_insertions_or_deletions(
23952    edits: &Vec<(Range<Anchor>, String)>,
23953    snapshot: &MultiBufferSnapshot,
23954) -> bool {
23955    let mut all_insertions = true;
23956    let mut all_deletions = true;
23957
23958    for (range, new_text) in edits.iter() {
23959        let range_is_empty = range.to_offset(snapshot).is_empty();
23960        let text_is_empty = new_text.is_empty();
23961
23962        if range_is_empty != text_is_empty {
23963            if range_is_empty {
23964                all_deletions = false;
23965            } else {
23966                all_insertions = false;
23967            }
23968        } else {
23969            return false;
23970        }
23971
23972        if !all_insertions && !all_deletions {
23973            return false;
23974        }
23975    }
23976    all_insertions || all_deletions
23977}
23978
23979struct MissingEditPredictionKeybindingTooltip;
23980
23981impl Render for MissingEditPredictionKeybindingTooltip {
23982    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23983        ui::tooltip_container(window, cx, |container, _, cx| {
23984            container
23985                .flex_shrink_0()
23986                .max_w_80()
23987                .min_h(rems_from_px(124.))
23988                .justify_between()
23989                .child(
23990                    v_flex()
23991                        .flex_1()
23992                        .text_ui_sm(cx)
23993                        .child(Label::new("Conflict with Accept Keybinding"))
23994                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23995                )
23996                .child(
23997                    h_flex()
23998                        .pb_1()
23999                        .gap_1()
24000                        .items_end()
24001                        .w_full()
24002                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24003                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24004                        }))
24005                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24006                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24007                        })),
24008                )
24009        })
24010    }
24011}
24012
24013#[derive(Debug, Clone, Copy, PartialEq)]
24014pub struct LineHighlight {
24015    pub background: Background,
24016    pub border: Option<gpui::Hsla>,
24017    pub include_gutter: bool,
24018    pub type_id: Option<TypeId>,
24019}
24020
24021struct LineManipulationResult {
24022    pub new_text: String,
24023    pub line_count_before: usize,
24024    pub line_count_after: usize,
24025}
24026
24027fn render_diff_hunk_controls(
24028    row: u32,
24029    status: &DiffHunkStatus,
24030    hunk_range: Range<Anchor>,
24031    is_created_file: bool,
24032    line_height: Pixels,
24033    editor: &Entity<Editor>,
24034    _window: &mut Window,
24035    cx: &mut App,
24036) -> AnyElement {
24037    h_flex()
24038        .h(line_height)
24039        .mr_1()
24040        .gap_1()
24041        .px_0p5()
24042        .pb_1()
24043        .border_x_1()
24044        .border_b_1()
24045        .border_color(cx.theme().colors().border_variant)
24046        .rounded_b_lg()
24047        .bg(cx.theme().colors().editor_background)
24048        .gap_1()
24049        .block_mouse_except_scroll()
24050        .shadow_md()
24051        .child(if status.has_secondary_hunk() {
24052            Button::new(("stage", row as u64), "Stage")
24053                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24054                .tooltip({
24055                    let focus_handle = editor.focus_handle(cx);
24056                    move |window, cx| {
24057                        Tooltip::for_action_in(
24058                            "Stage Hunk",
24059                            &::git::ToggleStaged,
24060                            &focus_handle,
24061                            window,
24062                            cx,
24063                        )
24064                    }
24065                })
24066                .on_click({
24067                    let editor = editor.clone();
24068                    move |_event, _window, cx| {
24069                        editor.update(cx, |editor, cx| {
24070                            editor.stage_or_unstage_diff_hunks(
24071                                true,
24072                                vec![hunk_range.start..hunk_range.start],
24073                                cx,
24074                            );
24075                        });
24076                    }
24077                })
24078        } else {
24079            Button::new(("unstage", row as u64), "Unstage")
24080                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24081                .tooltip({
24082                    let focus_handle = editor.focus_handle(cx);
24083                    move |window, cx| {
24084                        Tooltip::for_action_in(
24085                            "Unstage Hunk",
24086                            &::git::ToggleStaged,
24087                            &focus_handle,
24088                            window,
24089                            cx,
24090                        )
24091                    }
24092                })
24093                .on_click({
24094                    let editor = editor.clone();
24095                    move |_event, _window, cx| {
24096                        editor.update(cx, |editor, cx| {
24097                            editor.stage_or_unstage_diff_hunks(
24098                                false,
24099                                vec![hunk_range.start..hunk_range.start],
24100                                cx,
24101                            );
24102                        });
24103                    }
24104                })
24105        })
24106        .child(
24107            Button::new(("restore", row as u64), "Restore")
24108                .tooltip({
24109                    let focus_handle = editor.focus_handle(cx);
24110                    move |window, cx| {
24111                        Tooltip::for_action_in(
24112                            "Restore Hunk",
24113                            &::git::Restore,
24114                            &focus_handle,
24115                            window,
24116                            cx,
24117                        )
24118                    }
24119                })
24120                .on_click({
24121                    let editor = editor.clone();
24122                    move |_event, window, cx| {
24123                        editor.update(cx, |editor, cx| {
24124                            let snapshot = editor.snapshot(window, cx);
24125                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24126                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24127                        });
24128                    }
24129                })
24130                .disabled(is_created_file),
24131        )
24132        .when(
24133            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24134            |el| {
24135                el.child(
24136                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24137                        .shape(IconButtonShape::Square)
24138                        .icon_size(IconSize::Small)
24139                        // .disabled(!has_multiple_hunks)
24140                        .tooltip({
24141                            let focus_handle = editor.focus_handle(cx);
24142                            move |window, cx| {
24143                                Tooltip::for_action_in(
24144                                    "Next Hunk",
24145                                    &GoToHunk,
24146                                    &focus_handle,
24147                                    window,
24148                                    cx,
24149                                )
24150                            }
24151                        })
24152                        .on_click({
24153                            let editor = editor.clone();
24154                            move |_event, window, cx| {
24155                                editor.update(cx, |editor, cx| {
24156                                    let snapshot = editor.snapshot(window, cx);
24157                                    let position =
24158                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24159                                    editor.go_to_hunk_before_or_after_position(
24160                                        &snapshot,
24161                                        position,
24162                                        Direction::Next,
24163                                        window,
24164                                        cx,
24165                                    );
24166                                    editor.expand_selected_diff_hunks(cx);
24167                                });
24168                            }
24169                        }),
24170                )
24171                .child(
24172                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24173                        .shape(IconButtonShape::Square)
24174                        .icon_size(IconSize::Small)
24175                        // .disabled(!has_multiple_hunks)
24176                        .tooltip({
24177                            let focus_handle = editor.focus_handle(cx);
24178                            move |window, cx| {
24179                                Tooltip::for_action_in(
24180                                    "Previous Hunk",
24181                                    &GoToPreviousHunk,
24182                                    &focus_handle,
24183                                    window,
24184                                    cx,
24185                                )
24186                            }
24187                        })
24188                        .on_click({
24189                            let editor = editor.clone();
24190                            move |_event, window, cx| {
24191                                editor.update(cx, |editor, cx| {
24192                                    let snapshot = editor.snapshot(window, cx);
24193                                    let point =
24194                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24195                                    editor.go_to_hunk_before_or_after_position(
24196                                        &snapshot,
24197                                        point,
24198                                        Direction::Prev,
24199                                        window,
24200                                        cx,
24201                                    );
24202                                    editor.expand_selected_diff_hunks(cx);
24203                                });
24204                            }
24205                        }),
24206                )
24207            },
24208        )
24209        .into_any_element()
24210}
24211
24212pub fn multibuffer_context_lines(cx: &App) -> u32 {
24213    EditorSettings::try_get(cx)
24214        .map(|settings| settings.excerpt_context_lines)
24215        .unwrap_or(2)
24216        .clamp(1, 32)
24217}