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::Itertools;
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253struct InlineValueCache {
  254    enabled: bool,
  255    inlays: Vec<InlayId>,
  256    refresh_task: Task<Option<()>>,
  257}
  258
  259impl InlineValueCache {
  260    fn new(enabled: bool) -> Self {
  261        Self {
  262            enabled,
  263            inlays: Vec::new(),
  264            refresh_task: Task::ready(None),
  265        }
  266    }
  267}
  268
  269#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  270pub enum InlayId {
  271    EditPrediction(usize),
  272    DebuggerValue(usize),
  273    // LSP
  274    Hint(usize),
  275    Color(usize),
  276}
  277
  278impl InlayId {
  279    fn id(&self) -> usize {
  280        match self {
  281            Self::EditPrediction(id) => *id,
  282            Self::DebuggerValue(id) => *id,
  283            Self::Hint(id) => *id,
  284            Self::Color(id) => *id,
  285        }
  286    }
  287}
  288
  289pub enum ActiveDebugLine {}
  290pub enum DebugStackFrameLine {}
  291enum DocumentHighlightRead {}
  292enum DocumentHighlightWrite {}
  293enum InputComposition {}
  294pub enum PendingInput {}
  295enum SelectedTextHighlight {}
  296
  297pub enum ConflictsOuter {}
  298pub enum ConflictsOurs {}
  299pub enum ConflictsTheirs {}
  300pub enum ConflictsOursMarker {}
  301pub enum ConflictsTheirsMarker {}
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326    },
  327}
  328
  329pub enum HideMouseCursorOrigin {
  330    TypingAction,
  331    MovementAction,
  332}
  333
  334pub fn init_settings(cx: &mut App) {
  335    EditorSettings::register(cx);
  336}
  337
  338pub fn init(cx: &mut App) {
  339    init_settings(cx);
  340
  341    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  342
  343    workspace::register_project_item::<Editor>(cx);
  344    workspace::FollowableViewRegistry::register::<Editor>(cx);
  345    workspace::register_serializable_item::<Editor>(cx);
  346
  347    cx.observe_new(
  348        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  349            workspace.register_action(Editor::new_file);
  350            workspace.register_action(Editor::new_file_vertical);
  351            workspace.register_action(Editor::new_file_horizontal);
  352            workspace.register_action(Editor::cancel_language_server_work);
  353            workspace.register_action(Editor::toggle_focus);
  354        },
  355    )
  356    .detach();
  357
  358    cx.on_action(move |_: &workspace::NewFile, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        if let Some(app_state) = app_state.upgrade() {
  361            workspace::open_new(
  362                Default::default(),
  363                app_state,
  364                cx,
  365                |workspace, window, cx| {
  366                    Editor::new_file(workspace, &Default::default(), window, cx)
  367                },
  368            )
  369            .detach();
  370        }
  371    });
  372    cx.on_action(move |_: &workspace::NewWindow, cx| {
  373        let app_state = workspace::AppState::global(cx);
  374        if let Some(app_state) = app_state.upgrade() {
  375            workspace::open_new(
  376                Default::default(),
  377                app_state,
  378                cx,
  379                |workspace, window, cx| {
  380                    cx.activate(true);
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387}
  388
  389pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  390    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  391}
  392
  393pub trait DiagnosticRenderer {
  394    fn render_group(
  395        &self,
  396        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  397        buffer_id: BufferId,
  398        snapshot: EditorSnapshot,
  399        editor: WeakEntity<Editor>,
  400        cx: &mut App,
  401    ) -> Vec<BlockProperties<Anchor>>;
  402
  403    fn render_hover(
  404        &self,
  405        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  406        range: Range<Point>,
  407        buffer_id: BufferId,
  408        cx: &mut App,
  409    ) -> Option<Entity<markdown::Markdown>>;
  410
  411    fn open_link(
  412        &self,
  413        editor: &mut Editor,
  414        link: SharedString,
  415        window: &mut Window,
  416        cx: &mut Context<Editor>,
  417    );
  418}
  419
  420pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  421
  422impl GlobalDiagnosticRenderer {
  423    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  424        cx.try_global::<Self>().map(|g| g.0.clone())
  425    }
  426}
  427
  428impl gpui::Global for GlobalDiagnosticRenderer {}
  429pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  430    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  431}
  432
  433pub struct SearchWithinRange;
  434
  435trait InvalidationRegion {
  436    fn ranges(&self) -> &[Range<Anchor>];
  437}
  438
  439#[derive(Clone, Debug, PartialEq)]
  440pub enum SelectPhase {
  441    Begin {
  442        position: DisplayPoint,
  443        add: bool,
  444        click_count: usize,
  445    },
  446    BeginColumnar {
  447        position: DisplayPoint,
  448        reset: bool,
  449        mode: ColumnarMode,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug, PartialEq)]
  465pub enum ColumnarMode {
  466    FromMouse,
  467    FromSelection,
  468}
  469
  470#[derive(Clone, Debug)]
  471pub enum SelectMode {
  472    Character,
  473    Word(Range<Anchor>),
  474    Line(Range<Anchor>),
  475    All,
  476}
  477
  478#[derive(Clone, PartialEq, Eq, Debug)]
  479pub enum EditorMode {
  480    SingleLine,
  481    AutoHeight {
  482        min_lines: usize,
  483        max_lines: Option<usize>,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// When set to `true`, the editor's height will be determined by its content.
  491        sized_by_content: bool,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sized_by_content: false,
  504        }
  505    }
  506
  507    #[inline]
  508    pub fn is_full(&self) -> bool {
  509        matches!(self, Self::Full { .. })
  510    }
  511
  512    #[inline]
  513    pub fn is_single_line(&self) -> bool {
  514        matches!(self, Self::SingleLine { .. })
  515    }
  516
  517    #[inline]
  518    fn is_minimap(&self) -> bool {
  519        matches!(self, Self::Minimap { .. })
  520    }
  521}
  522
  523#[derive(Copy, Clone, Debug)]
  524pub enum SoftWrap {
  525    /// Prefer not to wrap at all.
  526    ///
  527    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  528    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  529    GitDiff,
  530    /// Prefer a single line generally, unless an overly long line is encountered.
  531    None,
  532    /// Soft wrap lines that exceed the editor width.
  533    EditorWidth,
  534    /// Soft wrap lines at the preferred line length.
  535    Column(u32),
  536    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  537    Bounded(u32),
  538}
  539
  540#[derive(Clone)]
  541pub struct EditorStyle {
  542    pub background: Hsla,
  543    pub border: Hsla,
  544    pub local_player: PlayerColor,
  545    pub text: TextStyle,
  546    pub scrollbar_width: Pixels,
  547    pub syntax: Arc<SyntaxTheme>,
  548    pub status: StatusColors,
  549    pub inlay_hints_style: HighlightStyle,
  550    pub edit_prediction_styles: EditPredictionStyles,
  551    pub unnecessary_code_fade: f32,
  552    pub show_underlines: bool,
  553}
  554
  555impl Default for EditorStyle {
  556    fn default() -> Self {
  557        Self {
  558            background: Hsla::default(),
  559            border: Hsla::default(),
  560            local_player: PlayerColor::default(),
  561            text: TextStyle::default(),
  562            scrollbar_width: Pixels::default(),
  563            syntax: Default::default(),
  564            // HACK: Status colors don't have a real default.
  565            // We should look into removing the status colors from the editor
  566            // style and retrieve them directly from the theme.
  567            status: StatusColors::dark(),
  568            inlay_hints_style: HighlightStyle::default(),
  569            edit_prediction_styles: EditPredictionStyles {
  570                insertion: HighlightStyle::default(),
  571                whitespace: HighlightStyle::default(),
  572            },
  573            unnecessary_code_fade: Default::default(),
  574            show_underlines: true,
  575        }
  576    }
  577}
  578
  579pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  580    let show_background = language_settings::language_settings(None, None, cx)
  581        .inlay_hints
  582        .show_background;
  583
  584    HighlightStyle {
  585        color: Some(cx.theme().status().hint),
  586        background_color: show_background.then(|| cx.theme().status().hint_background),
  587        ..HighlightStyle::default()
  588    }
  589}
  590
  591pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  592    EditPredictionStyles {
  593        insertion: HighlightStyle {
  594            color: Some(cx.theme().status().predictive),
  595            ..HighlightStyle::default()
  596        },
  597        whitespace: HighlightStyle {
  598            background_color: Some(cx.theme().status().created_background),
  599            ..HighlightStyle::default()
  600        },
  601    }
  602}
  603
  604type CompletionId = usize;
  605
  606pub(crate) enum EditDisplayMode {
  607    TabAccept,
  608    DiffPopover,
  609    Inline,
  610}
  611
  612enum EditPrediction {
  613    Edit {
  614        edits: Vec<(Range<Anchor>, String)>,
  615        edit_preview: Option<EditPreview>,
  616        display_mode: EditDisplayMode,
  617        snapshot: BufferSnapshot,
  618    },
  619    Move {
  620        target: Anchor,
  621        snapshot: BufferSnapshot,
  622    },
  623}
  624
  625struct EditPredictionState {
  626    inlay_ids: Vec<InlayId>,
  627    completion: EditPrediction,
  628    completion_id: Option<SharedString>,
  629    invalidation_range: Range<Anchor>,
  630}
  631
  632enum EditPredictionSettings {
  633    Disabled,
  634    Enabled {
  635        show_in_menu: bool,
  636        preview_requires_modifier: bool,
  637    },
  638}
  639
  640enum EditPredictionHighlight {}
  641
  642#[derive(Debug, Clone)]
  643struct InlineDiagnostic {
  644    message: SharedString,
  645    group_id: usize,
  646    is_primary: bool,
  647    start: Point,
  648    severity: lsp::DiagnosticSeverity,
  649}
  650
  651pub enum MenuEditPredictionsPolicy {
  652    Never,
  653    ByProvider,
  654}
  655
  656pub enum EditPredictionPreview {
  657    /// Modifier is not pressed
  658    Inactive { released_too_fast: bool },
  659    /// Modifier pressed
  660    Active {
  661        since: Instant,
  662        previous_scroll_position: Option<ScrollAnchor>,
  663    },
  664}
  665
  666impl EditPredictionPreview {
  667    pub fn released_too_fast(&self) -> bool {
  668        match self {
  669            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  670            EditPredictionPreview::Active { .. } => false,
  671        }
  672    }
  673
  674    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  675        if let EditPredictionPreview::Active {
  676            previous_scroll_position,
  677            ..
  678        } = self
  679        {
  680            *previous_scroll_position = scroll_position;
  681        }
  682    }
  683}
  684
  685pub struct ContextMenuOptions {
  686    pub min_entries_visible: usize,
  687    pub max_entries_visible: usize,
  688    pub placement: Option<ContextMenuPlacement>,
  689}
  690
  691#[derive(Debug, Clone, PartialEq, Eq)]
  692pub enum ContextMenuPlacement {
  693    Above,
  694    Below,
  695}
  696
  697#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  698struct EditorActionId(usize);
  699
  700impl EditorActionId {
  701    pub fn post_inc(&mut self) -> Self {
  702        let answer = self.0;
  703
  704        *self = Self(answer + 1);
  705
  706        Self(answer)
  707    }
  708}
  709
  710// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  711// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  712
  713type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  714type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  715
  716#[derive(Default)]
  717struct ScrollbarMarkerState {
  718    scrollbar_size: Size<Pixels>,
  719    dirty: bool,
  720    markers: Arc<[PaintQuad]>,
  721    pending_refresh: Option<Task<Result<()>>>,
  722}
  723
  724impl ScrollbarMarkerState {
  725    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  726        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  727    }
  728}
  729
  730#[derive(Clone, Copy, PartialEq, Eq)]
  731pub enum MinimapVisibility {
  732    Disabled,
  733    Enabled {
  734        /// The configuration currently present in the users settings.
  735        setting_configuration: bool,
  736        /// Whether to override the currently set visibility from the users setting.
  737        toggle_override: bool,
  738    },
  739}
  740
  741impl MinimapVisibility {
  742    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  743        if mode.is_full() {
  744            Self::Enabled {
  745                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  746                toggle_override: false,
  747            }
  748        } else {
  749            Self::Disabled
  750        }
  751    }
  752
  753    fn hidden(&self) -> Self {
  754        match *self {
  755            Self::Enabled {
  756                setting_configuration,
  757                ..
  758            } => Self::Enabled {
  759                setting_configuration,
  760                toggle_override: setting_configuration,
  761            },
  762            Self::Disabled => Self::Disabled,
  763        }
  764    }
  765
  766    fn disabled(&self) -> bool {
  767        match *self {
  768            Self::Disabled => true,
  769            _ => false,
  770        }
  771    }
  772
  773    fn settings_visibility(&self) -> bool {
  774        match *self {
  775            Self::Enabled {
  776                setting_configuration,
  777                ..
  778            } => setting_configuration,
  779            _ => false,
  780        }
  781    }
  782
  783    fn visible(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                toggle_override,
  788            } => setting_configuration ^ toggle_override,
  789            _ => false,
  790        }
  791    }
  792
  793    fn toggle_visibility(&self) -> Self {
  794        match *self {
  795            Self::Enabled {
  796                toggle_override,
  797                setting_configuration,
  798            } => Self::Enabled {
  799                setting_configuration,
  800                toggle_override: !toggle_override,
  801            },
  802            Self::Disabled => Self::Disabled,
  803        }
  804    }
  805}
  806
  807#[derive(Clone, Debug)]
  808struct RunnableTasks {
  809    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  810    offset: multi_buffer::Anchor,
  811    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  812    column: u32,
  813    // Values of all named captures, including those starting with '_'
  814    extra_variables: HashMap<String, String>,
  815    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  816    context_range: Range<BufferOffset>,
  817}
  818
  819impl RunnableTasks {
  820    fn resolve<'a>(
  821        &'a self,
  822        cx: &'a task::TaskContext,
  823    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  824        self.templates.iter().filter_map(|(kind, template)| {
  825            template
  826                .resolve_task(&kind.to_id_base(), cx)
  827                .map(|task| (kind.clone(), task))
  828        })
  829    }
  830}
  831
  832#[derive(Clone)]
  833pub struct ResolvedTasks {
  834    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  835    position: Anchor,
  836}
  837
  838#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  839struct BufferOffset(usize);
  840
  841// Addons allow storing per-editor state in other crates (e.g. Vim)
  842pub trait Addon: 'static {
  843    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  844
  845    fn render_buffer_header_controls(
  846        &self,
  847        _: &ExcerptInfo,
  848        _: &Window,
  849        _: &App,
  850    ) -> Option<AnyElement> {
  851        None
  852    }
  853
  854    fn to_any(&self) -> &dyn std::any::Any;
  855
  856    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  857        None
  858    }
  859}
  860
  861struct ChangeLocation {
  862    current: Option<Vec<Anchor>>,
  863    original: Vec<Anchor>,
  864}
  865impl ChangeLocation {
  866    fn locations(&self) -> &[Anchor] {
  867        self.current.as_ref().unwrap_or(&self.original)
  868    }
  869}
  870
  871/// A set of caret positions, registered when the editor was edited.
  872pub struct ChangeList {
  873    changes: Vec<ChangeLocation>,
  874    /// Currently "selected" change.
  875    position: Option<usize>,
  876}
  877
  878impl ChangeList {
  879    pub fn new() -> Self {
  880        Self {
  881            changes: Vec::new(),
  882            position: None,
  883        }
  884    }
  885
  886    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  887    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  888    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  889        if self.changes.is_empty() {
  890            return None;
  891        }
  892
  893        let prev = self.position.unwrap_or(self.changes.len());
  894        let next = if direction == Direction::Prev {
  895            prev.saturating_sub(count)
  896        } else {
  897            (prev + count).min(self.changes.len() - 1)
  898        };
  899        self.position = Some(next);
  900        self.changes.get(next).map(|change| change.locations())
  901    }
  902
  903    /// Adds a new change to the list, resetting the change list position.
  904    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  905        self.position.take();
  906        if let Some(last) = self.changes.last_mut()
  907            && group
  908        {
  909            last.current = Some(new_positions)
  910        } else {
  911            self.changes.push(ChangeLocation {
  912                original: new_positions,
  913                current: None,
  914            });
  915        }
  916    }
  917
  918    pub fn last(&self) -> Option<&[Anchor]> {
  919        self.changes.last().map(|change| change.locations())
  920    }
  921
  922    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  923        self.changes.last().map(|change| change.original.as_slice())
  924    }
  925
  926    pub fn invert_last_group(&mut self) {
  927        if let Some(last) = self.changes.last_mut() {
  928            if let Some(current) = last.current.as_mut() {
  929                mem::swap(&mut last.original, current);
  930            }
  931        }
  932    }
  933}
  934
  935#[derive(Clone)]
  936struct InlineBlamePopoverState {
  937    scroll_handle: ScrollHandle,
  938    commit_message: Option<ParsedCommitMessage>,
  939    markdown: Entity<Markdown>,
  940}
  941
  942struct InlineBlamePopover {
  943    position: gpui::Point<Pixels>,
  944    hide_task: Option<Task<()>>,
  945    popover_bounds: Option<Bounds<Pixels>>,
  946    popover_state: InlineBlamePopoverState,
  947    keyboard_grace: bool,
  948}
  949
  950enum SelectionDragState {
  951    /// State when no drag related activity is detected.
  952    None,
  953    /// State when the mouse is down on a selection that is about to be dragged.
  954    ReadyToDrag {
  955        selection: Selection<Anchor>,
  956        click_position: gpui::Point<Pixels>,
  957        mouse_down_time: Instant,
  958    },
  959    /// State when the mouse is dragging the selection in the editor.
  960    Dragging {
  961        selection: Selection<Anchor>,
  962        drop_cursor: Selection<Anchor>,
  963        hide_drop_cursor: bool,
  964    },
  965}
  966
  967enum ColumnarSelectionState {
  968    FromMouse {
  969        selection_tail: Anchor,
  970        display_point: Option<DisplayPoint>,
  971    },
  972    FromSelection {
  973        selection_tail: Anchor,
  974    },
  975}
  976
  977/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  978/// a breakpoint on them.
  979#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  980struct PhantomBreakpointIndicator {
  981    display_row: DisplayRow,
  982    /// There's a small debounce between hovering over the line and showing the indicator.
  983    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  984    is_active: bool,
  985    collides_with_existing_breakpoint: bool,
  986}
  987
  988/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  989///
  990/// See the [module level documentation](self) for more information.
  991pub struct Editor {
  992    focus_handle: FocusHandle,
  993    last_focused_descendant: Option<WeakFocusHandle>,
  994    /// The text buffer being edited
  995    buffer: Entity<MultiBuffer>,
  996    /// Map of how text in the buffer should be displayed.
  997    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  998    pub display_map: Entity<DisplayMap>,
  999    pub selections: SelectionsCollection,
 1000    pub scroll_manager: ScrollManager,
 1001    /// When inline assist editors are linked, they all render cursors because
 1002    /// typing enters text into each of them, even the ones that aren't focused.
 1003    pub(crate) show_cursor_when_unfocused: bool,
 1004    columnar_selection_state: Option<ColumnarSelectionState>,
 1005    add_selections_state: Option<AddSelectionsState>,
 1006    select_next_state: Option<SelectNextState>,
 1007    select_prev_state: Option<SelectNextState>,
 1008    selection_history: SelectionHistory,
 1009    defer_selection_effects: bool,
 1010    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1011    autoclose_regions: Vec<AutocloseRegion>,
 1012    snippet_stack: InvalidationStack<SnippetState>,
 1013    select_syntax_node_history: SelectSyntaxNodeHistory,
 1014    ime_transaction: Option<TransactionId>,
 1015    pub diagnostics_max_severity: DiagnosticSeverity,
 1016    active_diagnostics: ActiveDiagnostic,
 1017    show_inline_diagnostics: bool,
 1018    inline_diagnostics_update: Task<()>,
 1019    inline_diagnostics_enabled: bool,
 1020    diagnostics_enabled: bool,
 1021    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1022    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1023    hard_wrap: Option<usize>,
 1024
 1025    // TODO: make this a access method
 1026    pub project: Option<Entity<Project>>,
 1027    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1028    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1029    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1030    blink_manager: Entity<BlinkManager>,
 1031    show_cursor_names: bool,
 1032    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1033    pub show_local_selections: bool,
 1034    mode: EditorMode,
 1035    show_breadcrumbs: bool,
 1036    show_gutter: bool,
 1037    show_scrollbars: ScrollbarAxes,
 1038    minimap_visibility: MinimapVisibility,
 1039    offset_content: bool,
 1040    disable_expand_excerpt_buttons: bool,
 1041    show_line_numbers: Option<bool>,
 1042    use_relative_line_numbers: Option<bool>,
 1043    show_git_diff_gutter: Option<bool>,
 1044    show_code_actions: Option<bool>,
 1045    show_runnables: Option<bool>,
 1046    show_breakpoints: Option<bool>,
 1047    show_wrap_guides: Option<bool>,
 1048    show_indent_guides: Option<bool>,
 1049    placeholder_text: Option<Arc<str>>,
 1050    highlight_order: usize,
 1051    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1052    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1053    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1054    scrollbar_marker_state: ScrollbarMarkerState,
 1055    active_indent_guides_state: ActiveIndentGuidesState,
 1056    nav_history: Option<ItemNavHistory>,
 1057    context_menu: RefCell<Option<CodeContextMenu>>,
 1058    context_menu_options: Option<ContextMenuOptions>,
 1059    mouse_context_menu: Option<MouseContextMenu>,
 1060    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1061    inline_blame_popover: Option<InlineBlamePopover>,
 1062    inline_blame_popover_show_task: Option<Task<()>>,
 1063    signature_help_state: SignatureHelpState,
 1064    auto_signature_help: Option<bool>,
 1065    find_all_references_task_sources: Vec<Anchor>,
 1066    next_completion_id: CompletionId,
 1067    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1068    code_actions_task: Option<Task<Result<()>>>,
 1069    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1070    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1071    document_highlights_task: Option<Task<()>>,
 1072    linked_editing_range_task: Option<Task<Option<()>>>,
 1073    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1074    pending_rename: Option<RenameState>,
 1075    searchable: bool,
 1076    cursor_shape: CursorShape,
 1077    current_line_highlight: Option<CurrentLineHighlight>,
 1078    collapse_matches: bool,
 1079    autoindent_mode: Option<AutoindentMode>,
 1080    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1081    input_enabled: bool,
 1082    use_modal_editing: bool,
 1083    read_only: bool,
 1084    leader_id: Option<CollaboratorId>,
 1085    remote_id: Option<ViewId>,
 1086    pub hover_state: HoverState,
 1087    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1088    gutter_hovered: bool,
 1089    hovered_link_state: Option<HoveredLinkState>,
 1090    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1091    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1092    active_edit_prediction: Option<EditPredictionState>,
 1093    /// Used to prevent flickering as the user types while the menu is open
 1094    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1095    edit_prediction_settings: EditPredictionSettings,
 1096    edit_predictions_hidden_for_vim_mode: bool,
 1097    show_edit_predictions_override: Option<bool>,
 1098    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1099    edit_prediction_preview: EditPredictionPreview,
 1100    edit_prediction_indent_conflict: bool,
 1101    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1102    inlay_hint_cache: InlayHintCache,
 1103    next_inlay_id: usize,
 1104    _subscriptions: Vec<Subscription>,
 1105    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1106    gutter_dimensions: GutterDimensions,
 1107    style: Option<EditorStyle>,
 1108    text_style_refinement: Option<TextStyleRefinement>,
 1109    next_editor_action_id: EditorActionId,
 1110    editor_actions: Rc<
 1111        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1112    >,
 1113    use_autoclose: bool,
 1114    use_auto_surround: bool,
 1115    auto_replace_emoji_shortcode: bool,
 1116    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1117    show_git_blame_gutter: bool,
 1118    show_git_blame_inline: bool,
 1119    show_git_blame_inline_delay_task: Option<Task<()>>,
 1120    git_blame_inline_enabled: bool,
 1121    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1122    serialize_dirty_buffers: bool,
 1123    show_selection_menu: Option<bool>,
 1124    blame: Option<Entity<GitBlame>>,
 1125    blame_subscription: Option<Subscription>,
 1126    custom_context_menu: Option<
 1127        Box<
 1128            dyn 'static
 1129                + Fn(
 1130                    &mut Self,
 1131                    DisplayPoint,
 1132                    &mut Window,
 1133                    &mut Context<Self>,
 1134                ) -> Option<Entity<ui::ContextMenu>>,
 1135        >,
 1136    >,
 1137    last_bounds: Option<Bounds<Pixels>>,
 1138    last_position_map: Option<Rc<PositionMap>>,
 1139    expect_bounds_change: Option<Bounds<Pixels>>,
 1140    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1141    tasks_update_task: Option<Task<()>>,
 1142    breakpoint_store: Option<Entity<BreakpointStore>>,
 1143    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1144    hovered_diff_hunk_row: Option<DisplayRow>,
 1145    pull_diagnostics_task: Task<()>,
 1146    in_project_search: bool,
 1147    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1148    breadcrumb_header: Option<String>,
 1149    focused_block: Option<FocusedBlock>,
 1150    next_scroll_position: NextScrollCursorCenterTopBottom,
 1151    addons: HashMap<TypeId, Box<dyn Addon>>,
 1152    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1153    load_diff_task: Option<Shared<Task<()>>>,
 1154    /// Whether we are temporarily displaying a diff other than git's
 1155    temporary_diff_override: bool,
 1156    selection_mark_mode: bool,
 1157    toggle_fold_multiple_buffers: Task<()>,
 1158    _scroll_cursor_center_top_bottom_task: Task<()>,
 1159    serialize_selections: Task<()>,
 1160    serialize_folds: Task<()>,
 1161    mouse_cursor_hidden: bool,
 1162    minimap: Option<Entity<Self>>,
 1163    hide_mouse_mode: HideMouseMode,
 1164    pub change_list: ChangeList,
 1165    inline_value_cache: InlineValueCache,
 1166    selection_drag_state: SelectionDragState,
 1167    next_color_inlay_id: usize,
 1168    colors: Option<LspColorData>,
 1169    folding_newlines: Task<()>,
 1170}
 1171
 1172#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1173enum NextScrollCursorCenterTopBottom {
 1174    #[default]
 1175    Center,
 1176    Top,
 1177    Bottom,
 1178}
 1179
 1180impl NextScrollCursorCenterTopBottom {
 1181    fn next(&self) -> Self {
 1182        match self {
 1183            Self::Center => Self::Top,
 1184            Self::Top => Self::Bottom,
 1185            Self::Bottom => Self::Center,
 1186        }
 1187    }
 1188}
 1189
 1190#[derive(Clone)]
 1191pub struct EditorSnapshot {
 1192    pub mode: EditorMode,
 1193    show_gutter: bool,
 1194    show_line_numbers: Option<bool>,
 1195    show_git_diff_gutter: Option<bool>,
 1196    show_code_actions: Option<bool>,
 1197    show_runnables: Option<bool>,
 1198    show_breakpoints: Option<bool>,
 1199    git_blame_gutter_max_author_length: Option<usize>,
 1200    pub display_snapshot: DisplaySnapshot,
 1201    pub placeholder_text: Option<Arc<str>>,
 1202    is_focused: bool,
 1203    scroll_anchor: ScrollAnchor,
 1204    ongoing_scroll: OngoingScroll,
 1205    current_line_highlight: CurrentLineHighlight,
 1206    gutter_hovered: bool,
 1207}
 1208
 1209#[derive(Default, Debug, Clone, Copy)]
 1210pub struct GutterDimensions {
 1211    pub left_padding: Pixels,
 1212    pub right_padding: Pixels,
 1213    pub width: Pixels,
 1214    pub margin: Pixels,
 1215    pub git_blame_entries_width: Option<Pixels>,
 1216}
 1217
 1218impl GutterDimensions {
 1219    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1220        Self {
 1221            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1222            ..Default::default()
 1223        }
 1224    }
 1225
 1226    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1227        -cx.text_system().descent(font_id, font_size)
 1228    }
 1229    /// The full width of the space taken up by the gutter.
 1230    pub fn full_width(&self) -> Pixels {
 1231        self.margin + self.width
 1232    }
 1233
 1234    /// The width of the space reserved for the fold indicators,
 1235    /// use alongside 'justify_end' and `gutter_width` to
 1236    /// right align content with the line numbers
 1237    pub fn fold_area_width(&self) -> Pixels {
 1238        self.margin + self.right_padding
 1239    }
 1240}
 1241
 1242struct CharacterDimensions {
 1243    em_width: Pixels,
 1244    em_advance: Pixels,
 1245    line_height: Pixels,
 1246}
 1247
 1248#[derive(Debug)]
 1249pub struct RemoteSelection {
 1250    pub replica_id: ReplicaId,
 1251    pub selection: Selection<Anchor>,
 1252    pub cursor_shape: CursorShape,
 1253    pub collaborator_id: CollaboratorId,
 1254    pub line_mode: bool,
 1255    pub user_name: Option<SharedString>,
 1256    pub color: PlayerColor,
 1257}
 1258
 1259#[derive(Clone, Debug)]
 1260struct SelectionHistoryEntry {
 1261    selections: Arc<[Selection<Anchor>]>,
 1262    select_next_state: Option<SelectNextState>,
 1263    select_prev_state: Option<SelectNextState>,
 1264    add_selections_state: Option<AddSelectionsState>,
 1265}
 1266
 1267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1268enum SelectionHistoryMode {
 1269    Normal,
 1270    Undoing,
 1271    Redoing,
 1272    Skipping,
 1273}
 1274
 1275#[derive(Clone, PartialEq, Eq, Hash)]
 1276struct HoveredCursor {
 1277    replica_id: u16,
 1278    selection_id: usize,
 1279}
 1280
 1281impl Default for SelectionHistoryMode {
 1282    fn default() -> Self {
 1283        Self::Normal
 1284    }
 1285}
 1286
 1287#[derive(Debug)]
 1288/// SelectionEffects controls the side-effects of updating the selection.
 1289///
 1290/// The default behaviour does "what you mostly want":
 1291/// - it pushes to the nav history if the cursor moved by >10 lines
 1292/// - it re-triggers completion requests
 1293/// - it scrolls to fit
 1294///
 1295/// You might want to modify these behaviours. For example when doing a "jump"
 1296/// like go to definition, we always want to add to nav history; but when scrolling
 1297/// in vim mode we never do.
 1298///
 1299/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1300/// move.
 1301#[derive(Clone)]
 1302pub struct SelectionEffects {
 1303    nav_history: Option<bool>,
 1304    completions: bool,
 1305    scroll: Option<Autoscroll>,
 1306}
 1307
 1308impl Default for SelectionEffects {
 1309    fn default() -> Self {
 1310        Self {
 1311            nav_history: None,
 1312            completions: true,
 1313            scroll: Some(Autoscroll::fit()),
 1314        }
 1315    }
 1316}
 1317impl SelectionEffects {
 1318    pub fn scroll(scroll: Autoscroll) -> Self {
 1319        Self {
 1320            scroll: Some(scroll),
 1321            ..Default::default()
 1322        }
 1323    }
 1324
 1325    pub fn no_scroll() -> Self {
 1326        Self {
 1327            scroll: None,
 1328            ..Default::default()
 1329        }
 1330    }
 1331
 1332    pub fn completions(self, completions: bool) -> Self {
 1333        Self {
 1334            completions,
 1335            ..self
 1336        }
 1337    }
 1338
 1339    pub fn nav_history(self, nav_history: bool) -> Self {
 1340        Self {
 1341            nav_history: Some(nav_history),
 1342            ..self
 1343        }
 1344    }
 1345}
 1346
 1347struct DeferredSelectionEffectsState {
 1348    changed: bool,
 1349    effects: SelectionEffects,
 1350    old_cursor_position: Anchor,
 1351    history_entry: SelectionHistoryEntry,
 1352}
 1353
 1354#[derive(Default)]
 1355struct SelectionHistory {
 1356    #[allow(clippy::type_complexity)]
 1357    selections_by_transaction:
 1358        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1359    mode: SelectionHistoryMode,
 1360    undo_stack: VecDeque<SelectionHistoryEntry>,
 1361    redo_stack: VecDeque<SelectionHistoryEntry>,
 1362}
 1363
 1364impl SelectionHistory {
 1365    #[track_caller]
 1366    fn insert_transaction(
 1367        &mut self,
 1368        transaction_id: TransactionId,
 1369        selections: Arc<[Selection<Anchor>]>,
 1370    ) {
 1371        if selections.is_empty() {
 1372            log::error!(
 1373                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1374                std::panic::Location::caller()
 1375            );
 1376            return;
 1377        }
 1378        self.selections_by_transaction
 1379            .insert(transaction_id, (selections, None));
 1380    }
 1381
 1382    #[allow(clippy::type_complexity)]
 1383    fn transaction(
 1384        &self,
 1385        transaction_id: TransactionId,
 1386    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1387        self.selections_by_transaction.get(&transaction_id)
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction_mut(
 1392        &mut self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get_mut(&transaction_id)
 1396    }
 1397
 1398    fn push(&mut self, entry: SelectionHistoryEntry) {
 1399        if !entry.selections.is_empty() {
 1400            match self.mode {
 1401                SelectionHistoryMode::Normal => {
 1402                    self.push_undo(entry);
 1403                    self.redo_stack.clear();
 1404                }
 1405                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1406                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1407                SelectionHistoryMode::Skipping => {}
 1408            }
 1409        }
 1410    }
 1411
 1412    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1413        if self
 1414            .undo_stack
 1415            .back()
 1416            .map_or(true, |e| e.selections != entry.selections)
 1417        {
 1418            self.undo_stack.push_back(entry);
 1419            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1420                self.undo_stack.pop_front();
 1421            }
 1422        }
 1423    }
 1424
 1425    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1426        if self
 1427            .redo_stack
 1428            .back()
 1429            .map_or(true, |e| e.selections != entry.selections)
 1430        {
 1431            self.redo_stack.push_back(entry);
 1432            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1433                self.redo_stack.pop_front();
 1434            }
 1435        }
 1436    }
 1437}
 1438
 1439#[derive(Clone, Copy)]
 1440pub struct RowHighlightOptions {
 1441    pub autoscroll: bool,
 1442    pub include_gutter: bool,
 1443}
 1444
 1445impl Default for RowHighlightOptions {
 1446    fn default() -> Self {
 1447        Self {
 1448            autoscroll: Default::default(),
 1449            include_gutter: true,
 1450        }
 1451    }
 1452}
 1453
 1454struct RowHighlight {
 1455    index: usize,
 1456    range: Range<Anchor>,
 1457    color: Hsla,
 1458    options: RowHighlightOptions,
 1459    type_id: TypeId,
 1460}
 1461
 1462#[derive(Clone, Debug)]
 1463struct AddSelectionsState {
 1464    groups: Vec<AddSelectionsGroup>,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsGroup {
 1469    above: bool,
 1470    stack: Vec<usize>,
 1471}
 1472
 1473#[derive(Clone)]
 1474struct SelectNextState {
 1475    query: AhoCorasick,
 1476    wordwise: bool,
 1477    done: bool,
 1478}
 1479
 1480impl std::fmt::Debug for SelectNextState {
 1481    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1482        f.debug_struct(std::any::type_name::<Self>())
 1483            .field("wordwise", &self.wordwise)
 1484            .field("done", &self.done)
 1485            .finish()
 1486    }
 1487}
 1488
 1489#[derive(Debug)]
 1490struct AutocloseRegion {
 1491    selection_id: usize,
 1492    range: Range<Anchor>,
 1493    pair: BracketPair,
 1494}
 1495
 1496#[derive(Debug)]
 1497struct SnippetState {
 1498    ranges: Vec<Vec<Range<Anchor>>>,
 1499    active_index: usize,
 1500    choices: Vec<Option<Vec<String>>>,
 1501}
 1502
 1503#[doc(hidden)]
 1504pub struct RenameState {
 1505    pub range: Range<Anchor>,
 1506    pub old_name: Arc<str>,
 1507    pub editor: Entity<Editor>,
 1508    block_id: CustomBlockId,
 1509}
 1510
 1511struct InvalidationStack<T>(Vec<T>);
 1512
 1513struct RegisteredEditPredictionProvider {
 1514    provider: Arc<dyn EditPredictionProviderHandle>,
 1515    _subscription: Subscription,
 1516}
 1517
 1518#[derive(Debug, PartialEq, Eq)]
 1519pub struct ActiveDiagnosticGroup {
 1520    pub active_range: Range<Anchor>,
 1521    pub active_message: String,
 1522    pub group_id: usize,
 1523    pub blocks: HashSet<CustomBlockId>,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527
 1528pub(crate) enum ActiveDiagnostic {
 1529    None,
 1530    All,
 1531    Group(ActiveDiagnosticGroup),
 1532}
 1533
 1534#[derive(Serialize, Deserialize, Clone, Debug)]
 1535pub struct ClipboardSelection {
 1536    /// The number of bytes in this selection.
 1537    pub len: usize,
 1538    /// Whether this was a full-line selection.
 1539    pub is_entire_line: bool,
 1540    /// The indentation of the first line when this content was originally copied.
 1541    pub first_line_indent: u32,
 1542}
 1543
 1544// selections, scroll behavior, was newest selection reversed
 1545type SelectSyntaxNodeHistoryState = (
 1546    Box<[Selection<usize>]>,
 1547    SelectSyntaxNodeScrollBehavior,
 1548    bool,
 1549);
 1550
 1551#[derive(Default)]
 1552struct SelectSyntaxNodeHistory {
 1553    stack: Vec<SelectSyntaxNodeHistoryState>,
 1554    // disable temporarily to allow changing selections without losing the stack
 1555    pub disable_clearing: bool,
 1556}
 1557
 1558impl SelectSyntaxNodeHistory {
 1559    pub fn try_clear(&mut self) {
 1560        if !self.disable_clearing {
 1561            self.stack.clear();
 1562        }
 1563    }
 1564
 1565    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1566        self.stack.push(selection);
 1567    }
 1568
 1569    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1570        self.stack.pop()
 1571    }
 1572}
 1573
 1574enum SelectSyntaxNodeScrollBehavior {
 1575    CursorTop,
 1576    FitSelection,
 1577    CursorBottom,
 1578}
 1579
 1580#[derive(Debug)]
 1581pub(crate) struct NavigationData {
 1582    cursor_anchor: Anchor,
 1583    cursor_position: Point,
 1584    scroll_anchor: ScrollAnchor,
 1585    scroll_top_row: u32,
 1586}
 1587
 1588#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1589pub enum GotoDefinitionKind {
 1590    Symbol,
 1591    Declaration,
 1592    Type,
 1593    Implementation,
 1594}
 1595
 1596#[derive(Debug, Clone)]
 1597enum InlayHintRefreshReason {
 1598    ModifiersChanged(bool),
 1599    Toggle(bool),
 1600    SettingsChange(InlayHintSettings),
 1601    NewLinesShown,
 1602    BufferEdited(HashSet<Arc<Language>>),
 1603    RefreshRequested,
 1604    ExcerptsRemoved(Vec<ExcerptId>),
 1605}
 1606
 1607impl InlayHintRefreshReason {
 1608    fn description(&self) -> &'static str {
 1609        match self {
 1610            Self::ModifiersChanged(_) => "modifiers changed",
 1611            Self::Toggle(_) => "toggle",
 1612            Self::SettingsChange(_) => "settings change",
 1613            Self::NewLinesShown => "new lines shown",
 1614            Self::BufferEdited(_) => "buffer edited",
 1615            Self::RefreshRequested => "refresh requested",
 1616            Self::ExcerptsRemoved(_) => "excerpts removed",
 1617        }
 1618    }
 1619}
 1620
 1621pub enum FormatTarget {
 1622    Buffers(HashSet<Entity<Buffer>>),
 1623    Ranges(Vec<Range<MultiBufferPoint>>),
 1624}
 1625
 1626pub(crate) struct FocusedBlock {
 1627    id: BlockId,
 1628    focus_handle: WeakFocusHandle,
 1629}
 1630
 1631#[derive(Clone)]
 1632enum JumpData {
 1633    MultiBufferRow {
 1634        row: MultiBufferRow,
 1635        line_offset_from_top: u32,
 1636    },
 1637    MultiBufferPoint {
 1638        excerpt_id: ExcerptId,
 1639        position: Point,
 1640        anchor: text::Anchor,
 1641        line_offset_from_top: u32,
 1642    },
 1643}
 1644
 1645pub enum MultibufferSelectionMode {
 1646    First,
 1647    All,
 1648}
 1649
 1650#[derive(Clone, Copy, Debug, Default)]
 1651pub struct RewrapOptions {
 1652    pub override_language_settings: bool,
 1653    pub preserve_existing_whitespace: bool,
 1654}
 1655
 1656impl Editor {
 1657    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1658        let buffer = cx.new(|cx| Buffer::local("", cx));
 1659        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1660        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1661    }
 1662
 1663    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::full(), buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn auto_height(
 1670        min_lines: usize,
 1671        max_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: Some(max_lines),
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1690    /// The editor grows as tall as needed to fit its content.
 1691    pub fn auto_height_unbounded(
 1692        min_lines: usize,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| Buffer::local("", cx));
 1697        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1698        Self::new(
 1699            EditorMode::AutoHeight {
 1700                min_lines,
 1701                max_lines: None,
 1702            },
 1703            buffer,
 1704            None,
 1705            window,
 1706            cx,
 1707        )
 1708    }
 1709
 1710    pub fn for_buffer(
 1711        buffer: Entity<Buffer>,
 1712        project: Option<Entity<Project>>,
 1713        window: &mut Window,
 1714        cx: &mut Context<Self>,
 1715    ) -> Self {
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(EditorMode::full(), buffer, project, window, cx)
 1718    }
 1719
 1720    pub fn for_multibuffer(
 1721        buffer: Entity<MultiBuffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        Self::new(EditorMode::full(), buffer, project, window, cx)
 1727    }
 1728
 1729    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1730        let mut clone = Self::new(
 1731            self.mode.clone(),
 1732            self.buffer.clone(),
 1733            self.project.clone(),
 1734            window,
 1735            cx,
 1736        );
 1737        self.display_map.update(cx, |display_map, cx| {
 1738            let snapshot = display_map.snapshot(cx);
 1739            clone.display_map.update(cx, |display_map, cx| {
 1740                display_map.set_state(&snapshot, cx);
 1741            });
 1742        });
 1743        clone.folds_did_change(cx);
 1744        clone.selections.clone_state(&self.selections);
 1745        clone.scroll_manager.clone_state(&self.scroll_manager);
 1746        clone.searchable = self.searchable;
 1747        clone.read_only = self.read_only;
 1748        clone
 1749    }
 1750
 1751    pub fn new(
 1752        mode: EditorMode,
 1753        buffer: Entity<MultiBuffer>,
 1754        project: Option<Entity<Project>>,
 1755        window: &mut Window,
 1756        cx: &mut Context<Self>,
 1757    ) -> Self {
 1758        Editor::new_internal(mode, buffer, project, None, window, cx)
 1759    }
 1760
 1761    fn new_internal(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        display_map: Option<Entity<DisplayMap>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        debug_assert!(
 1770            display_map.is_none() || mode.is_minimap(),
 1771            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1772        );
 1773
 1774        let full_mode = mode.is_full();
 1775        let is_minimap = mode.is_minimap();
 1776        let diagnostics_max_severity = if full_mode {
 1777            EditorSettings::get_global(cx)
 1778                .diagnostics_max_severity
 1779                .unwrap_or(DiagnosticSeverity::Hint)
 1780        } else {
 1781            DiagnosticSeverity::Off
 1782        };
 1783        let style = window.text_style();
 1784        let font_size = style.font_size.to_pixels(window.rem_size());
 1785        let editor = cx.entity().downgrade();
 1786        let fold_placeholder = FoldPlaceholder {
 1787            constrain_width: true,
 1788            render: Arc::new(move |fold_id, fold_range, cx| {
 1789                let editor = editor.clone();
 1790                div()
 1791                    .id(fold_id)
 1792                    .bg(cx.theme().colors().ghost_element_background)
 1793                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1794                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1795                    .rounded_xs()
 1796                    .size_full()
 1797                    .cursor_pointer()
 1798                    .child("")
 1799                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1800                    .on_click(move |_, _window, cx| {
 1801                        editor
 1802                            .update(cx, |editor, cx| {
 1803                                editor.unfold_ranges(
 1804                                    &[fold_range.start..fold_range.end],
 1805                                    true,
 1806                                    false,
 1807                                    cx,
 1808                                );
 1809                                cx.stop_propagation();
 1810                            })
 1811                            .ok();
 1812                    })
 1813                    .into_any()
 1814            }),
 1815            merge_adjacent: true,
 1816            ..FoldPlaceholder::default()
 1817        };
 1818        let display_map = display_map.unwrap_or_else(|| {
 1819            cx.new(|cx| {
 1820                DisplayMap::new(
 1821                    buffer.clone(),
 1822                    style.font(),
 1823                    font_size,
 1824                    None,
 1825                    FILE_HEADER_HEIGHT,
 1826                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1827                    fold_placeholder,
 1828                    diagnostics_max_severity,
 1829                    cx,
 1830                )
 1831            })
 1832        });
 1833
 1834        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1835
 1836        let blink_manager = cx.new(|cx| {
 1837            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1838            if is_minimap {
 1839                blink_manager.disable(cx);
 1840            }
 1841            blink_manager
 1842        });
 1843
 1844        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1845            .then(|| language_settings::SoftWrap::None);
 1846
 1847        let mut project_subscriptions = Vec::new();
 1848        if full_mode {
 1849            if let Some(project) = project.as_ref() {
 1850                project_subscriptions.push(cx.subscribe_in(
 1851                    project,
 1852                    window,
 1853                    |editor, _, event, window, cx| match event {
 1854                        project::Event::RefreshCodeLens => {
 1855                            // we always query lens with actions, without storing them, always refreshing them
 1856                        }
 1857                        project::Event::RefreshInlayHints => {
 1858                            editor
 1859                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1860                        }
 1861                        project::Event::LanguageServerAdded(..)
 1862                        | project::Event::LanguageServerRemoved(..) => {
 1863                            if editor.tasks_update_task.is_none() {
 1864                                editor.tasks_update_task =
 1865                                    Some(editor.refresh_runnables(window, cx));
 1866                            }
 1867                        }
 1868                        project::Event::SnippetEdit(id, snippet_edits) => {
 1869                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1870                                let focus_handle = editor.focus_handle(cx);
 1871                                if focus_handle.is_focused(window) {
 1872                                    let snapshot = buffer.read(cx).snapshot();
 1873                                    for (range, snippet) in snippet_edits {
 1874                                        let editor_range =
 1875                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1876                                        editor
 1877                                            .insert_snippet(
 1878                                                &[editor_range],
 1879                                                snippet.clone(),
 1880                                                window,
 1881                                                cx,
 1882                                            )
 1883                                            .ok();
 1884                                    }
 1885                                }
 1886                            }
 1887                        }
 1888                        project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1889                            if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1890                                editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1891                            }
 1892                        }
 1893                        _ => {}
 1894                    },
 1895                ));
 1896                if let Some(task_inventory) = project
 1897                    .read(cx)
 1898                    .task_store()
 1899                    .read(cx)
 1900                    .task_inventory()
 1901                    .cloned()
 1902                {
 1903                    project_subscriptions.push(cx.observe_in(
 1904                        &task_inventory,
 1905                        window,
 1906                        |editor, _, window, cx| {
 1907                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1908                        },
 1909                    ));
 1910                };
 1911
 1912                project_subscriptions.push(cx.subscribe_in(
 1913                    &project.read(cx).breakpoint_store(),
 1914                    window,
 1915                    |editor, _, event, window, cx| match event {
 1916                        BreakpointStoreEvent::ClearDebugLines => {
 1917                            editor.clear_row_highlights::<ActiveDebugLine>();
 1918                            editor.refresh_inline_values(cx);
 1919                        }
 1920                        BreakpointStoreEvent::SetDebugLine => {
 1921                            if editor.go_to_active_debug_line(window, cx) {
 1922                                cx.stop_propagation();
 1923                            }
 1924
 1925                            editor.refresh_inline_values(cx);
 1926                        }
 1927                        _ => {}
 1928                    },
 1929                ));
 1930                let git_store = project.read(cx).git_store().clone();
 1931                let project = project.clone();
 1932                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1933                    match event {
 1934                        GitStoreEvent::RepositoryUpdated(
 1935                            _,
 1936                            RepositoryEvent::Updated {
 1937                                new_instance: true, ..
 1938                            },
 1939                            _,
 1940                        ) => {
 1941                            this.load_diff_task = Some(
 1942                                update_uncommitted_diff_for_buffer(
 1943                                    cx.entity(),
 1944                                    &project,
 1945                                    this.buffer.read(cx).all_buffers(),
 1946                                    this.buffer.clone(),
 1947                                    cx,
 1948                                )
 1949                                .shared(),
 1950                            );
 1951                        }
 1952                        _ => {}
 1953                    }
 1954                }));
 1955            }
 1956        }
 1957
 1958        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1959
 1960        let inlay_hint_settings =
 1961            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1962        let focus_handle = cx.focus_handle();
 1963        if !is_minimap {
 1964            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1965                .detach();
 1966            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1967                .detach();
 1968            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1969                .detach();
 1970            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1971                .detach();
 1972            cx.observe_pending_input(window, Self::observe_pending_input)
 1973                .detach();
 1974        }
 1975
 1976        let show_indent_guides = if matches!(
 1977            mode,
 1978            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1979        ) {
 1980            Some(false)
 1981        } else {
 1982            None
 1983        };
 1984
 1985        let breakpoint_store = match (&mode, project.as_ref()) {
 1986            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1987            _ => None,
 1988        };
 1989
 1990        let mut code_action_providers = Vec::new();
 1991        let mut load_uncommitted_diff = None;
 1992        if let Some(project) = project.clone() {
 1993            load_uncommitted_diff = Some(
 1994                update_uncommitted_diff_for_buffer(
 1995                    cx.entity(),
 1996                    &project,
 1997                    buffer.read(cx).all_buffers(),
 1998                    buffer.clone(),
 1999                    cx,
 2000                )
 2001                .shared(),
 2002            );
 2003            code_action_providers.push(Rc::new(project) as Rc<_>);
 2004        }
 2005
 2006        let mut editor = Self {
 2007            focus_handle,
 2008            show_cursor_when_unfocused: false,
 2009            last_focused_descendant: None,
 2010            buffer: buffer.clone(),
 2011            display_map: display_map.clone(),
 2012            selections,
 2013            scroll_manager: ScrollManager::new(cx),
 2014            columnar_selection_state: None,
 2015            add_selections_state: None,
 2016            select_next_state: None,
 2017            select_prev_state: None,
 2018            selection_history: SelectionHistory::default(),
 2019            defer_selection_effects: false,
 2020            deferred_selection_effects_state: None,
 2021            autoclose_regions: Vec::new(),
 2022            snippet_stack: InvalidationStack::default(),
 2023            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2024            ime_transaction: None,
 2025            active_diagnostics: ActiveDiagnostic::None,
 2026            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2027            inline_diagnostics_update: Task::ready(()),
 2028            inline_diagnostics: Vec::new(),
 2029            soft_wrap_mode_override,
 2030            diagnostics_max_severity,
 2031            hard_wrap: None,
 2032            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2033            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2034            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2035            project,
 2036            blink_manager: blink_manager.clone(),
 2037            show_local_selections: true,
 2038            show_scrollbars: ScrollbarAxes {
 2039                horizontal: full_mode,
 2040                vertical: full_mode,
 2041            },
 2042            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2043            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2044            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2045            show_gutter: full_mode,
 2046            show_line_numbers: (!full_mode).then_some(false),
 2047            use_relative_line_numbers: None,
 2048            disable_expand_excerpt_buttons: !full_mode,
 2049            show_git_diff_gutter: None,
 2050            show_code_actions: None,
 2051            show_runnables: None,
 2052            show_breakpoints: None,
 2053            show_wrap_guides: None,
 2054            show_indent_guides,
 2055            placeholder_text: None,
 2056            highlight_order: 0,
 2057            highlighted_rows: HashMap::default(),
 2058            background_highlights: TreeMap::default(),
 2059            gutter_highlights: TreeMap::default(),
 2060            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2061            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2062            nav_history: None,
 2063            context_menu: RefCell::new(None),
 2064            context_menu_options: None,
 2065            mouse_context_menu: None,
 2066            completion_tasks: Vec::new(),
 2067            inline_blame_popover: None,
 2068            inline_blame_popover_show_task: None,
 2069            signature_help_state: SignatureHelpState::default(),
 2070            auto_signature_help: None,
 2071            find_all_references_task_sources: Vec::new(),
 2072            next_completion_id: 0,
 2073            next_inlay_id: 0,
 2074            code_action_providers,
 2075            available_code_actions: None,
 2076            code_actions_task: None,
 2077            quick_selection_highlight_task: None,
 2078            debounced_selection_highlight_task: None,
 2079            document_highlights_task: None,
 2080            linked_editing_range_task: None,
 2081            pending_rename: None,
 2082            searchable: !is_minimap,
 2083            cursor_shape: EditorSettings::get_global(cx)
 2084                .cursor_shape
 2085                .unwrap_or_default(),
 2086            current_line_highlight: None,
 2087            autoindent_mode: Some(AutoindentMode::EachLine),
 2088            collapse_matches: false,
 2089            workspace: None,
 2090            input_enabled: !is_minimap,
 2091            use_modal_editing: full_mode,
 2092            read_only: is_minimap,
 2093            use_autoclose: true,
 2094            use_auto_surround: true,
 2095            auto_replace_emoji_shortcode: false,
 2096            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2097            leader_id: None,
 2098            remote_id: None,
 2099            hover_state: HoverState::default(),
 2100            pending_mouse_down: None,
 2101            hovered_link_state: None,
 2102            edit_prediction_provider: None,
 2103            active_edit_prediction: None,
 2104            stale_edit_prediction_in_menu: None,
 2105            edit_prediction_preview: EditPredictionPreview::Inactive {
 2106                released_too_fast: false,
 2107            },
 2108            inline_diagnostics_enabled: full_mode,
 2109            diagnostics_enabled: full_mode,
 2110            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2111            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2112            gutter_hovered: false,
 2113            pixel_position_of_newest_cursor: None,
 2114            last_bounds: None,
 2115            last_position_map: None,
 2116            expect_bounds_change: None,
 2117            gutter_dimensions: GutterDimensions::default(),
 2118            style: None,
 2119            show_cursor_names: false,
 2120            hovered_cursors: HashMap::default(),
 2121            next_editor_action_id: EditorActionId::default(),
 2122            editor_actions: Rc::default(),
 2123            edit_predictions_hidden_for_vim_mode: false,
 2124            show_edit_predictions_override: None,
 2125            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2126            edit_prediction_settings: EditPredictionSettings::Disabled,
 2127            edit_prediction_indent_conflict: false,
 2128            edit_prediction_requires_modifier_in_indent_conflict: true,
 2129            custom_context_menu: None,
 2130            show_git_blame_gutter: false,
 2131            show_git_blame_inline: false,
 2132            show_selection_menu: None,
 2133            show_git_blame_inline_delay_task: None,
 2134            git_blame_inline_enabled: full_mode
 2135                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2136            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2137            serialize_dirty_buffers: !is_minimap
 2138                && ProjectSettings::get_global(cx)
 2139                    .session
 2140                    .restore_unsaved_buffers,
 2141            blame: None,
 2142            blame_subscription: None,
 2143            tasks: BTreeMap::default(),
 2144
 2145            breakpoint_store,
 2146            gutter_breakpoint_indicator: (None, None),
 2147            hovered_diff_hunk_row: None,
 2148            _subscriptions: (!is_minimap)
 2149                .then(|| {
 2150                    vec![
 2151                        cx.observe(&buffer, Self::on_buffer_changed),
 2152                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2153                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2154                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2155                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2156                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2157                        cx.observe_window_activation(window, |editor, window, cx| {
 2158                            let active = window.is_window_active();
 2159                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2160                                if active {
 2161                                    blink_manager.enable(cx);
 2162                                } else {
 2163                                    blink_manager.disable(cx);
 2164                                }
 2165                            });
 2166                            if active {
 2167                                editor.show_mouse_cursor(cx);
 2168                            }
 2169                        }),
 2170                    ]
 2171                })
 2172                .unwrap_or_default(),
 2173            tasks_update_task: None,
 2174            pull_diagnostics_task: Task::ready(()),
 2175            colors: None,
 2176            next_color_inlay_id: 0,
 2177            linked_edit_ranges: Default::default(),
 2178            in_project_search: false,
 2179            previous_search_ranges: None,
 2180            breadcrumb_header: None,
 2181            focused_block: None,
 2182            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2183            addons: HashMap::default(),
 2184            registered_buffers: HashMap::default(),
 2185            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2186            selection_mark_mode: false,
 2187            toggle_fold_multiple_buffers: Task::ready(()),
 2188            serialize_selections: Task::ready(()),
 2189            serialize_folds: Task::ready(()),
 2190            text_style_refinement: None,
 2191            load_diff_task: load_uncommitted_diff,
 2192            temporary_diff_override: false,
 2193            mouse_cursor_hidden: false,
 2194            minimap: None,
 2195            hide_mouse_mode: EditorSettings::get_global(cx)
 2196                .hide_mouse
 2197                .unwrap_or_default(),
 2198            change_list: ChangeList::new(),
 2199            mode,
 2200            selection_drag_state: SelectionDragState::None,
 2201            folding_newlines: Task::ready(()),
 2202        };
 2203
 2204        if is_minimap {
 2205            return editor;
 2206        }
 2207
 2208        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2209            editor
 2210                ._subscriptions
 2211                .push(cx.observe(breakpoints, |_, _, cx| {
 2212                    cx.notify();
 2213                }));
 2214        }
 2215        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2216        editor._subscriptions.extend(project_subscriptions);
 2217
 2218        editor._subscriptions.push(cx.subscribe_in(
 2219            &cx.entity(),
 2220            window,
 2221            |editor, _, e: &EditorEvent, window, cx| match e {
 2222                EditorEvent::ScrollPositionChanged { local, .. } => {
 2223                    if *local {
 2224                        let new_anchor = editor.scroll_manager.anchor();
 2225                        let snapshot = editor.snapshot(window, cx);
 2226                        editor.update_restoration_data(cx, move |data| {
 2227                            data.scroll_position = (
 2228                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2229                                new_anchor.offset,
 2230                            );
 2231                        });
 2232                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2233                        editor.inline_blame_popover.take();
 2234                    }
 2235                }
 2236                EditorEvent::Edited { .. } => {
 2237                    if !vim_enabled(cx) {
 2238                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2239                        let pop_state = editor
 2240                            .change_list
 2241                            .last()
 2242                            .map(|previous| {
 2243                                previous.len() == selections.len()
 2244                                    && previous.iter().enumerate().all(|(ix, p)| {
 2245                                        p.to_display_point(&map).row()
 2246                                            == selections[ix].head().row()
 2247                                    })
 2248                            })
 2249                            .unwrap_or(false);
 2250                        let new_positions = selections
 2251                            .into_iter()
 2252                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2253                            .collect();
 2254                        editor
 2255                            .change_list
 2256                            .push_to_change_list(pop_state, new_positions);
 2257                    }
 2258                }
 2259                _ => (),
 2260            },
 2261        ));
 2262
 2263        if let Some(dap_store) = editor
 2264            .project
 2265            .as_ref()
 2266            .map(|project| project.read(cx).dap_store())
 2267        {
 2268            let weak_editor = cx.weak_entity();
 2269
 2270            editor
 2271                ._subscriptions
 2272                .push(
 2273                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2274                        let session_entity = cx.entity();
 2275                        weak_editor
 2276                            .update(cx, |editor, cx| {
 2277                                editor._subscriptions.push(
 2278                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2279                                );
 2280                            })
 2281                            .ok();
 2282                    }),
 2283                );
 2284
 2285            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2286                editor
 2287                    ._subscriptions
 2288                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2289            }
 2290        }
 2291
 2292        // skip adding the initial selection to selection history
 2293        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2294        editor.end_selection(window, cx);
 2295        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2296
 2297        editor.scroll_manager.show_scrollbars(window, cx);
 2298        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2299
 2300        if full_mode {
 2301            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2302            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2303
 2304            if editor.git_blame_inline_enabled {
 2305                editor.start_git_blame_inline(false, window, cx);
 2306            }
 2307
 2308            editor.go_to_active_debug_line(window, cx);
 2309
 2310            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2311                if let Some(project) = editor.project.as_ref() {
 2312                    let handle = project.update(cx, |project, cx| {
 2313                        project.register_buffer_with_language_servers(&buffer, cx)
 2314                    });
 2315                    editor
 2316                        .registered_buffers
 2317                        .insert(buffer.read(cx).remote_id(), handle);
 2318                }
 2319            }
 2320
 2321            editor.minimap =
 2322                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2323            editor.colors = Some(LspColorData::new(cx));
 2324            editor.update_lsp_data(false, None, window, cx);
 2325        }
 2326
 2327        if editor.mode.is_full() {
 2328            editor.report_editor_event("Editor Opened", None, cx);
 2329        }
 2330
 2331        editor
 2332    }
 2333
 2334    pub fn deploy_mouse_context_menu(
 2335        &mut self,
 2336        position: gpui::Point<Pixels>,
 2337        context_menu: Entity<ContextMenu>,
 2338        window: &mut Window,
 2339        cx: &mut Context<Self>,
 2340    ) {
 2341        self.mouse_context_menu = Some(MouseContextMenu::new(
 2342            self,
 2343            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2344            context_menu,
 2345            window,
 2346            cx,
 2347        ));
 2348    }
 2349
 2350    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2351        self.mouse_context_menu
 2352            .as_ref()
 2353            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2354    }
 2355
 2356    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2357        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2358    }
 2359
 2360    fn key_context_internal(
 2361        &self,
 2362        has_active_edit_prediction: bool,
 2363        window: &Window,
 2364        cx: &App,
 2365    ) -> KeyContext {
 2366        let mut key_context = KeyContext::new_with_defaults();
 2367        key_context.add("Editor");
 2368        let mode = match self.mode {
 2369            EditorMode::SingleLine { .. } => "single_line",
 2370            EditorMode::AutoHeight { .. } => "auto_height",
 2371            EditorMode::Minimap { .. } => "minimap",
 2372            EditorMode::Full { .. } => "full",
 2373        };
 2374
 2375        if EditorSettings::jupyter_enabled(cx) {
 2376            key_context.add("jupyter");
 2377        }
 2378
 2379        key_context.set("mode", mode);
 2380        if self.pending_rename.is_some() {
 2381            key_context.add("renaming");
 2382        }
 2383
 2384        match self.context_menu.borrow().as_ref() {
 2385            Some(CodeContextMenu::Completions(menu)) => {
 2386                if menu.visible() {
 2387                    key_context.add("menu");
 2388                    key_context.add("showing_completions");
 2389                }
 2390            }
 2391            Some(CodeContextMenu::CodeActions(menu)) => {
 2392                if menu.visible() {
 2393                    key_context.add("menu");
 2394                    key_context.add("showing_code_actions")
 2395                }
 2396            }
 2397            None => {}
 2398        }
 2399
 2400        if self.signature_help_state.has_multiple_signatures() {
 2401            key_context.add("showing_signature_help");
 2402        }
 2403
 2404        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2405        if !self.focus_handle(cx).contains_focused(window, cx)
 2406            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2407        {
 2408            for addon in self.addons.values() {
 2409                addon.extend_key_context(&mut key_context, cx)
 2410            }
 2411        }
 2412
 2413        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2414            if let Some(extension) = singleton_buffer
 2415                .read(cx)
 2416                .file()
 2417                .and_then(|file| file.path().extension()?.to_str())
 2418            {
 2419                key_context.set("extension", extension.to_string());
 2420            }
 2421        } else {
 2422            key_context.add("multibuffer");
 2423        }
 2424
 2425        if has_active_edit_prediction {
 2426            if self.edit_prediction_in_conflict() {
 2427                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2428            } else {
 2429                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2430                key_context.add("copilot_suggestion");
 2431            }
 2432        }
 2433
 2434        if self.selection_mark_mode {
 2435            key_context.add("selection_mode");
 2436        }
 2437
 2438        key_context
 2439    }
 2440
 2441    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2442        if self.mouse_cursor_hidden {
 2443            self.mouse_cursor_hidden = false;
 2444            cx.notify();
 2445        }
 2446    }
 2447
 2448    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2449        let hide_mouse_cursor = match origin {
 2450            HideMouseCursorOrigin::TypingAction => {
 2451                matches!(
 2452                    self.hide_mouse_mode,
 2453                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2454                )
 2455            }
 2456            HideMouseCursorOrigin::MovementAction => {
 2457                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2458            }
 2459        };
 2460        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2461            self.mouse_cursor_hidden = hide_mouse_cursor;
 2462            cx.notify();
 2463        }
 2464    }
 2465
 2466    pub fn edit_prediction_in_conflict(&self) -> bool {
 2467        if !self.show_edit_predictions_in_menu() {
 2468            return false;
 2469        }
 2470
 2471        let showing_completions = self
 2472            .context_menu
 2473            .borrow()
 2474            .as_ref()
 2475            .map_or(false, |context| {
 2476                matches!(context, CodeContextMenu::Completions(_))
 2477            });
 2478
 2479        showing_completions
 2480            || self.edit_prediction_requires_modifier()
 2481            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2482            // bindings to insert tab characters.
 2483            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2484    }
 2485
 2486    pub fn accept_edit_prediction_keybind(
 2487        &self,
 2488        accept_partial: bool,
 2489        window: &Window,
 2490        cx: &App,
 2491    ) -> AcceptEditPredictionBinding {
 2492        let key_context = self.key_context_internal(true, window, cx);
 2493        let in_conflict = self.edit_prediction_in_conflict();
 2494
 2495        let bindings = if accept_partial {
 2496            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2497        } else {
 2498            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2499        };
 2500
 2501        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2502        // just the first one.
 2503        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2504            !in_conflict
 2505                || binding
 2506                    .keystrokes()
 2507                    .first()
 2508                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2509        }))
 2510    }
 2511
 2512    pub fn new_file(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFile,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2519            "Failed to create buffer",
 2520            window,
 2521            cx,
 2522            |e, _, _| match e.error_code() {
 2523                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2524                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2525                e.error_tag("required").unwrap_or("the latest version")
 2526            )),
 2527                _ => None,
 2528            },
 2529        );
 2530    }
 2531
 2532    pub fn new_in_workspace(
 2533        workspace: &mut Workspace,
 2534        window: &mut Window,
 2535        cx: &mut Context<Workspace>,
 2536    ) -> Task<Result<Entity<Editor>>> {
 2537        let project = workspace.project().clone();
 2538        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2539
 2540        cx.spawn_in(window, async move |workspace, cx| {
 2541            let buffer = create.await?;
 2542            workspace.update_in(cx, |workspace, window, cx| {
 2543                let editor =
 2544                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2545                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2546                editor
 2547            })
 2548        })
 2549    }
 2550
 2551    fn new_file_vertical(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitVertical,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_horizontal(
 2561        workspace: &mut Workspace,
 2562        _: &workspace::NewFileSplitHorizontal,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2567    }
 2568
 2569    fn new_file_in_direction(
 2570        workspace: &mut Workspace,
 2571        direction: SplitDirection,
 2572        window: &mut Window,
 2573        cx: &mut Context<Workspace>,
 2574    ) {
 2575        let project = workspace.project().clone();
 2576        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2577
 2578        cx.spawn_in(window, async move |workspace, cx| {
 2579            let buffer = create.await?;
 2580            workspace.update_in(cx, move |workspace, window, cx| {
 2581                workspace.split_item(
 2582                    direction,
 2583                    Box::new(
 2584                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2585                    ),
 2586                    window,
 2587                    cx,
 2588                )
 2589            })?;
 2590            anyhow::Ok(())
 2591        })
 2592        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2593            match e.error_code() {
 2594                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2595                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2596                e.error_tag("required").unwrap_or("the latest version")
 2597            )),
 2598                _ => None,
 2599            }
 2600        });
 2601    }
 2602
 2603    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2604        self.leader_id
 2605    }
 2606
 2607    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2608        &self.buffer
 2609    }
 2610
 2611    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2612        self.workspace.as_ref()?.0.upgrade()
 2613    }
 2614
 2615    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2616        self.buffer().read(cx).title(cx)
 2617    }
 2618
 2619    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2620        let git_blame_gutter_max_author_length = self
 2621            .render_git_blame_gutter(cx)
 2622            .then(|| {
 2623                if let Some(blame) = self.blame.as_ref() {
 2624                    let max_author_length =
 2625                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2626                    Some(max_author_length)
 2627                } else {
 2628                    None
 2629                }
 2630            })
 2631            .flatten();
 2632
 2633        EditorSnapshot {
 2634            mode: self.mode.clone(),
 2635            show_gutter: self.show_gutter,
 2636            show_line_numbers: self.show_line_numbers,
 2637            show_git_diff_gutter: self.show_git_diff_gutter,
 2638            show_code_actions: self.show_code_actions,
 2639            show_runnables: self.show_runnables,
 2640            show_breakpoints: self.show_breakpoints,
 2641            git_blame_gutter_max_author_length,
 2642            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2643            scroll_anchor: self.scroll_manager.anchor(),
 2644            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2645            placeholder_text: self.placeholder_text.clone(),
 2646            is_focused: self.focus_handle.is_focused(window),
 2647            current_line_highlight: self
 2648                .current_line_highlight
 2649                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2650            gutter_hovered: self.gutter_hovered,
 2651        }
 2652    }
 2653
 2654    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2655        self.buffer.read(cx).language_at(point, cx)
 2656    }
 2657
 2658    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2659        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2660    }
 2661
 2662    pub fn active_excerpt(
 2663        &self,
 2664        cx: &App,
 2665    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2666        self.buffer
 2667            .read(cx)
 2668            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2669    }
 2670
 2671    pub fn mode(&self) -> &EditorMode {
 2672        &self.mode
 2673    }
 2674
 2675    pub fn set_mode(&mut self, mode: EditorMode) {
 2676        self.mode = mode;
 2677    }
 2678
 2679    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2680        self.collaboration_hub.as_deref()
 2681    }
 2682
 2683    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2684        self.collaboration_hub = Some(hub);
 2685    }
 2686
 2687    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2688        self.in_project_search = in_project_search;
 2689    }
 2690
 2691    pub fn set_custom_context_menu(
 2692        &mut self,
 2693        f: impl 'static
 2694        + Fn(
 2695            &mut Self,
 2696            DisplayPoint,
 2697            &mut Window,
 2698            &mut Context<Self>,
 2699        ) -> Option<Entity<ui::ContextMenu>>,
 2700    ) {
 2701        self.custom_context_menu = Some(Box::new(f))
 2702    }
 2703
 2704    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2705        self.completion_provider = provider;
 2706    }
 2707
 2708    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2709        self.semantics_provider.clone()
 2710    }
 2711
 2712    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2713        self.semantics_provider = provider;
 2714    }
 2715
 2716    pub fn set_edit_prediction_provider<T>(
 2717        &mut self,
 2718        provider: Option<Entity<T>>,
 2719        window: &mut Window,
 2720        cx: &mut Context<Self>,
 2721    ) where
 2722        T: EditPredictionProvider,
 2723    {
 2724        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2725            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2726                if this.focus_handle.is_focused(window) {
 2727                    this.update_visible_edit_prediction(window, cx);
 2728                }
 2729            }),
 2730            provider: Arc::new(provider),
 2731        });
 2732        self.update_edit_prediction_settings(cx);
 2733        self.refresh_edit_prediction(false, false, window, cx);
 2734    }
 2735
 2736    pub fn placeholder_text(&self) -> Option<&str> {
 2737        self.placeholder_text.as_deref()
 2738    }
 2739
 2740    pub fn set_placeholder_text(
 2741        &mut self,
 2742        placeholder_text: impl Into<Arc<str>>,
 2743        cx: &mut Context<Self>,
 2744    ) {
 2745        let placeholder_text = Some(placeholder_text.into());
 2746        if self.placeholder_text != placeholder_text {
 2747            self.placeholder_text = placeholder_text;
 2748            cx.notify();
 2749        }
 2750    }
 2751
 2752    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2753        self.cursor_shape = cursor_shape;
 2754
 2755        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2756        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2757
 2758        cx.notify();
 2759    }
 2760
 2761    pub fn set_current_line_highlight(
 2762        &mut self,
 2763        current_line_highlight: Option<CurrentLineHighlight>,
 2764    ) {
 2765        self.current_line_highlight = current_line_highlight;
 2766    }
 2767
 2768    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2769        self.collapse_matches = collapse_matches;
 2770    }
 2771
 2772    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2773        let buffers = self.buffer.read(cx).all_buffers();
 2774        let Some(project) = self.project.as_ref() else {
 2775            return;
 2776        };
 2777        project.update(cx, |project, cx| {
 2778            for buffer in buffers {
 2779                self.registered_buffers
 2780                    .entry(buffer.read(cx).remote_id())
 2781                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2782            }
 2783        })
 2784    }
 2785
 2786    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2787        if self.collapse_matches {
 2788            return range.start..range.start;
 2789        }
 2790        range.clone()
 2791    }
 2792
 2793    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2794        if self.display_map.read(cx).clip_at_line_ends != clip {
 2795            self.display_map
 2796                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2797        }
 2798    }
 2799
 2800    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2801        self.input_enabled = input_enabled;
 2802    }
 2803
 2804    pub fn set_edit_predictions_hidden_for_vim_mode(
 2805        &mut self,
 2806        hidden: bool,
 2807        window: &mut Window,
 2808        cx: &mut Context<Self>,
 2809    ) {
 2810        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2811            self.edit_predictions_hidden_for_vim_mode = hidden;
 2812            if hidden {
 2813                self.update_visible_edit_prediction(window, cx);
 2814            } else {
 2815                self.refresh_edit_prediction(true, false, window, cx);
 2816            }
 2817        }
 2818    }
 2819
 2820    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2821        self.menu_edit_predictions_policy = value;
 2822    }
 2823
 2824    pub fn set_autoindent(&mut self, autoindent: bool) {
 2825        if autoindent {
 2826            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2827        } else {
 2828            self.autoindent_mode = None;
 2829        }
 2830    }
 2831
 2832    pub fn read_only(&self, cx: &App) -> bool {
 2833        self.read_only || self.buffer.read(cx).read_only()
 2834    }
 2835
 2836    pub fn set_read_only(&mut self, read_only: bool) {
 2837        self.read_only = read_only;
 2838    }
 2839
 2840    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2841        self.use_autoclose = autoclose;
 2842    }
 2843
 2844    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2845        self.use_auto_surround = auto_surround;
 2846    }
 2847
 2848    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2849        self.auto_replace_emoji_shortcode = auto_replace;
 2850    }
 2851
 2852    pub fn toggle_edit_predictions(
 2853        &mut self,
 2854        _: &ToggleEditPrediction,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        if self.show_edit_predictions_override.is_some() {
 2859            self.set_show_edit_predictions(None, window, cx);
 2860        } else {
 2861            let show_edit_predictions = !self.edit_predictions_enabled();
 2862            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2863        }
 2864    }
 2865
 2866    pub fn set_show_edit_predictions(
 2867        &mut self,
 2868        show_edit_predictions: Option<bool>,
 2869        window: &mut Window,
 2870        cx: &mut Context<Self>,
 2871    ) {
 2872        self.show_edit_predictions_override = show_edit_predictions;
 2873        self.update_edit_prediction_settings(cx);
 2874
 2875        if let Some(false) = show_edit_predictions {
 2876            self.discard_edit_prediction(false, cx);
 2877        } else {
 2878            self.refresh_edit_prediction(false, true, window, cx);
 2879        }
 2880    }
 2881
 2882    fn edit_predictions_disabled_in_scope(
 2883        &self,
 2884        buffer: &Entity<Buffer>,
 2885        buffer_position: language::Anchor,
 2886        cx: &App,
 2887    ) -> bool {
 2888        let snapshot = buffer.read(cx).snapshot();
 2889        let settings = snapshot.settings_at(buffer_position, cx);
 2890
 2891        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2892            return false;
 2893        };
 2894
 2895        scope.override_name().map_or(false, |scope_name| {
 2896            settings
 2897                .edit_predictions_disabled_in
 2898                .iter()
 2899                .any(|s| s == scope_name)
 2900        })
 2901    }
 2902
 2903    pub fn set_use_modal_editing(&mut self, to: bool) {
 2904        self.use_modal_editing = to;
 2905    }
 2906
 2907    pub fn use_modal_editing(&self) -> bool {
 2908        self.use_modal_editing
 2909    }
 2910
 2911    fn selections_did_change(
 2912        &mut self,
 2913        local: bool,
 2914        old_cursor_position: &Anchor,
 2915        effects: SelectionEffects,
 2916        window: &mut Window,
 2917        cx: &mut Context<Self>,
 2918    ) {
 2919        window.invalidate_character_coordinates();
 2920
 2921        // Copy selections to primary selection buffer
 2922        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2923        if local {
 2924            let selections = self.selections.all::<usize>(cx);
 2925            let buffer_handle = self.buffer.read(cx).read(cx);
 2926
 2927            let mut text = String::new();
 2928            for (index, selection) in selections.iter().enumerate() {
 2929                let text_for_selection = buffer_handle
 2930                    .text_for_range(selection.start..selection.end)
 2931                    .collect::<String>();
 2932
 2933                text.push_str(&text_for_selection);
 2934                if index != selections.len() - 1 {
 2935                    text.push('\n');
 2936                }
 2937            }
 2938
 2939            if !text.is_empty() {
 2940                cx.write_to_primary(ClipboardItem::new_string(text));
 2941            }
 2942        }
 2943
 2944        let selection_anchors = self.selections.disjoint_anchors();
 2945
 2946        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2947            self.buffer.update(cx, |buffer, cx| {
 2948                buffer.set_active_selections(
 2949                    &selection_anchors,
 2950                    self.selections.line_mode,
 2951                    self.cursor_shape,
 2952                    cx,
 2953                )
 2954            });
 2955        }
 2956        let display_map = self
 2957            .display_map
 2958            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2959        let buffer = &display_map.buffer_snapshot;
 2960        if self.selections.count() == 1 {
 2961            self.add_selections_state = None;
 2962        }
 2963        self.select_next_state = None;
 2964        self.select_prev_state = None;
 2965        self.select_syntax_node_history.try_clear();
 2966        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2967        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2968        self.take_rename(false, window, cx);
 2969
 2970        let newest_selection = self.selections.newest_anchor();
 2971        let new_cursor_position = newest_selection.head();
 2972        let selection_start = newest_selection.start;
 2973
 2974        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2975            self.push_to_nav_history(
 2976                *old_cursor_position,
 2977                Some(new_cursor_position.to_point(buffer)),
 2978                false,
 2979                effects.nav_history == Some(true),
 2980                cx,
 2981            );
 2982        }
 2983
 2984        if local {
 2985            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2986                if !self.registered_buffers.contains_key(&buffer_id) {
 2987                    if let Some(project) = self.project.as_ref() {
 2988                        project.update(cx, |project, cx| {
 2989                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2990                                return;
 2991                            };
 2992                            self.registered_buffers.insert(
 2993                                buffer_id,
 2994                                project.register_buffer_with_language_servers(&buffer, cx),
 2995                            );
 2996                        })
 2997                    }
 2998                }
 2999            }
 3000
 3001            let mut context_menu = self.context_menu.borrow_mut();
 3002            let completion_menu = match context_menu.as_ref() {
 3003                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3004                Some(CodeContextMenu::CodeActions(_)) => {
 3005                    *context_menu = None;
 3006                    None
 3007                }
 3008                None => None,
 3009            };
 3010            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3011            drop(context_menu);
 3012
 3013            if effects.completions {
 3014                if let Some(completion_position) = completion_position {
 3015                    let start_offset = selection_start.to_offset(buffer);
 3016                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3017                    let continue_showing = if position_matches {
 3018                        if self.snippet_stack.is_empty() {
 3019                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3020                        } else {
 3021                            // Snippet choices can be shown even when the cursor is in whitespace.
 3022                            // Dismissing the menu with actions like backspace is handled by
 3023                            // invalidation regions.
 3024                            true
 3025                        }
 3026                    } else {
 3027                        false
 3028                    };
 3029
 3030                    if continue_showing {
 3031                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3032                    } else {
 3033                        self.hide_context_menu(window, cx);
 3034                    }
 3035                }
 3036            }
 3037
 3038            hide_hover(self, cx);
 3039
 3040            if old_cursor_position.to_display_point(&display_map).row()
 3041                != new_cursor_position.to_display_point(&display_map).row()
 3042            {
 3043                self.available_code_actions.take();
 3044            }
 3045            self.refresh_code_actions(window, cx);
 3046            self.refresh_document_highlights(cx);
 3047            self.refresh_selected_text_highlights(false, window, cx);
 3048            refresh_matching_bracket_highlights(self, window, cx);
 3049            self.update_visible_edit_prediction(window, cx);
 3050            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3051            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3052            self.inline_blame_popover.take();
 3053            if self.git_blame_inline_enabled {
 3054                self.start_inline_blame_timer(window, cx);
 3055            }
 3056        }
 3057
 3058        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3059        cx.emit(EditorEvent::SelectionsChanged { local });
 3060
 3061        let selections = &self.selections.disjoint;
 3062        if selections.len() == 1 {
 3063            cx.emit(SearchEvent::ActiveMatchChanged)
 3064        }
 3065        if local {
 3066            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3067                let inmemory_selections = selections
 3068                    .iter()
 3069                    .map(|s| {
 3070                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3071                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3072                    })
 3073                    .collect();
 3074                self.update_restoration_data(cx, |data| {
 3075                    data.selections = inmemory_selections;
 3076                });
 3077
 3078                if WorkspaceSettings::get(None, cx).restore_on_startup
 3079                    != RestoreOnStartupBehavior::None
 3080                {
 3081                    if let Some(workspace_id) =
 3082                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3083                    {
 3084                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3085                        let selections = selections.clone();
 3086                        let background_executor = cx.background_executor().clone();
 3087                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3088                        self.serialize_selections = cx.background_spawn(async move {
 3089                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3090                            let db_selections = selections
 3091                                .iter()
 3092                                .map(|selection| {
 3093                                    (
 3094                                        selection.start.to_offset(&snapshot),
 3095                                        selection.end.to_offset(&snapshot),
 3096                                    )
 3097                                })
 3098                                .collect();
 3099
 3100                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3101                                .await
 3102                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3103                                .log_err();
 3104                        });
 3105                    }
 3106                }
 3107            }
 3108        }
 3109
 3110        cx.notify();
 3111    }
 3112
 3113    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3114        use text::ToOffset as _;
 3115        use text::ToPoint as _;
 3116
 3117        if self.mode.is_minimap()
 3118            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3119        {
 3120            return;
 3121        }
 3122
 3123        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3124            return;
 3125        };
 3126
 3127        let snapshot = singleton.read(cx).snapshot();
 3128        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3129            let display_snapshot = display_map.snapshot(cx);
 3130
 3131            display_snapshot
 3132                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3133                .map(|fold| {
 3134                    fold.range.start.text_anchor.to_point(&snapshot)
 3135                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3136                })
 3137                .collect()
 3138        });
 3139        self.update_restoration_data(cx, |data| {
 3140            data.folds = inmemory_folds;
 3141        });
 3142
 3143        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3144            return;
 3145        };
 3146        let background_executor = cx.background_executor().clone();
 3147        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3148        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3149            display_map
 3150                .snapshot(cx)
 3151                .folds_in_range(0..snapshot.len())
 3152                .map(|fold| {
 3153                    (
 3154                        fold.range.start.text_anchor.to_offset(&snapshot),
 3155                        fold.range.end.text_anchor.to_offset(&snapshot),
 3156                    )
 3157                })
 3158                .collect()
 3159        });
 3160        self.serialize_folds = cx.background_spawn(async move {
 3161            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3162            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3163                .await
 3164                .with_context(|| {
 3165                    format!(
 3166                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3167                    )
 3168                })
 3169                .log_err();
 3170        });
 3171    }
 3172
 3173    pub fn sync_selections(
 3174        &mut self,
 3175        other: Entity<Editor>,
 3176        cx: &mut Context<Self>,
 3177    ) -> gpui::Subscription {
 3178        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3179        self.selections.change_with(cx, |selections| {
 3180            selections.select_anchors(other_selections);
 3181        });
 3182
 3183        let other_subscription =
 3184            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3185                EditorEvent::SelectionsChanged { local: true } => {
 3186                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3187                    if other_selections.is_empty() {
 3188                        return;
 3189                    }
 3190                    this.selections.change_with(cx, |selections| {
 3191                        selections.select_anchors(other_selections);
 3192                    });
 3193                }
 3194                _ => {}
 3195            });
 3196
 3197        let this_subscription =
 3198            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3199                EditorEvent::SelectionsChanged { local: true } => {
 3200                    let these_selections = this.selections.disjoint.to_vec();
 3201                    if these_selections.is_empty() {
 3202                        return;
 3203                    }
 3204                    other.update(cx, |other_editor, cx| {
 3205                        other_editor.selections.change_with(cx, |selections| {
 3206                            selections.select_anchors(these_selections);
 3207                        })
 3208                    });
 3209                }
 3210                _ => {}
 3211            });
 3212
 3213        Subscription::join(other_subscription, this_subscription)
 3214    }
 3215
 3216    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3217    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3218    /// effects of selection change occur at the end of the transaction.
 3219    pub fn change_selections<R>(
 3220        &mut self,
 3221        effects: SelectionEffects,
 3222        window: &mut Window,
 3223        cx: &mut Context<Self>,
 3224        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3225    ) -> R {
 3226        if let Some(state) = &mut self.deferred_selection_effects_state {
 3227            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3228            state.effects.completions = effects.completions;
 3229            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3230            let (changed, result) = self.selections.change_with(cx, change);
 3231            state.changed |= changed;
 3232            return result;
 3233        }
 3234        let mut state = DeferredSelectionEffectsState {
 3235            changed: false,
 3236            effects,
 3237            old_cursor_position: self.selections.newest_anchor().head(),
 3238            history_entry: SelectionHistoryEntry {
 3239                selections: self.selections.disjoint_anchors(),
 3240                select_next_state: self.select_next_state.clone(),
 3241                select_prev_state: self.select_prev_state.clone(),
 3242                add_selections_state: self.add_selections_state.clone(),
 3243            },
 3244        };
 3245        let (changed, result) = self.selections.change_with(cx, change);
 3246        state.changed = state.changed || changed;
 3247        if self.defer_selection_effects {
 3248            self.deferred_selection_effects_state = Some(state);
 3249        } else {
 3250            self.apply_selection_effects(state, window, cx);
 3251        }
 3252        result
 3253    }
 3254
 3255    /// Defers the effects of selection change, so that the effects of multiple calls to
 3256    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3257    /// to selection history and the state of popovers based on selection position aren't
 3258    /// erroneously updated.
 3259    pub fn with_selection_effects_deferred<R>(
 3260        &mut self,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3264    ) -> R {
 3265        let already_deferred = self.defer_selection_effects;
 3266        self.defer_selection_effects = true;
 3267        let result = update(self, window, cx);
 3268        if !already_deferred {
 3269            self.defer_selection_effects = false;
 3270            if let Some(state) = self.deferred_selection_effects_state.take() {
 3271                self.apply_selection_effects(state, window, cx);
 3272            }
 3273        }
 3274        result
 3275    }
 3276
 3277    fn apply_selection_effects(
 3278        &mut self,
 3279        state: DeferredSelectionEffectsState,
 3280        window: &mut Window,
 3281        cx: &mut Context<Self>,
 3282    ) {
 3283        if state.changed {
 3284            self.selection_history.push(state.history_entry);
 3285
 3286            if let Some(autoscroll) = state.effects.scroll {
 3287                self.request_autoscroll(autoscroll, cx);
 3288            }
 3289
 3290            let old_cursor_position = &state.old_cursor_position;
 3291
 3292            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3293
 3294            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3295                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3296            }
 3297        }
 3298    }
 3299
 3300    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3301    where
 3302        I: IntoIterator<Item = (Range<S>, T)>,
 3303        S: ToOffset,
 3304        T: Into<Arc<str>>,
 3305    {
 3306        if self.read_only(cx) {
 3307            return;
 3308        }
 3309
 3310        self.buffer
 3311            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3312    }
 3313
 3314    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3315    where
 3316        I: IntoIterator<Item = (Range<S>, T)>,
 3317        S: ToOffset,
 3318        T: Into<Arc<str>>,
 3319    {
 3320        if self.read_only(cx) {
 3321            return;
 3322        }
 3323
 3324        self.buffer.update(cx, |buffer, cx| {
 3325            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3326        });
 3327    }
 3328
 3329    pub fn edit_with_block_indent<I, S, T>(
 3330        &mut self,
 3331        edits: I,
 3332        original_indent_columns: Vec<Option<u32>>,
 3333        cx: &mut Context<Self>,
 3334    ) where
 3335        I: IntoIterator<Item = (Range<S>, T)>,
 3336        S: ToOffset,
 3337        T: Into<Arc<str>>,
 3338    {
 3339        if self.read_only(cx) {
 3340            return;
 3341        }
 3342
 3343        self.buffer.update(cx, |buffer, cx| {
 3344            buffer.edit(
 3345                edits,
 3346                Some(AutoindentMode::Block {
 3347                    original_indent_columns,
 3348                }),
 3349                cx,
 3350            )
 3351        });
 3352    }
 3353
 3354    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3355        self.hide_context_menu(window, cx);
 3356
 3357        match phase {
 3358            SelectPhase::Begin {
 3359                position,
 3360                add,
 3361                click_count,
 3362            } => self.begin_selection(position, add, click_count, window, cx),
 3363            SelectPhase::BeginColumnar {
 3364                position,
 3365                goal_column,
 3366                reset,
 3367                mode,
 3368            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3369            SelectPhase::Extend {
 3370                position,
 3371                click_count,
 3372            } => self.extend_selection(position, click_count, window, cx),
 3373            SelectPhase::Update {
 3374                position,
 3375                goal_column,
 3376                scroll_delta,
 3377            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3378            SelectPhase::End => self.end_selection(window, cx),
 3379        }
 3380    }
 3381
 3382    fn extend_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        click_count: usize,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388    ) {
 3389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3390        let tail = self.selections.newest::<usize>(cx).tail();
 3391        self.begin_selection(position, false, click_count, window, cx);
 3392
 3393        let position = position.to_offset(&display_map, Bias::Left);
 3394        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3395
 3396        let mut pending_selection = self
 3397            .selections
 3398            .pending_anchor()
 3399            .expect("extend_selection not called with pending selection");
 3400        if position >= tail {
 3401            pending_selection.start = tail_anchor;
 3402        } else {
 3403            pending_selection.end = tail_anchor;
 3404            pending_selection.reversed = true;
 3405        }
 3406
 3407        let mut pending_mode = self.selections.pending_mode().unwrap();
 3408        match &mut pending_mode {
 3409            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3410            _ => {}
 3411        }
 3412
 3413        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3414            SelectionEffects::scroll(Autoscroll::fit())
 3415        } else {
 3416            SelectionEffects::no_scroll()
 3417        };
 3418
 3419        self.change_selections(effects, window, cx, |s| {
 3420            s.set_pending(pending_selection, pending_mode)
 3421        });
 3422    }
 3423
 3424    fn begin_selection(
 3425        &mut self,
 3426        position: DisplayPoint,
 3427        add: bool,
 3428        click_count: usize,
 3429        window: &mut Window,
 3430        cx: &mut Context<Self>,
 3431    ) {
 3432        if !self.focus_handle.is_focused(window) {
 3433            self.last_focused_descendant = None;
 3434            window.focus(&self.focus_handle);
 3435        }
 3436
 3437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3438        let buffer = &display_map.buffer_snapshot;
 3439        let position = display_map.clip_point(position, Bias::Left);
 3440
 3441        let start;
 3442        let end;
 3443        let mode;
 3444        let mut auto_scroll;
 3445        match click_count {
 3446            1 => {
 3447                start = buffer.anchor_before(position.to_point(&display_map));
 3448                end = start;
 3449                mode = SelectMode::Character;
 3450                auto_scroll = true;
 3451            }
 3452            2 => {
 3453                let position = display_map
 3454                    .clip_point(position, Bias::Left)
 3455                    .to_offset(&display_map, Bias::Left);
 3456                let (range, _) = buffer.surrounding_word(position, false);
 3457                start = buffer.anchor_before(range.start);
 3458                end = buffer.anchor_before(range.end);
 3459                mode = SelectMode::Word(start..end);
 3460                auto_scroll = true;
 3461            }
 3462            3 => {
 3463                let position = display_map
 3464                    .clip_point(position, Bias::Left)
 3465                    .to_point(&display_map);
 3466                let line_start = display_map.prev_line_boundary(position).0;
 3467                let next_line_start = buffer.clip_point(
 3468                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3469                    Bias::Left,
 3470                );
 3471                start = buffer.anchor_before(line_start);
 3472                end = buffer.anchor_before(next_line_start);
 3473                mode = SelectMode::Line(start..end);
 3474                auto_scroll = true;
 3475            }
 3476            _ => {
 3477                start = buffer.anchor_before(0);
 3478                end = buffer.anchor_before(buffer.len());
 3479                mode = SelectMode::All;
 3480                auto_scroll = false;
 3481            }
 3482        }
 3483        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3484
 3485        let point_to_delete: Option<usize> = {
 3486            let selected_points: Vec<Selection<Point>> =
 3487                self.selections.disjoint_in_range(start..end, cx);
 3488
 3489            if !add || click_count > 1 {
 3490                None
 3491            } else if !selected_points.is_empty() {
 3492                Some(selected_points[0].id)
 3493            } else {
 3494                let clicked_point_already_selected =
 3495                    self.selections.disjoint.iter().find(|selection| {
 3496                        selection.start.to_point(buffer) == start.to_point(buffer)
 3497                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3498                    });
 3499
 3500                clicked_point_already_selected.map(|selection| selection.id)
 3501            }
 3502        };
 3503
 3504        let selections_count = self.selections.count();
 3505        let effects = if auto_scroll {
 3506            SelectionEffects::default()
 3507        } else {
 3508            SelectionEffects::no_scroll()
 3509        };
 3510
 3511        self.change_selections(effects, window, cx, |s| {
 3512            if let Some(point_to_delete) = point_to_delete {
 3513                s.delete(point_to_delete);
 3514
 3515                if selections_count == 1 {
 3516                    s.set_pending_anchor_range(start..end, mode);
 3517                }
 3518            } else {
 3519                if !add {
 3520                    s.clear_disjoint();
 3521                }
 3522
 3523                s.set_pending_anchor_range(start..end, mode);
 3524            }
 3525        });
 3526    }
 3527
 3528    fn begin_columnar_selection(
 3529        &mut self,
 3530        position: DisplayPoint,
 3531        goal_column: u32,
 3532        reset: bool,
 3533        mode: ColumnarMode,
 3534        window: &mut Window,
 3535        cx: &mut Context<Self>,
 3536    ) {
 3537        if !self.focus_handle.is_focused(window) {
 3538            self.last_focused_descendant = None;
 3539            window.focus(&self.focus_handle);
 3540        }
 3541
 3542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3543
 3544        if reset {
 3545            let pointer_position = display_map
 3546                .buffer_snapshot
 3547                .anchor_before(position.to_point(&display_map));
 3548
 3549            self.change_selections(
 3550                SelectionEffects::scroll(Autoscroll::newest()),
 3551                window,
 3552                cx,
 3553                |s| {
 3554                    s.clear_disjoint();
 3555                    s.set_pending_anchor_range(
 3556                        pointer_position..pointer_position,
 3557                        SelectMode::Character,
 3558                    );
 3559                },
 3560            );
 3561        };
 3562
 3563        let tail = self.selections.newest::<Point>(cx).tail();
 3564        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3565        self.columnar_selection_state = match mode {
 3566            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3567                selection_tail: selection_anchor,
 3568                display_point: if reset {
 3569                    if position.column() != goal_column {
 3570                        Some(DisplayPoint::new(position.row(), goal_column))
 3571                    } else {
 3572                        None
 3573                    }
 3574                } else {
 3575                    None
 3576                },
 3577            }),
 3578            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3579                selection_tail: selection_anchor,
 3580            }),
 3581        };
 3582
 3583        if !reset {
 3584            self.select_columns(position, goal_column, &display_map, window, cx);
 3585        }
 3586    }
 3587
 3588    fn update_selection(
 3589        &mut self,
 3590        position: DisplayPoint,
 3591        goal_column: u32,
 3592        scroll_delta: gpui::Point<f32>,
 3593        window: &mut Window,
 3594        cx: &mut Context<Self>,
 3595    ) {
 3596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3597
 3598        if self.columnar_selection_state.is_some() {
 3599            self.select_columns(position, goal_column, &display_map, window, cx);
 3600        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3601            let buffer = &display_map.buffer_snapshot;
 3602            let head;
 3603            let tail;
 3604            let mode = self.selections.pending_mode().unwrap();
 3605            match &mode {
 3606                SelectMode::Character => {
 3607                    head = position.to_point(&display_map);
 3608                    tail = pending.tail().to_point(buffer);
 3609                }
 3610                SelectMode::Word(original_range) => {
 3611                    let offset = display_map
 3612                        .clip_point(position, Bias::Left)
 3613                        .to_offset(&display_map, Bias::Left);
 3614                    let original_range = original_range.to_offset(buffer);
 3615
 3616                    let head_offset = if buffer.is_inside_word(offset, false)
 3617                        || original_range.contains(&offset)
 3618                    {
 3619                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3620                        if word_range.start < original_range.start {
 3621                            word_range.start
 3622                        } else {
 3623                            word_range.end
 3624                        }
 3625                    } else {
 3626                        offset
 3627                    };
 3628
 3629                    head = head_offset.to_point(buffer);
 3630                    if head_offset <= original_range.start {
 3631                        tail = original_range.end.to_point(buffer);
 3632                    } else {
 3633                        tail = original_range.start.to_point(buffer);
 3634                    }
 3635                }
 3636                SelectMode::Line(original_range) => {
 3637                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3638
 3639                    let position = display_map
 3640                        .clip_point(position, Bias::Left)
 3641                        .to_point(&display_map);
 3642                    let line_start = display_map.prev_line_boundary(position).0;
 3643                    let next_line_start = buffer.clip_point(
 3644                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3645                        Bias::Left,
 3646                    );
 3647
 3648                    if line_start < original_range.start {
 3649                        head = line_start
 3650                    } else {
 3651                        head = next_line_start
 3652                    }
 3653
 3654                    if head <= original_range.start {
 3655                        tail = original_range.end;
 3656                    } else {
 3657                        tail = original_range.start;
 3658                    }
 3659                }
 3660                SelectMode::All => {
 3661                    return;
 3662                }
 3663            };
 3664
 3665            if head < tail {
 3666                pending.start = buffer.anchor_before(head);
 3667                pending.end = buffer.anchor_before(tail);
 3668                pending.reversed = true;
 3669            } else {
 3670                pending.start = buffer.anchor_before(tail);
 3671                pending.end = buffer.anchor_before(head);
 3672                pending.reversed = false;
 3673            }
 3674
 3675            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3676                s.set_pending(pending, mode);
 3677            });
 3678        } else {
 3679            log::error!("update_selection dispatched with no pending selection");
 3680            return;
 3681        }
 3682
 3683        self.apply_scroll_delta(scroll_delta, window, cx);
 3684        cx.notify();
 3685    }
 3686
 3687    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3688        self.columnar_selection_state.take();
 3689        if self.selections.pending_anchor().is_some() {
 3690            let selections = self.selections.all::<usize>(cx);
 3691            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3692                s.select(selections);
 3693                s.clear_pending();
 3694            });
 3695        }
 3696    }
 3697
 3698    fn select_columns(
 3699        &mut self,
 3700        head: DisplayPoint,
 3701        goal_column: u32,
 3702        display_map: &DisplaySnapshot,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3707            return;
 3708        };
 3709
 3710        let tail = match columnar_state {
 3711            ColumnarSelectionState::FromMouse {
 3712                selection_tail,
 3713                display_point,
 3714            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3715            ColumnarSelectionState::FromSelection { selection_tail } => {
 3716                selection_tail.to_display_point(&display_map)
 3717            }
 3718        };
 3719
 3720        let start_row = cmp::min(tail.row(), head.row());
 3721        let end_row = cmp::max(tail.row(), head.row());
 3722        let start_column = cmp::min(tail.column(), goal_column);
 3723        let end_column = cmp::max(tail.column(), goal_column);
 3724        let reversed = start_column < tail.column();
 3725
 3726        let selection_ranges = (start_row.0..=end_row.0)
 3727            .map(DisplayRow)
 3728            .filter_map(|row| {
 3729                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3730                    || start_column <= display_map.line_len(row))
 3731                    && !display_map.is_block_line(row)
 3732                {
 3733                    let start = display_map
 3734                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3735                        .to_point(display_map);
 3736                    let end = display_map
 3737                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3738                        .to_point(display_map);
 3739                    if reversed {
 3740                        Some(end..start)
 3741                    } else {
 3742                        Some(start..end)
 3743                    }
 3744                } else {
 3745                    None
 3746                }
 3747            })
 3748            .collect::<Vec<_>>();
 3749
 3750        let ranges = match columnar_state {
 3751            ColumnarSelectionState::FromMouse { .. } => {
 3752                let mut non_empty_ranges = selection_ranges
 3753                    .iter()
 3754                    .filter(|selection_range| selection_range.start != selection_range.end)
 3755                    .peekable();
 3756                if non_empty_ranges.peek().is_some() {
 3757                    non_empty_ranges.cloned().collect()
 3758                } else {
 3759                    selection_ranges
 3760                }
 3761            }
 3762            _ => selection_ranges,
 3763        };
 3764
 3765        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3766            s.select_ranges(ranges);
 3767        });
 3768        cx.notify();
 3769    }
 3770
 3771    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3772        self.selections
 3773            .all_adjusted(cx)
 3774            .iter()
 3775            .any(|selection| !selection.is_empty())
 3776    }
 3777
 3778    pub fn has_pending_nonempty_selection(&self) -> bool {
 3779        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3780            Some(Selection { start, end, .. }) => start != end,
 3781            None => false,
 3782        };
 3783
 3784        pending_nonempty_selection
 3785            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3786    }
 3787
 3788    pub fn has_pending_selection(&self) -> bool {
 3789        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3790    }
 3791
 3792    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3793        self.selection_mark_mode = false;
 3794        self.selection_drag_state = SelectionDragState::None;
 3795
 3796        if self.clear_expanded_diff_hunks(cx) {
 3797            cx.notify();
 3798            return;
 3799        }
 3800        if self.dismiss_menus_and_popups(true, window, cx) {
 3801            return;
 3802        }
 3803
 3804        if self.mode.is_full()
 3805            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3806        {
 3807            return;
 3808        }
 3809
 3810        cx.propagate();
 3811    }
 3812
 3813    pub fn dismiss_menus_and_popups(
 3814        &mut self,
 3815        is_user_requested: bool,
 3816        window: &mut Window,
 3817        cx: &mut Context<Self>,
 3818    ) -> bool {
 3819        if self.take_rename(false, window, cx).is_some() {
 3820            return true;
 3821        }
 3822
 3823        if hide_hover(self, cx) {
 3824            return true;
 3825        }
 3826
 3827        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_context_menu(window, cx).is_some() {
 3832            return true;
 3833        }
 3834
 3835        if self.mouse_context_menu.take().is_some() {
 3836            return true;
 3837        }
 3838
 3839        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3840            return true;
 3841        }
 3842
 3843        if self.snippet_stack.pop().is_some() {
 3844            return true;
 3845        }
 3846
 3847        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3848            self.dismiss_diagnostics(cx);
 3849            return true;
 3850        }
 3851
 3852        false
 3853    }
 3854
 3855    fn linked_editing_ranges_for(
 3856        &self,
 3857        selection: Range<text::Anchor>,
 3858        cx: &App,
 3859    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3860        if self.linked_edit_ranges.is_empty() {
 3861            return None;
 3862        }
 3863        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3864            selection.end.buffer_id.and_then(|end_buffer_id| {
 3865                if selection.start.buffer_id != Some(end_buffer_id) {
 3866                    return None;
 3867                }
 3868                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3869                let snapshot = buffer.read(cx).snapshot();
 3870                self.linked_edit_ranges
 3871                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3872                    .map(|ranges| (ranges, snapshot, buffer))
 3873            })?;
 3874        use text::ToOffset as TO;
 3875        // find offset from the start of current range to current cursor position
 3876        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3877
 3878        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3879        let start_difference = start_offset - start_byte_offset;
 3880        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3881        let end_difference = end_offset - start_byte_offset;
 3882        // Current range has associated linked ranges.
 3883        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3884        for range in linked_ranges.iter() {
 3885            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3886            let end_offset = start_offset + end_difference;
 3887            let start_offset = start_offset + start_difference;
 3888            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3889                continue;
 3890            }
 3891            if self.selections.disjoint_anchor_ranges().any(|s| {
 3892                if s.start.buffer_id != selection.start.buffer_id
 3893                    || s.end.buffer_id != selection.end.buffer_id
 3894                {
 3895                    return false;
 3896                }
 3897                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3898                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3899            }) {
 3900                continue;
 3901            }
 3902            let start = buffer_snapshot.anchor_after(start_offset);
 3903            let end = buffer_snapshot.anchor_after(end_offset);
 3904            linked_edits
 3905                .entry(buffer.clone())
 3906                .or_default()
 3907                .push(start..end);
 3908        }
 3909        Some(linked_edits)
 3910    }
 3911
 3912    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3913        let text: Arc<str> = text.into();
 3914
 3915        if self.read_only(cx) {
 3916            return;
 3917        }
 3918
 3919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3920
 3921        let selections = self.selections.all_adjusted(cx);
 3922        let mut bracket_inserted = false;
 3923        let mut edits = Vec::new();
 3924        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3925        let mut new_selections = Vec::with_capacity(selections.len());
 3926        let mut new_autoclose_regions = Vec::new();
 3927        let snapshot = self.buffer.read(cx).read(cx);
 3928        let mut clear_linked_edit_ranges = false;
 3929
 3930        for (selection, autoclose_region) in
 3931            self.selections_with_autoclose_regions(selections, &snapshot)
 3932        {
 3933            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3934                // Determine if the inserted text matches the opening or closing
 3935                // bracket of any of this language's bracket pairs.
 3936                let mut bracket_pair = None;
 3937                let mut is_bracket_pair_start = false;
 3938                let mut is_bracket_pair_end = false;
 3939                if !text.is_empty() {
 3940                    let mut bracket_pair_matching_end = None;
 3941                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3942                    //  and they are removing the character that triggered IME popup.
 3943                    for (pair, enabled) in scope.brackets() {
 3944                        if !pair.close && !pair.surround {
 3945                            continue;
 3946                        }
 3947
 3948                        if enabled && pair.start.ends_with(text.as_ref()) {
 3949                            let prefix_len = pair.start.len() - text.len();
 3950                            let preceding_text_matches_prefix = prefix_len == 0
 3951                                || (selection.start.column >= (prefix_len as u32)
 3952                                    && snapshot.contains_str_at(
 3953                                        Point::new(
 3954                                            selection.start.row,
 3955                                            selection.start.column - (prefix_len as u32),
 3956                                        ),
 3957                                        &pair.start[..prefix_len],
 3958                                    ));
 3959                            if preceding_text_matches_prefix {
 3960                                bracket_pair = Some(pair.clone());
 3961                                is_bracket_pair_start = true;
 3962                                break;
 3963                            }
 3964                        }
 3965                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3966                        {
 3967                            // take first bracket pair matching end, but don't break in case a later bracket
 3968                            // pair matches start
 3969                            bracket_pair_matching_end = Some(pair.clone());
 3970                        }
 3971                    }
 3972                    if let Some(end) = bracket_pair_matching_end
 3973                        && bracket_pair.is_none()
 3974                    {
 3975                        bracket_pair = Some(end);
 3976                        is_bracket_pair_end = true;
 3977                    }
 3978                }
 3979
 3980                if let Some(bracket_pair) = bracket_pair {
 3981                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3982                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3983                    let auto_surround =
 3984                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3985                    if selection.is_empty() {
 3986                        if is_bracket_pair_start {
 3987                            // If the inserted text is a suffix of an opening bracket and the
 3988                            // selection is preceded by the rest of the opening bracket, then
 3989                            // insert the closing bracket.
 3990                            let following_text_allows_autoclose = snapshot
 3991                                .chars_at(selection.start)
 3992                                .next()
 3993                                .map_or(true, |c| scope.should_autoclose_before(c));
 3994
 3995                            let preceding_text_allows_autoclose = selection.start.column == 0
 3996                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3997                                    true,
 3998                                    |c| {
 3999                                        bracket_pair.start != bracket_pair.end
 4000                                            || !snapshot
 4001                                                .char_classifier_at(selection.start)
 4002                                                .is_word(c)
 4003                                    },
 4004                                );
 4005
 4006                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4007                                && bracket_pair.start.len() == 1
 4008                            {
 4009                                let target = bracket_pair.start.chars().next().unwrap();
 4010                                let current_line_count = snapshot
 4011                                    .reversed_chars_at(selection.start)
 4012                                    .take_while(|&c| c != '\n')
 4013                                    .filter(|&c| c == target)
 4014                                    .count();
 4015                                current_line_count % 2 == 1
 4016                            } else {
 4017                                false
 4018                            };
 4019
 4020                            if autoclose
 4021                                && bracket_pair.close
 4022                                && following_text_allows_autoclose
 4023                                && preceding_text_allows_autoclose
 4024                                && !is_closing_quote
 4025                            {
 4026                                let anchor = snapshot.anchor_before(selection.end);
 4027                                new_selections.push((selection.map(|_| anchor), text.len()));
 4028                                new_autoclose_regions.push((
 4029                                    anchor,
 4030                                    text.len(),
 4031                                    selection.id,
 4032                                    bracket_pair.clone(),
 4033                                ));
 4034                                edits.push((
 4035                                    selection.range(),
 4036                                    format!("{}{}", text, bracket_pair.end).into(),
 4037                                ));
 4038                                bracket_inserted = true;
 4039                                continue;
 4040                            }
 4041                        }
 4042
 4043                        if let Some(region) = autoclose_region {
 4044                            // If the selection is followed by an auto-inserted closing bracket,
 4045                            // then don't insert that closing bracket again; just move the selection
 4046                            // past the closing bracket.
 4047                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4048                                && text.as_ref() == region.pair.end.as_str()
 4049                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4050                            if should_skip {
 4051                                let anchor = snapshot.anchor_after(selection.end);
 4052                                new_selections
 4053                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4054                                continue;
 4055                            }
 4056                        }
 4057
 4058                        let always_treat_brackets_as_autoclosed = snapshot
 4059                            .language_settings_at(selection.start, cx)
 4060                            .always_treat_brackets_as_autoclosed;
 4061                        if always_treat_brackets_as_autoclosed
 4062                            && is_bracket_pair_end
 4063                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4064                        {
 4065                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4066                            // and the inserted text is a closing bracket and the selection is followed
 4067                            // by the closing bracket then move the selection past the closing bracket.
 4068                            let anchor = snapshot.anchor_after(selection.end);
 4069                            new_selections.push((selection.map(|_| anchor), text.len()));
 4070                            continue;
 4071                        }
 4072                    }
 4073                    // If an opening bracket is 1 character long and is typed while
 4074                    // text is selected, then surround that text with the bracket pair.
 4075                    else if auto_surround
 4076                        && bracket_pair.surround
 4077                        && is_bracket_pair_start
 4078                        && bracket_pair.start.chars().count() == 1
 4079                    {
 4080                        edits.push((selection.start..selection.start, text.clone()));
 4081                        edits.push((
 4082                            selection.end..selection.end,
 4083                            bracket_pair.end.as_str().into(),
 4084                        ));
 4085                        bracket_inserted = true;
 4086                        new_selections.push((
 4087                            Selection {
 4088                                id: selection.id,
 4089                                start: snapshot.anchor_after(selection.start),
 4090                                end: snapshot.anchor_before(selection.end),
 4091                                reversed: selection.reversed,
 4092                                goal: selection.goal,
 4093                            },
 4094                            0,
 4095                        ));
 4096                        continue;
 4097                    }
 4098                }
 4099            }
 4100
 4101            if self.auto_replace_emoji_shortcode
 4102                && selection.is_empty()
 4103                && text.as_ref().ends_with(':')
 4104            {
 4105                if let Some(possible_emoji_short_code) =
 4106                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4107                {
 4108                    if !possible_emoji_short_code.is_empty() {
 4109                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4110                            let emoji_shortcode_start = Point::new(
 4111                                selection.start.row,
 4112                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4113                            );
 4114
 4115                            // Remove shortcode from buffer
 4116                            edits.push((
 4117                                emoji_shortcode_start..selection.start,
 4118                                "".to_string().into(),
 4119                            ));
 4120                            new_selections.push((
 4121                                Selection {
 4122                                    id: selection.id,
 4123                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4124                                    end: snapshot.anchor_before(selection.start),
 4125                                    reversed: selection.reversed,
 4126                                    goal: selection.goal,
 4127                                },
 4128                                0,
 4129                            ));
 4130
 4131                            // Insert emoji
 4132                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4133                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4134                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4135
 4136                            continue;
 4137                        }
 4138                    }
 4139                }
 4140            }
 4141
 4142            // If not handling any auto-close operation, then just replace the selected
 4143            // text with the given input and move the selection to the end of the
 4144            // newly inserted text.
 4145            let anchor = snapshot.anchor_after(selection.end);
 4146            if !self.linked_edit_ranges.is_empty() {
 4147                let start_anchor = snapshot.anchor_before(selection.start);
 4148
 4149                let is_word_char = text.chars().next().map_or(true, |char| {
 4150                    let classifier = snapshot
 4151                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4152                        .ignore_punctuation(true);
 4153                    classifier.is_word(char)
 4154                });
 4155
 4156                if is_word_char {
 4157                    if let Some(ranges) = self
 4158                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4159                    {
 4160                        for (buffer, edits) in ranges {
 4161                            linked_edits
 4162                                .entry(buffer.clone())
 4163                                .or_default()
 4164                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4165                        }
 4166                    }
 4167                } else {
 4168                    clear_linked_edit_ranges = true;
 4169                }
 4170            }
 4171
 4172            new_selections.push((selection.map(|_| anchor), 0));
 4173            edits.push((selection.start..selection.end, text.clone()));
 4174        }
 4175
 4176        drop(snapshot);
 4177
 4178        self.transact(window, cx, |this, window, cx| {
 4179            if clear_linked_edit_ranges {
 4180                this.linked_edit_ranges.clear();
 4181            }
 4182            let initial_buffer_versions =
 4183                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4184
 4185            this.buffer.update(cx, |buffer, cx| {
 4186                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4187            });
 4188            for (buffer, edits) in linked_edits {
 4189                buffer.update(cx, |buffer, cx| {
 4190                    let snapshot = buffer.snapshot();
 4191                    let edits = edits
 4192                        .into_iter()
 4193                        .map(|(range, text)| {
 4194                            use text::ToPoint as TP;
 4195                            let end_point = TP::to_point(&range.end, &snapshot);
 4196                            let start_point = TP::to_point(&range.start, &snapshot);
 4197                            (start_point..end_point, text)
 4198                        })
 4199                        .sorted_by_key(|(range, _)| range.start);
 4200                    buffer.edit(edits, None, cx);
 4201                })
 4202            }
 4203            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4204            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4205            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4206            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4207                .zip(new_selection_deltas)
 4208                .map(|(selection, delta)| Selection {
 4209                    id: selection.id,
 4210                    start: selection.start + delta,
 4211                    end: selection.end + delta,
 4212                    reversed: selection.reversed,
 4213                    goal: SelectionGoal::None,
 4214                })
 4215                .collect::<Vec<_>>();
 4216
 4217            let mut i = 0;
 4218            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4219                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4220                let start = map.buffer_snapshot.anchor_before(position);
 4221                let end = map.buffer_snapshot.anchor_after(position);
 4222                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4223                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4224                        Ordering::Less => i += 1,
 4225                        Ordering::Greater => break,
 4226                        Ordering::Equal => {
 4227                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4228                                Ordering::Less => i += 1,
 4229                                Ordering::Equal => break,
 4230                                Ordering::Greater => break,
 4231                            }
 4232                        }
 4233                    }
 4234                }
 4235                this.autoclose_regions.insert(
 4236                    i,
 4237                    AutocloseRegion {
 4238                        selection_id,
 4239                        range: start..end,
 4240                        pair,
 4241                    },
 4242                );
 4243            }
 4244
 4245            let had_active_edit_prediction = this.has_active_edit_prediction();
 4246            this.change_selections(
 4247                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4248                window,
 4249                cx,
 4250                |s| s.select(new_selections),
 4251            );
 4252
 4253            if !bracket_inserted {
 4254                if let Some(on_type_format_task) =
 4255                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4256                {
 4257                    on_type_format_task.detach_and_log_err(cx);
 4258                }
 4259            }
 4260
 4261            let editor_settings = EditorSettings::get_global(cx);
 4262            if bracket_inserted
 4263                && (editor_settings.auto_signature_help
 4264                    || editor_settings.show_signature_help_after_edits)
 4265            {
 4266                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4267            }
 4268
 4269            let trigger_in_words =
 4270                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4271            if this.hard_wrap.is_some() {
 4272                let latest: Range<Point> = this.selections.newest(cx).range();
 4273                if latest.is_empty()
 4274                    && this
 4275                        .buffer()
 4276                        .read(cx)
 4277                        .snapshot(cx)
 4278                        .line_len(MultiBufferRow(latest.start.row))
 4279                        == latest.start.column
 4280                {
 4281                    this.rewrap_impl(
 4282                        RewrapOptions {
 4283                            override_language_settings: true,
 4284                            preserve_existing_whitespace: true,
 4285                        },
 4286                        cx,
 4287                    )
 4288                }
 4289            }
 4290            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4291            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4292            this.refresh_edit_prediction(true, false, window, cx);
 4293            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4294        });
 4295    }
 4296
 4297    fn find_possible_emoji_shortcode_at_position(
 4298        snapshot: &MultiBufferSnapshot,
 4299        position: Point,
 4300    ) -> Option<String> {
 4301        let mut chars = Vec::new();
 4302        let mut found_colon = false;
 4303        for char in snapshot.reversed_chars_at(position).take(100) {
 4304            // Found a possible emoji shortcode in the middle of the buffer
 4305            if found_colon {
 4306                if char.is_whitespace() {
 4307                    chars.reverse();
 4308                    return Some(chars.iter().collect());
 4309                }
 4310                // If the previous character is not a whitespace, we are in the middle of a word
 4311                // and we only want to complete the shortcode if the word is made up of other emojis
 4312                let mut containing_word = String::new();
 4313                for ch in snapshot
 4314                    .reversed_chars_at(position)
 4315                    .skip(chars.len() + 1)
 4316                    .take(100)
 4317                {
 4318                    if ch.is_whitespace() {
 4319                        break;
 4320                    }
 4321                    containing_word.push(ch);
 4322                }
 4323                let containing_word = containing_word.chars().rev().collect::<String>();
 4324                if util::word_consists_of_emojis(containing_word.as_str()) {
 4325                    chars.reverse();
 4326                    return Some(chars.iter().collect());
 4327                }
 4328            }
 4329
 4330            if char.is_whitespace() || !char.is_ascii() {
 4331                return None;
 4332            }
 4333            if char == ':' {
 4334                found_colon = true;
 4335            } else {
 4336                chars.push(char);
 4337            }
 4338        }
 4339        // Found a possible emoji shortcode at the beginning of the buffer
 4340        chars.reverse();
 4341        Some(chars.iter().collect())
 4342    }
 4343
 4344    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4346        self.transact(window, cx, |this, window, cx| {
 4347            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4348                let selections = this.selections.all::<usize>(cx);
 4349                let multi_buffer = this.buffer.read(cx);
 4350                let buffer = multi_buffer.snapshot(cx);
 4351                selections
 4352                    .iter()
 4353                    .map(|selection| {
 4354                        let start_point = selection.start.to_point(&buffer);
 4355                        let mut existing_indent =
 4356                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4357                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4358                        let start = selection.start;
 4359                        let end = selection.end;
 4360                        let selection_is_empty = start == end;
 4361                        let language_scope = buffer.language_scope_at(start);
 4362                        let (
 4363                            comment_delimiter,
 4364                            doc_delimiter,
 4365                            insert_extra_newline,
 4366                            indent_on_newline,
 4367                            indent_on_extra_newline,
 4368                        ) = if let Some(language) = &language_scope {
 4369                            let mut insert_extra_newline =
 4370                                insert_extra_newline_brackets(&buffer, start..end, language)
 4371                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4372
 4373                            // Comment extension on newline is allowed only for cursor selections
 4374                            let comment_delimiter = maybe!({
 4375                                if !selection_is_empty {
 4376                                    return None;
 4377                                }
 4378
 4379                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4380                                    return None;
 4381                                }
 4382
 4383                                let delimiters = language.line_comment_prefixes();
 4384                                let max_len_of_delimiter =
 4385                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4386                                let (snapshot, range) =
 4387                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4388
 4389                                let num_of_whitespaces = snapshot
 4390                                    .chars_for_range(range.clone())
 4391                                    .take_while(|c| c.is_whitespace())
 4392                                    .count();
 4393                                let comment_candidate = snapshot
 4394                                    .chars_for_range(range.clone())
 4395                                    .skip(num_of_whitespaces)
 4396                                    .take(max_len_of_delimiter)
 4397                                    .collect::<String>();
 4398                                let (delimiter, trimmed_len) = delimiters
 4399                                    .iter()
 4400                                    .filter_map(|delimiter| {
 4401                                        let prefix = delimiter.trim_end();
 4402                                        if comment_candidate.starts_with(prefix) {
 4403                                            Some((delimiter, prefix.len()))
 4404                                        } else {
 4405                                            None
 4406                                        }
 4407                                    })
 4408                                    .max_by_key(|(_, len)| *len)?;
 4409
 4410                                if let Some(BlockCommentConfig {
 4411                                    start: block_start, ..
 4412                                }) = language.block_comment()
 4413                                {
 4414                                    let block_start_trimmed = block_start.trim_end();
 4415                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4416                                        let line_content = snapshot
 4417                                            .chars_for_range(range)
 4418                                            .skip(num_of_whitespaces)
 4419                                            .take(block_start_trimmed.len())
 4420                                            .collect::<String>();
 4421
 4422                                        if line_content.starts_with(block_start_trimmed) {
 4423                                            return None;
 4424                                        }
 4425                                    }
 4426                                }
 4427
 4428                                let cursor_is_placed_after_comment_marker =
 4429                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4430                                if cursor_is_placed_after_comment_marker {
 4431                                    Some(delimiter.clone())
 4432                                } else {
 4433                                    None
 4434                                }
 4435                            });
 4436
 4437                            let mut indent_on_newline = IndentSize::spaces(0);
 4438                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4439
 4440                            let doc_delimiter = maybe!({
 4441                                if !selection_is_empty {
 4442                                    return None;
 4443                                }
 4444
 4445                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4446                                    return None;
 4447                                }
 4448
 4449                                let BlockCommentConfig {
 4450                                    start: start_tag,
 4451                                    end: end_tag,
 4452                                    prefix: delimiter,
 4453                                    tab_size: len,
 4454                                } = language.documentation_comment()?;
 4455                                let is_within_block_comment = buffer
 4456                                    .language_scope_at(start_point)
 4457                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4458                                if !is_within_block_comment {
 4459                                    return None;
 4460                                }
 4461
 4462                                let (snapshot, range) =
 4463                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4464
 4465                                let num_of_whitespaces = snapshot
 4466                                    .chars_for_range(range.clone())
 4467                                    .take_while(|c| c.is_whitespace())
 4468                                    .count();
 4469
 4470                                // 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.
 4471                                let column = start_point.column;
 4472                                let cursor_is_after_start_tag = {
 4473                                    let start_tag_len = start_tag.len();
 4474                                    let start_tag_line = snapshot
 4475                                        .chars_for_range(range.clone())
 4476                                        .skip(num_of_whitespaces)
 4477                                        .take(start_tag_len)
 4478                                        .collect::<String>();
 4479                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4480                                        num_of_whitespaces + start_tag_len <= column as usize
 4481                                    } else {
 4482                                        false
 4483                                    }
 4484                                };
 4485
 4486                                let cursor_is_after_delimiter = {
 4487                                    let delimiter_trim = delimiter.trim_end();
 4488                                    let delimiter_line = snapshot
 4489                                        .chars_for_range(range.clone())
 4490                                        .skip(num_of_whitespaces)
 4491                                        .take(delimiter_trim.len())
 4492                                        .collect::<String>();
 4493                                    if delimiter_line.starts_with(delimiter_trim) {
 4494                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4495                                    } else {
 4496                                        false
 4497                                    }
 4498                                };
 4499
 4500                                let cursor_is_before_end_tag_if_exists = {
 4501                                    let mut char_position = 0u32;
 4502                                    let mut end_tag_offset = None;
 4503
 4504                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4505                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4506                                            let chars_before_match =
 4507                                                chunk[..byte_pos].chars().count() as u32;
 4508                                            end_tag_offset =
 4509                                                Some(char_position + chars_before_match);
 4510                                            break 'outer;
 4511                                        }
 4512                                        char_position += chunk.chars().count() as u32;
 4513                                    }
 4514
 4515                                    if let Some(end_tag_offset) = end_tag_offset {
 4516                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4517                                        if cursor_is_after_start_tag {
 4518                                            if cursor_is_before_end_tag {
 4519                                                insert_extra_newline = true;
 4520                                            }
 4521                                            let cursor_is_at_start_of_end_tag =
 4522                                                column == end_tag_offset;
 4523                                            if cursor_is_at_start_of_end_tag {
 4524                                                indent_on_extra_newline.len = *len;
 4525                                            }
 4526                                        }
 4527                                        cursor_is_before_end_tag
 4528                                    } else {
 4529                                        true
 4530                                    }
 4531                                };
 4532
 4533                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4534                                    && cursor_is_before_end_tag_if_exists
 4535                                {
 4536                                    if cursor_is_after_start_tag {
 4537                                        indent_on_newline.len = *len;
 4538                                    }
 4539                                    Some(delimiter.clone())
 4540                                } else {
 4541                                    None
 4542                                }
 4543                            });
 4544
 4545                            (
 4546                                comment_delimiter,
 4547                                doc_delimiter,
 4548                                insert_extra_newline,
 4549                                indent_on_newline,
 4550                                indent_on_extra_newline,
 4551                            )
 4552                        } else {
 4553                            (
 4554                                None,
 4555                                None,
 4556                                false,
 4557                                IndentSize::default(),
 4558                                IndentSize::default(),
 4559                            )
 4560                        };
 4561
 4562                        let prevent_auto_indent = doc_delimiter.is_some();
 4563                        let delimiter = comment_delimiter.or(doc_delimiter);
 4564
 4565                        let capacity_for_delimiter =
 4566                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4567                        let mut new_text = String::with_capacity(
 4568                            1 + capacity_for_delimiter
 4569                                + existing_indent.len as usize
 4570                                + indent_on_newline.len as usize
 4571                                + indent_on_extra_newline.len as usize,
 4572                        );
 4573                        new_text.push('\n');
 4574                        new_text.extend(existing_indent.chars());
 4575                        new_text.extend(indent_on_newline.chars());
 4576
 4577                        if let Some(delimiter) = &delimiter {
 4578                            new_text.push_str(delimiter);
 4579                        }
 4580
 4581                        if insert_extra_newline {
 4582                            new_text.push('\n');
 4583                            new_text.extend(existing_indent.chars());
 4584                            new_text.extend(indent_on_extra_newline.chars());
 4585                        }
 4586
 4587                        let anchor = buffer.anchor_after(end);
 4588                        let new_selection = selection.map(|_| anchor);
 4589                        (
 4590                            ((start..end, new_text), prevent_auto_indent),
 4591                            (insert_extra_newline, new_selection),
 4592                        )
 4593                    })
 4594                    .unzip()
 4595            };
 4596
 4597            let mut auto_indent_edits = Vec::new();
 4598            let mut edits = Vec::new();
 4599            for (edit, prevent_auto_indent) in edits_with_flags {
 4600                if prevent_auto_indent {
 4601                    edits.push(edit);
 4602                } else {
 4603                    auto_indent_edits.push(edit);
 4604                }
 4605            }
 4606            if !edits.is_empty() {
 4607                this.edit(edits, cx);
 4608            }
 4609            if !auto_indent_edits.is_empty() {
 4610                this.edit_with_autoindent(auto_indent_edits, cx);
 4611            }
 4612
 4613            let buffer = this.buffer.read(cx).snapshot(cx);
 4614            let new_selections = selection_info
 4615                .into_iter()
 4616                .map(|(extra_newline_inserted, new_selection)| {
 4617                    let mut cursor = new_selection.end.to_point(&buffer);
 4618                    if extra_newline_inserted {
 4619                        cursor.row -= 1;
 4620                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4621                    }
 4622                    new_selection.map(|_| cursor)
 4623                })
 4624                .collect();
 4625
 4626            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4627            this.refresh_edit_prediction(true, false, window, cx);
 4628        });
 4629    }
 4630
 4631    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4633
 4634        let buffer = self.buffer.read(cx);
 4635        let snapshot = buffer.snapshot(cx);
 4636
 4637        let mut edits = Vec::new();
 4638        let mut rows = Vec::new();
 4639
 4640        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4641            let cursor = selection.head();
 4642            let row = cursor.row;
 4643
 4644            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4645
 4646            let newline = "\n".to_string();
 4647            edits.push((start_of_line..start_of_line, newline));
 4648
 4649            rows.push(row + rows_inserted as u32);
 4650        }
 4651
 4652        self.transact(window, cx, |editor, window, cx| {
 4653            editor.edit(edits, cx);
 4654
 4655            editor.change_selections(Default::default(), window, cx, |s| {
 4656                let mut index = 0;
 4657                s.move_cursors_with(|map, _, _| {
 4658                    let row = rows[index];
 4659                    index += 1;
 4660
 4661                    let point = Point::new(row, 0);
 4662                    let boundary = map.next_line_boundary(point).1;
 4663                    let clipped = map.clip_point(boundary, Bias::Left);
 4664
 4665                    (clipped, SelectionGoal::None)
 4666                });
 4667            });
 4668
 4669            let mut indent_edits = Vec::new();
 4670            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4671            for row in rows {
 4672                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4673                for (row, indent) in indents {
 4674                    if indent.len == 0 {
 4675                        continue;
 4676                    }
 4677
 4678                    let text = match indent.kind {
 4679                        IndentKind::Space => " ".repeat(indent.len as usize),
 4680                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4681                    };
 4682                    let point = Point::new(row.0, 0);
 4683                    indent_edits.push((point..point, text));
 4684                }
 4685            }
 4686            editor.edit(indent_edits, cx);
 4687        });
 4688    }
 4689
 4690    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4692
 4693        let buffer = self.buffer.read(cx);
 4694        let snapshot = buffer.snapshot(cx);
 4695
 4696        let mut edits = Vec::new();
 4697        let mut rows = Vec::new();
 4698        let mut rows_inserted = 0;
 4699
 4700        for selection in self.selections.all_adjusted(cx) {
 4701            let cursor = selection.head();
 4702            let row = cursor.row;
 4703
 4704            let point = Point::new(row + 1, 0);
 4705            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4706
 4707            let newline = "\n".to_string();
 4708            edits.push((start_of_line..start_of_line, newline));
 4709
 4710            rows_inserted += 1;
 4711            rows.push(row + rows_inserted);
 4712        }
 4713
 4714        self.transact(window, cx, |editor, window, cx| {
 4715            editor.edit(edits, cx);
 4716
 4717            editor.change_selections(Default::default(), window, cx, |s| {
 4718                let mut index = 0;
 4719                s.move_cursors_with(|map, _, _| {
 4720                    let row = rows[index];
 4721                    index += 1;
 4722
 4723                    let point = Point::new(row, 0);
 4724                    let boundary = map.next_line_boundary(point).1;
 4725                    let clipped = map.clip_point(boundary, Bias::Left);
 4726
 4727                    (clipped, SelectionGoal::None)
 4728                });
 4729            });
 4730
 4731            let mut indent_edits = Vec::new();
 4732            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4733            for row in rows {
 4734                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4735                for (row, indent) in indents {
 4736                    if indent.len == 0 {
 4737                        continue;
 4738                    }
 4739
 4740                    let text = match indent.kind {
 4741                        IndentKind::Space => " ".repeat(indent.len as usize),
 4742                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4743                    };
 4744                    let point = Point::new(row.0, 0);
 4745                    indent_edits.push((point..point, text));
 4746                }
 4747            }
 4748            editor.edit(indent_edits, cx);
 4749        });
 4750    }
 4751
 4752    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4753        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4754            original_indent_columns: Vec::new(),
 4755        });
 4756        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4757    }
 4758
 4759    fn insert_with_autoindent_mode(
 4760        &mut self,
 4761        text: &str,
 4762        autoindent_mode: Option<AutoindentMode>,
 4763        window: &mut Window,
 4764        cx: &mut Context<Self>,
 4765    ) {
 4766        if self.read_only(cx) {
 4767            return;
 4768        }
 4769
 4770        let text: Arc<str> = text.into();
 4771        self.transact(window, cx, |this, window, cx| {
 4772            let old_selections = this.selections.all_adjusted(cx);
 4773            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4774                let anchors = {
 4775                    let snapshot = buffer.read(cx);
 4776                    old_selections
 4777                        .iter()
 4778                        .map(|s| {
 4779                            let anchor = snapshot.anchor_after(s.head());
 4780                            s.map(|_| anchor)
 4781                        })
 4782                        .collect::<Vec<_>>()
 4783                };
 4784                buffer.edit(
 4785                    old_selections
 4786                        .iter()
 4787                        .map(|s| (s.start..s.end, text.clone())),
 4788                    autoindent_mode,
 4789                    cx,
 4790                );
 4791                anchors
 4792            });
 4793
 4794            this.change_selections(Default::default(), window, cx, |s| {
 4795                s.select_anchors(selection_anchors);
 4796            });
 4797
 4798            cx.notify();
 4799        });
 4800    }
 4801
 4802    fn trigger_completion_on_input(
 4803        &mut self,
 4804        text: &str,
 4805        trigger_in_words: bool,
 4806        window: &mut Window,
 4807        cx: &mut Context<Self>,
 4808    ) {
 4809        let completions_source = self
 4810            .context_menu
 4811            .borrow()
 4812            .as_ref()
 4813            .and_then(|menu| match menu {
 4814                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4815                CodeContextMenu::CodeActions(_) => None,
 4816            });
 4817
 4818        match completions_source {
 4819            Some(CompletionsMenuSource::Words) => {
 4820                self.show_word_completions(&ShowWordCompletions, window, cx)
 4821            }
 4822            Some(CompletionsMenuSource::Normal)
 4823            | Some(CompletionsMenuSource::SnippetChoices)
 4824            | None
 4825                if self.is_completion_trigger(
 4826                    text,
 4827                    trigger_in_words,
 4828                    completions_source.is_some(),
 4829                    cx,
 4830                ) =>
 4831            {
 4832                self.show_completions(
 4833                    &ShowCompletions {
 4834                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4835                    },
 4836                    window,
 4837                    cx,
 4838                )
 4839            }
 4840            _ => {
 4841                self.hide_context_menu(window, cx);
 4842            }
 4843        }
 4844    }
 4845
 4846    fn is_completion_trigger(
 4847        &self,
 4848        text: &str,
 4849        trigger_in_words: bool,
 4850        menu_is_open: bool,
 4851        cx: &mut Context<Self>,
 4852    ) -> bool {
 4853        let position = self.selections.newest_anchor().head();
 4854        let multibuffer = self.buffer.read(cx);
 4855        let Some(buffer) = position
 4856            .buffer_id
 4857            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4858        else {
 4859            return false;
 4860        };
 4861
 4862        if let Some(completion_provider) = &self.completion_provider {
 4863            completion_provider.is_completion_trigger(
 4864                &buffer,
 4865                position.text_anchor,
 4866                text,
 4867                trigger_in_words,
 4868                menu_is_open,
 4869                cx,
 4870            )
 4871        } else {
 4872            false
 4873        }
 4874    }
 4875
 4876    /// If any empty selections is touching the start of its innermost containing autoclose
 4877    /// region, expand it to select the brackets.
 4878    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4879        let selections = self.selections.all::<usize>(cx);
 4880        let buffer = self.buffer.read(cx).read(cx);
 4881        let new_selections = self
 4882            .selections_with_autoclose_regions(selections, &buffer)
 4883            .map(|(mut selection, region)| {
 4884                if !selection.is_empty() {
 4885                    return selection;
 4886                }
 4887
 4888                if let Some(region) = region {
 4889                    let mut range = region.range.to_offset(&buffer);
 4890                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4891                        range.start -= region.pair.start.len();
 4892                        if buffer.contains_str_at(range.start, &region.pair.start)
 4893                            && buffer.contains_str_at(range.end, &region.pair.end)
 4894                        {
 4895                            range.end += region.pair.end.len();
 4896                            selection.start = range.start;
 4897                            selection.end = range.end;
 4898
 4899                            return selection;
 4900                        }
 4901                    }
 4902                }
 4903
 4904                let always_treat_brackets_as_autoclosed = buffer
 4905                    .language_settings_at(selection.start, cx)
 4906                    .always_treat_brackets_as_autoclosed;
 4907
 4908                if !always_treat_brackets_as_autoclosed {
 4909                    return selection;
 4910                }
 4911
 4912                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4913                    for (pair, enabled) in scope.brackets() {
 4914                        if !enabled || !pair.close {
 4915                            continue;
 4916                        }
 4917
 4918                        if buffer.contains_str_at(selection.start, &pair.end) {
 4919                            let pair_start_len = pair.start.len();
 4920                            if buffer.contains_str_at(
 4921                                selection.start.saturating_sub(pair_start_len),
 4922                                &pair.start,
 4923                            ) {
 4924                                selection.start -= pair_start_len;
 4925                                selection.end += pair.end.len();
 4926
 4927                                return selection;
 4928                            }
 4929                        }
 4930                    }
 4931                }
 4932
 4933                selection
 4934            })
 4935            .collect();
 4936
 4937        drop(buffer);
 4938        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4939            selections.select(new_selections)
 4940        });
 4941    }
 4942
 4943    /// Iterate the given selections, and for each one, find the smallest surrounding
 4944    /// autoclose region. This uses the ordering of the selections and the autoclose
 4945    /// regions to avoid repeated comparisons.
 4946    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4947        &'a self,
 4948        selections: impl IntoIterator<Item = Selection<D>>,
 4949        buffer: &'a MultiBufferSnapshot,
 4950    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4951        let mut i = 0;
 4952        let mut regions = self.autoclose_regions.as_slice();
 4953        selections.into_iter().map(move |selection| {
 4954            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4955
 4956            let mut enclosing = None;
 4957            while let Some(pair_state) = regions.get(i) {
 4958                if pair_state.range.end.to_offset(buffer) < range.start {
 4959                    regions = &regions[i + 1..];
 4960                    i = 0;
 4961                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4962                    break;
 4963                } else {
 4964                    if pair_state.selection_id == selection.id {
 4965                        enclosing = Some(pair_state);
 4966                    }
 4967                    i += 1;
 4968                }
 4969            }
 4970
 4971            (selection, enclosing)
 4972        })
 4973    }
 4974
 4975    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4976    fn invalidate_autoclose_regions(
 4977        &mut self,
 4978        mut selections: &[Selection<Anchor>],
 4979        buffer: &MultiBufferSnapshot,
 4980    ) {
 4981        self.autoclose_regions.retain(|state| {
 4982            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 4983                return false;
 4984            }
 4985
 4986            let mut i = 0;
 4987            while let Some(selection) = selections.get(i) {
 4988                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4989                    selections = &selections[1..];
 4990                    continue;
 4991                }
 4992                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4993                    break;
 4994                }
 4995                if selection.id == state.selection_id {
 4996                    return true;
 4997                } else {
 4998                    i += 1;
 4999                }
 5000            }
 5001            false
 5002        });
 5003    }
 5004
 5005    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5006        let offset = position.to_offset(buffer);
 5007        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5008        if offset > word_range.start && kind == Some(CharKind::Word) {
 5009            Some(
 5010                buffer
 5011                    .text_for_range(word_range.start..offset)
 5012                    .collect::<String>(),
 5013            )
 5014        } else {
 5015            None
 5016        }
 5017    }
 5018
 5019    pub fn toggle_inline_values(
 5020        &mut self,
 5021        _: &ToggleInlineValues,
 5022        _: &mut Window,
 5023        cx: &mut Context<Self>,
 5024    ) {
 5025        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5026
 5027        self.refresh_inline_values(cx);
 5028    }
 5029
 5030    pub fn toggle_inlay_hints(
 5031        &mut self,
 5032        _: &ToggleInlayHints,
 5033        _: &mut Window,
 5034        cx: &mut Context<Self>,
 5035    ) {
 5036        self.refresh_inlay_hints(
 5037            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5038            cx,
 5039        );
 5040    }
 5041
 5042    pub fn inlay_hints_enabled(&self) -> bool {
 5043        self.inlay_hint_cache.enabled
 5044    }
 5045
 5046    pub fn inline_values_enabled(&self) -> bool {
 5047        self.inline_value_cache.enabled
 5048    }
 5049
 5050    #[cfg(any(test, feature = "test-support"))]
 5051    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5052        self.display_map
 5053            .read(cx)
 5054            .current_inlays()
 5055            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5056            .cloned()
 5057            .collect()
 5058    }
 5059
 5060    #[cfg(any(test, feature = "test-support"))]
 5061    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5062        self.display_map
 5063            .read(cx)
 5064            .current_inlays()
 5065            .cloned()
 5066            .collect()
 5067    }
 5068
 5069    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5070        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5071            return;
 5072        }
 5073
 5074        let reason_description = reason.description();
 5075        let ignore_debounce = matches!(
 5076            reason,
 5077            InlayHintRefreshReason::SettingsChange(_)
 5078                | InlayHintRefreshReason::Toggle(_)
 5079                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5080                | InlayHintRefreshReason::ModifiersChanged(_)
 5081        );
 5082        let (invalidate_cache, required_languages) = match reason {
 5083            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5084                match self.inlay_hint_cache.modifiers_override(enabled) {
 5085                    Some(enabled) => {
 5086                        if enabled {
 5087                            (InvalidationStrategy::RefreshRequested, None)
 5088                        } else {
 5089                            self.splice_inlays(
 5090                                &self
 5091                                    .visible_inlay_hints(cx)
 5092                                    .iter()
 5093                                    .map(|inlay| inlay.id)
 5094                                    .collect::<Vec<InlayId>>(),
 5095                                Vec::new(),
 5096                                cx,
 5097                            );
 5098                            return;
 5099                        }
 5100                    }
 5101                    None => return,
 5102                }
 5103            }
 5104            InlayHintRefreshReason::Toggle(enabled) => {
 5105                if self.inlay_hint_cache.toggle(enabled) {
 5106                    if enabled {
 5107                        (InvalidationStrategy::RefreshRequested, None)
 5108                    } else {
 5109                        self.splice_inlays(
 5110                            &self
 5111                                .visible_inlay_hints(cx)
 5112                                .iter()
 5113                                .map(|inlay| inlay.id)
 5114                                .collect::<Vec<InlayId>>(),
 5115                            Vec::new(),
 5116                            cx,
 5117                        );
 5118                        return;
 5119                    }
 5120                } else {
 5121                    return;
 5122                }
 5123            }
 5124            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5125                match self.inlay_hint_cache.update_settings(
 5126                    &self.buffer,
 5127                    new_settings,
 5128                    self.visible_inlay_hints(cx),
 5129                    cx,
 5130                ) {
 5131                    ControlFlow::Break(Some(InlaySplice {
 5132                        to_remove,
 5133                        to_insert,
 5134                    })) => {
 5135                        self.splice_inlays(&to_remove, to_insert, cx);
 5136                        return;
 5137                    }
 5138                    ControlFlow::Break(None) => return,
 5139                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5140                }
 5141            }
 5142            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5143                if let Some(InlaySplice {
 5144                    to_remove,
 5145                    to_insert,
 5146                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5147                {
 5148                    self.splice_inlays(&to_remove, to_insert, cx);
 5149                }
 5150                self.display_map.update(cx, |display_map, _| {
 5151                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5152                });
 5153                return;
 5154            }
 5155            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5156            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5157                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5158            }
 5159            InlayHintRefreshReason::RefreshRequested => {
 5160                (InvalidationStrategy::RefreshRequested, None)
 5161            }
 5162        };
 5163
 5164        if let Some(InlaySplice {
 5165            to_remove,
 5166            to_insert,
 5167        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5168            reason_description,
 5169            self.visible_excerpts(required_languages.as_ref(), cx),
 5170            invalidate_cache,
 5171            ignore_debounce,
 5172            cx,
 5173        ) {
 5174            self.splice_inlays(&to_remove, to_insert, cx);
 5175        }
 5176    }
 5177
 5178    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5179        self.display_map
 5180            .read(cx)
 5181            .current_inlays()
 5182            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5183            .cloned()
 5184            .collect()
 5185    }
 5186
 5187    pub fn visible_excerpts(
 5188        &self,
 5189        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5190        cx: &mut Context<Editor>,
 5191    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5192        let Some(project) = self.project.as_ref() else {
 5193            return HashMap::default();
 5194        };
 5195        let project = project.read(cx);
 5196        let multi_buffer = self.buffer().read(cx);
 5197        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5198        let multi_buffer_visible_start = self
 5199            .scroll_manager
 5200            .anchor()
 5201            .anchor
 5202            .to_point(&multi_buffer_snapshot);
 5203        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5204            multi_buffer_visible_start
 5205                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5206            Bias::Left,
 5207        );
 5208        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5209        multi_buffer_snapshot
 5210            .range_to_buffer_ranges(multi_buffer_visible_range)
 5211            .into_iter()
 5212            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5213            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5214                let buffer_file = project::File::from_dyn(buffer.file())?;
 5215                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5216                let worktree_entry = buffer_worktree
 5217                    .read(cx)
 5218                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5219                if worktree_entry.is_ignored {
 5220                    return None;
 5221                }
 5222
 5223                let language = buffer.language()?;
 5224                if let Some(restrict_to_languages) = restrict_to_languages {
 5225                    if !restrict_to_languages.contains(language) {
 5226                        return None;
 5227                    }
 5228                }
 5229                Some((
 5230                    excerpt_id,
 5231                    (
 5232                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5233                        buffer.version().clone(),
 5234                        excerpt_visible_range,
 5235                    ),
 5236                ))
 5237            })
 5238            .collect()
 5239    }
 5240
 5241    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5242        TextLayoutDetails {
 5243            text_system: window.text_system().clone(),
 5244            editor_style: self.style.clone().unwrap(),
 5245            rem_size: window.rem_size(),
 5246            scroll_anchor: self.scroll_manager.anchor(),
 5247            visible_rows: self.visible_line_count(),
 5248            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5249        }
 5250    }
 5251
 5252    pub fn splice_inlays(
 5253        &self,
 5254        to_remove: &[InlayId],
 5255        to_insert: Vec<Inlay>,
 5256        cx: &mut Context<Self>,
 5257    ) {
 5258        self.display_map.update(cx, |display_map, cx| {
 5259            display_map.splice_inlays(to_remove, to_insert, cx)
 5260        });
 5261        cx.notify();
 5262    }
 5263
 5264    fn trigger_on_type_formatting(
 5265        &self,
 5266        input: String,
 5267        window: &mut Window,
 5268        cx: &mut Context<Self>,
 5269    ) -> Option<Task<Result<()>>> {
 5270        if input.len() != 1 {
 5271            return None;
 5272        }
 5273
 5274        let project = self.project.as_ref()?;
 5275        let position = self.selections.newest_anchor().head();
 5276        let (buffer, buffer_position) = self
 5277            .buffer
 5278            .read(cx)
 5279            .text_anchor_for_position(position, cx)?;
 5280
 5281        let settings = language_settings::language_settings(
 5282            buffer
 5283                .read(cx)
 5284                .language_at(buffer_position)
 5285                .map(|l| l.name()),
 5286            buffer.read(cx).file(),
 5287            cx,
 5288        );
 5289        if !settings.use_on_type_format {
 5290            return None;
 5291        }
 5292
 5293        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5294        // hence we do LSP request & edit on host side only — add formats to host's history.
 5295        let push_to_lsp_host_history = true;
 5296        // If this is not the host, append its history with new edits.
 5297        let push_to_client_history = project.read(cx).is_via_collab();
 5298
 5299        let on_type_formatting = project.update(cx, |project, cx| {
 5300            project.on_type_format(
 5301                buffer.clone(),
 5302                buffer_position,
 5303                input,
 5304                push_to_lsp_host_history,
 5305                cx,
 5306            )
 5307        });
 5308        Some(cx.spawn_in(window, async move |editor, cx| {
 5309            if let Some(transaction) = on_type_formatting.await? {
 5310                if push_to_client_history {
 5311                    buffer
 5312                        .update(cx, |buffer, _| {
 5313                            buffer.push_transaction(transaction, Instant::now());
 5314                            buffer.finalize_last_transaction();
 5315                        })
 5316                        .ok();
 5317                }
 5318                editor.update(cx, |editor, cx| {
 5319                    editor.refresh_document_highlights(cx);
 5320                })?;
 5321            }
 5322            Ok(())
 5323        }))
 5324    }
 5325
 5326    pub fn show_word_completions(
 5327        &mut self,
 5328        _: &ShowWordCompletions,
 5329        window: &mut Window,
 5330        cx: &mut Context<Self>,
 5331    ) {
 5332        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5333    }
 5334
 5335    pub fn show_completions(
 5336        &mut self,
 5337        options: &ShowCompletions,
 5338        window: &mut Window,
 5339        cx: &mut Context<Self>,
 5340    ) {
 5341        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5342    }
 5343
 5344    fn open_or_update_completions_menu(
 5345        &mut self,
 5346        requested_source: Option<CompletionsMenuSource>,
 5347        trigger: Option<&str>,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) {
 5351        if self.pending_rename.is_some() {
 5352            return;
 5353        }
 5354
 5355        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5356
 5357        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5358        // inserted and selected. To handle that case, the start of the selection is used so that
 5359        // the menu starts with all choices.
 5360        let position = self
 5361            .selections
 5362            .newest_anchor()
 5363            .start
 5364            .bias_right(&multibuffer_snapshot);
 5365        if position.diff_base_anchor.is_some() {
 5366            return;
 5367        }
 5368        let (buffer, buffer_position) =
 5369            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5370                output
 5371            } else {
 5372                return;
 5373            };
 5374        let buffer_snapshot = buffer.read(cx).snapshot();
 5375
 5376        let query: Option<Arc<String>> =
 5377            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5378
 5379        drop(multibuffer_snapshot);
 5380
 5381        let provider = match requested_source {
 5382            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5383            Some(CompletionsMenuSource::Words) => None,
 5384            Some(CompletionsMenuSource::SnippetChoices) => {
 5385                log::error!("bug: SnippetChoices requested_source is not handled");
 5386                None
 5387            }
 5388        };
 5389
 5390        let sort_completions = provider
 5391            .as_ref()
 5392            .map_or(false, |provider| provider.sort_completions());
 5393
 5394        let filter_completions = provider
 5395            .as_ref()
 5396            .map_or(true, |provider| provider.filter_completions());
 5397
 5398        let trigger_kind = match trigger {
 5399            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5400                CompletionTriggerKind::TRIGGER_CHARACTER
 5401            }
 5402            _ => CompletionTriggerKind::INVOKED,
 5403        };
 5404        let completion_context = CompletionContext {
 5405            trigger_character: trigger.and_then(|trigger| {
 5406                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5407                    Some(String::from(trigger))
 5408                } else {
 5409                    None
 5410                }
 5411            }),
 5412            trigger_kind,
 5413        };
 5414
 5415        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5416        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5417        // involve trigger chars, so this is skipped in that case.
 5418        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5419        {
 5420            let menu_is_open = matches!(
 5421                self.context_menu.borrow().as_ref(),
 5422                Some(CodeContextMenu::Completions(_))
 5423            );
 5424            if menu_is_open {
 5425                self.hide_context_menu(window, cx);
 5426            }
 5427        }
 5428
 5429        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5430            if filter_completions {
 5431                menu.filter(query.clone(), provider.clone(), window, cx);
 5432            }
 5433            // When `is_incomplete` is false, no need to re-query completions when the current query
 5434            // is a suffix of the initial query.
 5435            if !menu.is_incomplete {
 5436                // If the new query is a suffix of the old query (typing more characters) and
 5437                // the previous result was complete, the existing completions can be filtered.
 5438                //
 5439                // Note that this is always true for snippet completions.
 5440                let query_matches = match (&menu.initial_query, &query) {
 5441                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5442                    (None, _) => true,
 5443                    _ => false,
 5444                };
 5445                if query_matches {
 5446                    let position_matches = if menu.initial_position == position {
 5447                        true
 5448                    } else {
 5449                        let snapshot = self.buffer.read(cx).read(cx);
 5450                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5451                    };
 5452                    if position_matches {
 5453                        return;
 5454                    }
 5455                }
 5456            }
 5457        };
 5458
 5459        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5460            buffer_snapshot.surrounding_word(buffer_position, false)
 5461        {
 5462            let word_to_exclude = buffer_snapshot
 5463                .text_for_range(word_range.clone())
 5464                .collect::<String>();
 5465            (
 5466                buffer_snapshot.anchor_before(word_range.start)
 5467                    ..buffer_snapshot.anchor_after(buffer_position),
 5468                Some(word_to_exclude),
 5469            )
 5470        } else {
 5471            (buffer_position..buffer_position, None)
 5472        };
 5473
 5474        let language = buffer_snapshot
 5475            .language_at(buffer_position)
 5476            .map(|language| language.name());
 5477
 5478        let completion_settings =
 5479            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5480
 5481        let show_completion_documentation = buffer_snapshot
 5482            .settings_at(buffer_position, cx)
 5483            .show_completion_documentation;
 5484
 5485        // The document can be large, so stay in reasonable bounds when searching for words,
 5486        // otherwise completion pop-up might be slow to appear.
 5487        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5488        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5489        let min_word_search = buffer_snapshot.clip_point(
 5490            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5491            Bias::Left,
 5492        );
 5493        let max_word_search = buffer_snapshot.clip_point(
 5494            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5495            Bias::Right,
 5496        );
 5497        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5498            ..buffer_snapshot.point_to_offset(max_word_search);
 5499
 5500        let skip_digits = query
 5501            .as_ref()
 5502            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5503
 5504        let (mut words, provider_responses) = match &provider {
 5505            Some(provider) => {
 5506                let provider_responses = provider.completions(
 5507                    position.excerpt_id,
 5508                    &buffer,
 5509                    buffer_position,
 5510                    completion_context,
 5511                    window,
 5512                    cx,
 5513                );
 5514
 5515                let words = match completion_settings.words {
 5516                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5517                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5518                        .background_spawn(async move {
 5519                            buffer_snapshot.words_in_range(WordsQuery {
 5520                                fuzzy_contents: None,
 5521                                range: word_search_range,
 5522                                skip_digits,
 5523                            })
 5524                        }),
 5525                };
 5526
 5527                (words, provider_responses)
 5528            }
 5529            None => (
 5530                cx.background_spawn(async move {
 5531                    buffer_snapshot.words_in_range(WordsQuery {
 5532                        fuzzy_contents: None,
 5533                        range: word_search_range,
 5534                        skip_digits,
 5535                    })
 5536                }),
 5537                Task::ready(Ok(Vec::new())),
 5538            ),
 5539        };
 5540
 5541        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5542
 5543        let id = post_inc(&mut self.next_completion_id);
 5544        let task = cx.spawn_in(window, async move |editor, cx| {
 5545            let Ok(()) = editor.update(cx, |this, _| {
 5546                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5547            }) else {
 5548                return;
 5549            };
 5550
 5551            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5552            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5553            let mut completions = Vec::new();
 5554            let mut is_incomplete = false;
 5555            if let Some(provider_responses) = provider_responses.await.log_err() {
 5556                if !provider_responses.is_empty() {
 5557                    for response in provider_responses {
 5558                        completions.extend(response.completions);
 5559                        is_incomplete = is_incomplete || response.is_incomplete;
 5560                    }
 5561                    if completion_settings.words == WordsCompletionMode::Fallback {
 5562                        words = Task::ready(BTreeMap::default());
 5563                    }
 5564                }
 5565            }
 5566
 5567            let mut words = words.await;
 5568            if let Some(word_to_exclude) = &word_to_exclude {
 5569                words.remove(word_to_exclude);
 5570            }
 5571            for lsp_completion in &completions {
 5572                words.remove(&lsp_completion.new_text);
 5573            }
 5574            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5575                replace_range: word_replace_range.clone(),
 5576                new_text: word.clone(),
 5577                label: CodeLabel::plain(word, None),
 5578                icon_path: None,
 5579                documentation: None,
 5580                source: CompletionSource::BufferWord {
 5581                    word_range,
 5582                    resolved: false,
 5583                },
 5584                insert_text_mode: Some(InsertTextMode::AS_IS),
 5585                confirm: None,
 5586            }));
 5587
 5588            let menu = if completions.is_empty() {
 5589                None
 5590            } else {
 5591                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5592                    let languages = editor
 5593                        .workspace
 5594                        .as_ref()
 5595                        .and_then(|(workspace, _)| workspace.upgrade())
 5596                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5597                    let menu = CompletionsMenu::new(
 5598                        id,
 5599                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5600                        sort_completions,
 5601                        show_completion_documentation,
 5602                        position,
 5603                        query.clone(),
 5604                        is_incomplete,
 5605                        buffer.clone(),
 5606                        completions.into(),
 5607                        snippet_sort_order,
 5608                        languages,
 5609                        language,
 5610                        cx,
 5611                    );
 5612
 5613                    let query = if filter_completions { query } else { None };
 5614                    let matches_task = if let Some(query) = query {
 5615                        menu.do_async_filtering(query, cx)
 5616                    } else {
 5617                        Task::ready(menu.unfiltered_matches())
 5618                    };
 5619                    (menu, matches_task)
 5620                }) else {
 5621                    return;
 5622                };
 5623
 5624                let matches = matches_task.await;
 5625
 5626                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5627                    // Newer menu already set, so exit.
 5628                    match editor.context_menu.borrow().as_ref() {
 5629                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5630                            if prev_menu.id > id {
 5631                                return;
 5632                            }
 5633                        }
 5634                        _ => {}
 5635                    };
 5636
 5637                    // Only valid to take prev_menu because it the new menu is immediately set
 5638                    // below, or the menu is hidden.
 5639                    match editor.context_menu.borrow_mut().take() {
 5640                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5641                            let position_matches =
 5642                                if prev_menu.initial_position == menu.initial_position {
 5643                                    true
 5644                                } else {
 5645                                    let snapshot = editor.buffer.read(cx).read(cx);
 5646                                    prev_menu.initial_position.to_offset(&snapshot)
 5647                                        == menu.initial_position.to_offset(&snapshot)
 5648                                };
 5649                            if position_matches {
 5650                                // Preserve markdown cache before `set_filter_results` because it will
 5651                                // try to populate the documentation cache.
 5652                                menu.preserve_markdown_cache(prev_menu);
 5653                            }
 5654                        }
 5655                        _ => {}
 5656                    };
 5657
 5658                    menu.set_filter_results(matches, provider, window, cx);
 5659                }) else {
 5660                    return;
 5661                };
 5662
 5663                menu.visible().then_some(menu)
 5664            };
 5665
 5666            editor
 5667                .update_in(cx, |editor, window, cx| {
 5668                    if editor.focus_handle.is_focused(window) {
 5669                        if let Some(menu) = menu {
 5670                            *editor.context_menu.borrow_mut() =
 5671                                Some(CodeContextMenu::Completions(menu));
 5672
 5673                            crate::hover_popover::hide_hover(editor, cx);
 5674                            if editor.show_edit_predictions_in_menu() {
 5675                                editor.update_visible_edit_prediction(window, cx);
 5676                            } else {
 5677                                editor.discard_edit_prediction(false, cx);
 5678                            }
 5679
 5680                            cx.notify();
 5681                            return;
 5682                        }
 5683                    }
 5684
 5685                    if editor.completion_tasks.len() <= 1 {
 5686                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5687                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5688                        // If it was already hidden and we don't show edit predictions in the menu,
 5689                        // we should also show the edit prediction when available.
 5690                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5691                            editor.update_visible_edit_prediction(window, cx);
 5692                        }
 5693                    }
 5694                })
 5695                .ok();
 5696        });
 5697
 5698        self.completion_tasks.push((id, task));
 5699    }
 5700
 5701    #[cfg(feature = "test-support")]
 5702    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5703        let menu = self.context_menu.borrow();
 5704        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5705            let completions = menu.completions.borrow();
 5706            Some(completions.to_vec())
 5707        } else {
 5708            None
 5709        }
 5710    }
 5711
 5712    pub fn with_completions_menu_matching_id<R>(
 5713        &self,
 5714        id: CompletionId,
 5715        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5716    ) -> R {
 5717        let mut context_menu = self.context_menu.borrow_mut();
 5718        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5719            return f(None);
 5720        };
 5721        if completions_menu.id != id {
 5722            return f(None);
 5723        }
 5724        f(Some(completions_menu))
 5725    }
 5726
 5727    pub fn confirm_completion(
 5728        &mut self,
 5729        action: &ConfirmCompletion,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5735    }
 5736
 5737    pub fn confirm_completion_insert(
 5738        &mut self,
 5739        _: &ConfirmCompletionInsert,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5745    }
 5746
 5747    pub fn confirm_completion_replace(
 5748        &mut self,
 5749        _: &ConfirmCompletionReplace,
 5750        window: &mut Window,
 5751        cx: &mut Context<Self>,
 5752    ) -> Option<Task<Result<()>>> {
 5753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5754        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5755    }
 5756
 5757    pub fn compose_completion(
 5758        &mut self,
 5759        action: &ComposeCompletion,
 5760        window: &mut Window,
 5761        cx: &mut Context<Self>,
 5762    ) -> Option<Task<Result<()>>> {
 5763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5764        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5765    }
 5766
 5767    fn do_completion(
 5768        &mut self,
 5769        item_ix: Option<usize>,
 5770        intent: CompletionIntent,
 5771        window: &mut Window,
 5772        cx: &mut Context<Editor>,
 5773    ) -> Option<Task<Result<()>>> {
 5774        use language::ToOffset as _;
 5775
 5776        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5777        else {
 5778            return None;
 5779        };
 5780
 5781        let candidate_id = {
 5782            let entries = completions_menu.entries.borrow();
 5783            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5784            if self.show_edit_predictions_in_menu() {
 5785                self.discard_edit_prediction(true, cx);
 5786            }
 5787            mat.candidate_id
 5788        };
 5789
 5790        let completion = completions_menu
 5791            .completions
 5792            .borrow()
 5793            .get(candidate_id)?
 5794            .clone();
 5795        cx.stop_propagation();
 5796
 5797        let buffer_handle = completions_menu.buffer.clone();
 5798
 5799        let CompletionEdit {
 5800            new_text,
 5801            snippet,
 5802            replace_range,
 5803        } = process_completion_for_edit(
 5804            &completion,
 5805            intent,
 5806            &buffer_handle,
 5807            &completions_menu.initial_position.text_anchor,
 5808            cx,
 5809        );
 5810
 5811        let buffer = buffer_handle.read(cx);
 5812        let snapshot = self.buffer.read(cx).snapshot(cx);
 5813        let newest_anchor = self.selections.newest_anchor();
 5814        let replace_range_multibuffer = {
 5815            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5816            let multibuffer_anchor = snapshot
 5817                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5818                .unwrap()
 5819                ..snapshot
 5820                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5821                    .unwrap();
 5822            multibuffer_anchor.start.to_offset(&snapshot)
 5823                ..multibuffer_anchor.end.to_offset(&snapshot)
 5824        };
 5825        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5826            return None;
 5827        }
 5828
 5829        let old_text = buffer
 5830            .text_for_range(replace_range.clone())
 5831            .collect::<String>();
 5832        let lookbehind = newest_anchor
 5833            .start
 5834            .text_anchor
 5835            .to_offset(buffer)
 5836            .saturating_sub(replace_range.start);
 5837        let lookahead = replace_range
 5838            .end
 5839            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5840        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5841        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5842
 5843        let selections = self.selections.all::<usize>(cx);
 5844        let mut ranges = Vec::new();
 5845        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5846
 5847        for selection in &selections {
 5848            let range = if selection.id == newest_anchor.id {
 5849                replace_range_multibuffer.clone()
 5850            } else {
 5851                let mut range = selection.range();
 5852
 5853                // if prefix is present, don't duplicate it
 5854                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5855                    range.start = range.start.saturating_sub(lookbehind);
 5856
 5857                    // if suffix is also present, mimic the newest cursor and replace it
 5858                    if selection.id != newest_anchor.id
 5859                        && snapshot.contains_str_at(range.end, suffix)
 5860                    {
 5861                        range.end += lookahead;
 5862                    }
 5863                }
 5864                range
 5865            };
 5866
 5867            ranges.push(range.clone());
 5868
 5869            if !self.linked_edit_ranges.is_empty() {
 5870                let start_anchor = snapshot.anchor_before(range.start);
 5871                let end_anchor = snapshot.anchor_after(range.end);
 5872                if let Some(ranges) = self
 5873                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5874                {
 5875                    for (buffer, edits) in ranges {
 5876                        linked_edits
 5877                            .entry(buffer.clone())
 5878                            .or_default()
 5879                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5880                    }
 5881                }
 5882            }
 5883        }
 5884
 5885        let common_prefix_len = old_text
 5886            .chars()
 5887            .zip(new_text.chars())
 5888            .take_while(|(a, b)| a == b)
 5889            .map(|(a, _)| a.len_utf8())
 5890            .sum::<usize>();
 5891
 5892        cx.emit(EditorEvent::InputHandled {
 5893            utf16_range_to_replace: None,
 5894            text: new_text[common_prefix_len..].into(),
 5895        });
 5896
 5897        self.transact(window, cx, |editor, window, cx| {
 5898            if let Some(mut snippet) = snippet {
 5899                snippet.text = new_text.to_string();
 5900                editor
 5901                    .insert_snippet(&ranges, snippet, window, cx)
 5902                    .log_err();
 5903            } else {
 5904                editor.buffer.update(cx, |multi_buffer, cx| {
 5905                    let auto_indent = match completion.insert_text_mode {
 5906                        Some(InsertTextMode::AS_IS) => None,
 5907                        _ => editor.autoindent_mode.clone(),
 5908                    };
 5909                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5910                    multi_buffer.edit(edits, auto_indent, cx);
 5911                });
 5912            }
 5913            for (buffer, edits) in linked_edits {
 5914                buffer.update(cx, |buffer, cx| {
 5915                    let snapshot = buffer.snapshot();
 5916                    let edits = edits
 5917                        .into_iter()
 5918                        .map(|(range, text)| {
 5919                            use text::ToPoint as TP;
 5920                            let end_point = TP::to_point(&range.end, &snapshot);
 5921                            let start_point = TP::to_point(&range.start, &snapshot);
 5922                            (start_point..end_point, text)
 5923                        })
 5924                        .sorted_by_key(|(range, _)| range.start);
 5925                    buffer.edit(edits, None, cx);
 5926                })
 5927            }
 5928
 5929            editor.refresh_edit_prediction(true, false, window, cx);
 5930        });
 5931        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5932
 5933        let show_new_completions_on_confirm = completion
 5934            .confirm
 5935            .as_ref()
 5936            .map_or(false, |confirm| confirm(intent, window, cx));
 5937        if show_new_completions_on_confirm {
 5938            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5939        }
 5940
 5941        let provider = self.completion_provider.as_ref()?;
 5942        drop(completion);
 5943        let apply_edits = provider.apply_additional_edits_for_completion(
 5944            buffer_handle,
 5945            completions_menu.completions.clone(),
 5946            candidate_id,
 5947            true,
 5948            cx,
 5949        );
 5950
 5951        let editor_settings = EditorSettings::get_global(cx);
 5952        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5953            // After the code completion is finished, users often want to know what signatures are needed.
 5954            // so we should automatically call signature_help
 5955            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5956        }
 5957
 5958        Some(cx.foreground_executor().spawn(async move {
 5959            apply_edits.await?;
 5960            Ok(())
 5961        }))
 5962    }
 5963
 5964    pub fn toggle_code_actions(
 5965        &mut self,
 5966        action: &ToggleCodeActions,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) {
 5970        let quick_launch = action.quick_launch;
 5971        let mut context_menu = self.context_menu.borrow_mut();
 5972        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5973            if code_actions.deployed_from == action.deployed_from {
 5974                // Toggle if we're selecting the same one
 5975                *context_menu = None;
 5976                cx.notify();
 5977                return;
 5978            } else {
 5979                // Otherwise, clear it and start a new one
 5980                *context_menu = None;
 5981                cx.notify();
 5982            }
 5983        }
 5984        drop(context_menu);
 5985        let snapshot = self.snapshot(window, cx);
 5986        let deployed_from = action.deployed_from.clone();
 5987        let action = action.clone();
 5988        self.completion_tasks.clear();
 5989        self.discard_edit_prediction(false, cx);
 5990
 5991        let multibuffer_point = match &action.deployed_from {
 5992            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5993                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5994            }
 5995            _ => self.selections.newest::<Point>(cx).head(),
 5996        };
 5997        let Some((buffer, buffer_row)) = snapshot
 5998            .buffer_snapshot
 5999            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6000            .and_then(|(buffer_snapshot, range)| {
 6001                self.buffer()
 6002                    .read(cx)
 6003                    .buffer(buffer_snapshot.remote_id())
 6004                    .map(|buffer| (buffer, range.start.row))
 6005            })
 6006        else {
 6007            return;
 6008        };
 6009        let buffer_id = buffer.read(cx).remote_id();
 6010        let tasks = self
 6011            .tasks
 6012            .get(&(buffer_id, buffer_row))
 6013            .map(|t| Arc::new(t.to_owned()));
 6014
 6015        if !self.focus_handle.is_focused(window) {
 6016            return;
 6017        }
 6018        let project = self.project.clone();
 6019
 6020        let code_actions_task = match deployed_from {
 6021            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6022            _ => self.code_actions(buffer_row, window, cx),
 6023        };
 6024
 6025        let runnable_task = match deployed_from {
 6026            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6027            _ => {
 6028                let mut task_context_task = Task::ready(None);
 6029                if let Some(tasks) = &tasks {
 6030                    if let Some(project) = project {
 6031                        task_context_task =
 6032                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6033                    }
 6034                }
 6035
 6036                cx.spawn_in(window, {
 6037                    let buffer = buffer.clone();
 6038                    async move |editor, cx| {
 6039                        let task_context = task_context_task.await;
 6040
 6041                        let resolved_tasks =
 6042                            tasks
 6043                                .zip(task_context.clone())
 6044                                .map(|(tasks, task_context)| ResolvedTasks {
 6045                                    templates: tasks.resolve(&task_context).collect(),
 6046                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6047                                        multibuffer_point.row,
 6048                                        tasks.column,
 6049                                    )),
 6050                                });
 6051                        let debug_scenarios = editor
 6052                            .update(cx, |editor, cx| {
 6053                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6054                            })?
 6055                            .await;
 6056                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6057                    }
 6058                })
 6059            }
 6060        };
 6061
 6062        cx.spawn_in(window, async move |editor, cx| {
 6063            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6064            let code_actions = code_actions_task.await;
 6065            let spawn_straight_away = quick_launch
 6066                && resolved_tasks
 6067                    .as_ref()
 6068                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6069                && code_actions
 6070                    .as_ref()
 6071                    .map_or(true, |actions| actions.is_empty())
 6072                && debug_scenarios.is_empty();
 6073
 6074            editor.update_in(cx, |editor, window, cx| {
 6075                crate::hover_popover::hide_hover(editor, cx);
 6076                let actions = CodeActionContents::new(
 6077                    resolved_tasks,
 6078                    code_actions,
 6079                    debug_scenarios,
 6080                    task_context.unwrap_or_default(),
 6081                );
 6082
 6083                // Don't show the menu if there are no actions available
 6084                if actions.is_empty() {
 6085                    cx.notify();
 6086                    return Task::ready(Ok(()));
 6087                }
 6088
 6089                *editor.context_menu.borrow_mut() =
 6090                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6091                        buffer,
 6092                        actions,
 6093                        selected_item: Default::default(),
 6094                        scroll_handle: UniformListScrollHandle::default(),
 6095                        deployed_from,
 6096                    }));
 6097                cx.notify();
 6098                if spawn_straight_away {
 6099                    if let Some(task) = editor.confirm_code_action(
 6100                        &ConfirmCodeAction { item_ix: Some(0) },
 6101                        window,
 6102                        cx,
 6103                    ) {
 6104                        return task;
 6105                    }
 6106                }
 6107
 6108                Task::ready(Ok(()))
 6109            })
 6110        })
 6111        .detach_and_log_err(cx);
 6112    }
 6113
 6114    fn debug_scenarios(
 6115        &mut self,
 6116        resolved_tasks: &Option<ResolvedTasks>,
 6117        buffer: &Entity<Buffer>,
 6118        cx: &mut App,
 6119    ) -> Task<Vec<task::DebugScenario>> {
 6120        maybe!({
 6121            let project = self.project.as_ref()?;
 6122            let dap_store = project.read(cx).dap_store();
 6123            let mut scenarios = vec![];
 6124            let resolved_tasks = resolved_tasks.as_ref()?;
 6125            let buffer = buffer.read(cx);
 6126            let language = buffer.language()?;
 6127            let file = buffer.file();
 6128            let debug_adapter = language_settings(language.name().into(), file, cx)
 6129                .debuggers
 6130                .first()
 6131                .map(SharedString::from)
 6132                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6133
 6134            dap_store.update(cx, |dap_store, cx| {
 6135                for (_, task) in &resolved_tasks.templates {
 6136                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6137                        task.original_task().clone(),
 6138                        debug_adapter.clone().into(),
 6139                        task.display_label().to_owned().into(),
 6140                        cx,
 6141                    );
 6142                    scenarios.push(maybe_scenario);
 6143                }
 6144            });
 6145            Some(cx.background_spawn(async move {
 6146                let scenarios = futures::future::join_all(scenarios)
 6147                    .await
 6148                    .into_iter()
 6149                    .flatten()
 6150                    .collect::<Vec<_>>();
 6151                scenarios
 6152            }))
 6153        })
 6154        .unwrap_or_else(|| Task::ready(vec![]))
 6155    }
 6156
 6157    fn code_actions(
 6158        &mut self,
 6159        buffer_row: u32,
 6160        window: &mut Window,
 6161        cx: &mut Context<Self>,
 6162    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6163        let mut task = self.code_actions_task.take();
 6164        cx.spawn_in(window, async move |editor, cx| {
 6165            while let Some(prev_task) = task {
 6166                prev_task.await.log_err();
 6167                task = editor
 6168                    .update(cx, |this, _| this.code_actions_task.take())
 6169                    .ok()?;
 6170            }
 6171
 6172            editor
 6173                .update(cx, |editor, cx| {
 6174                    editor
 6175                        .available_code_actions
 6176                        .clone()
 6177                        .and_then(|(location, code_actions)| {
 6178                            let snapshot = location.buffer.read(cx).snapshot();
 6179                            let point_range = location.range.to_point(&snapshot);
 6180                            let point_range = point_range.start.row..=point_range.end.row;
 6181                            if point_range.contains(&buffer_row) {
 6182                                Some(code_actions)
 6183                            } else {
 6184                                None
 6185                            }
 6186                        })
 6187                })
 6188                .ok()
 6189                .flatten()
 6190        })
 6191    }
 6192
 6193    pub fn confirm_code_action(
 6194        &mut self,
 6195        action: &ConfirmCodeAction,
 6196        window: &mut Window,
 6197        cx: &mut Context<Self>,
 6198    ) -> Option<Task<Result<()>>> {
 6199        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6200
 6201        let actions_menu =
 6202            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6203                menu
 6204            } else {
 6205                return None;
 6206            };
 6207
 6208        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6209        let action = actions_menu.actions.get(action_ix)?;
 6210        let title = action.label();
 6211        let buffer = actions_menu.buffer;
 6212        let workspace = self.workspace()?;
 6213
 6214        match action {
 6215            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6216                workspace.update(cx, |workspace, cx| {
 6217                    workspace.schedule_resolved_task(
 6218                        task_source_kind,
 6219                        resolved_task,
 6220                        false,
 6221                        window,
 6222                        cx,
 6223                    );
 6224
 6225                    Some(Task::ready(Ok(())))
 6226                })
 6227            }
 6228            CodeActionsItem::CodeAction {
 6229                excerpt_id,
 6230                action,
 6231                provider,
 6232            } => {
 6233                let apply_code_action =
 6234                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6235                let workspace = workspace.downgrade();
 6236                Some(cx.spawn_in(window, async move |editor, cx| {
 6237                    let project_transaction = apply_code_action.await?;
 6238                    Self::open_project_transaction(
 6239                        &editor,
 6240                        workspace,
 6241                        project_transaction,
 6242                        title,
 6243                        cx,
 6244                    )
 6245                    .await
 6246                }))
 6247            }
 6248            CodeActionsItem::DebugScenario(scenario) => {
 6249                let context = actions_menu.actions.context.clone();
 6250
 6251                workspace.update(cx, |workspace, cx| {
 6252                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6253                    workspace.start_debug_session(
 6254                        scenario,
 6255                        context,
 6256                        Some(buffer),
 6257                        None,
 6258                        window,
 6259                        cx,
 6260                    );
 6261                });
 6262                Some(Task::ready(Ok(())))
 6263            }
 6264        }
 6265    }
 6266
 6267    pub async fn open_project_transaction(
 6268        this: &WeakEntity<Editor>,
 6269        workspace: WeakEntity<Workspace>,
 6270        transaction: ProjectTransaction,
 6271        title: String,
 6272        cx: &mut AsyncWindowContext,
 6273    ) -> Result<()> {
 6274        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6275        cx.update(|_, cx| {
 6276            entries.sort_unstable_by_key(|(buffer, _)| {
 6277                buffer.read(cx).file().map(|f| f.path().clone())
 6278            });
 6279        })?;
 6280
 6281        // If the project transaction's edits are all contained within this editor, then
 6282        // avoid opening a new editor to display them.
 6283
 6284        if let Some((buffer, transaction)) = entries.first() {
 6285            if entries.len() == 1 {
 6286                let excerpt = this.update(cx, |editor, cx| {
 6287                    editor
 6288                        .buffer()
 6289                        .read(cx)
 6290                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6291                })?;
 6292                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6293                    if excerpted_buffer == *buffer {
 6294                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6295                            let excerpt_range = excerpt_range.to_offset(buffer);
 6296                            buffer
 6297                                .edited_ranges_for_transaction::<usize>(transaction)
 6298                                .all(|range| {
 6299                                    excerpt_range.start <= range.start
 6300                                        && excerpt_range.end >= range.end
 6301                                })
 6302                        })?;
 6303
 6304                        if all_edits_within_excerpt {
 6305                            return Ok(());
 6306                        }
 6307                    }
 6308                }
 6309            }
 6310        } else {
 6311            return Ok(());
 6312        }
 6313
 6314        let mut ranges_to_highlight = Vec::new();
 6315        let excerpt_buffer = cx.new(|cx| {
 6316            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6317            for (buffer_handle, transaction) in &entries {
 6318                let edited_ranges = buffer_handle
 6319                    .read(cx)
 6320                    .edited_ranges_for_transaction::<Point>(transaction)
 6321                    .collect::<Vec<_>>();
 6322                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6323                    PathKey::for_buffer(buffer_handle, cx),
 6324                    buffer_handle.clone(),
 6325                    edited_ranges,
 6326                    DEFAULT_MULTIBUFFER_CONTEXT,
 6327                    cx,
 6328                );
 6329
 6330                ranges_to_highlight.extend(ranges);
 6331            }
 6332            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6333            multibuffer
 6334        })?;
 6335
 6336        workspace.update_in(cx, |workspace, window, cx| {
 6337            let project = workspace.project().clone();
 6338            let editor =
 6339                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6340            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6341            editor.update(cx, |editor, cx| {
 6342                editor.highlight_background::<Self>(
 6343                    &ranges_to_highlight,
 6344                    |theme| theme.colors().editor_highlighted_line_background,
 6345                    cx,
 6346                );
 6347            });
 6348        })?;
 6349
 6350        Ok(())
 6351    }
 6352
 6353    pub fn clear_code_action_providers(&mut self) {
 6354        self.code_action_providers.clear();
 6355        self.available_code_actions.take();
 6356    }
 6357
 6358    pub fn add_code_action_provider(
 6359        &mut self,
 6360        provider: Rc<dyn CodeActionProvider>,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) {
 6364        if self
 6365            .code_action_providers
 6366            .iter()
 6367            .any(|existing_provider| existing_provider.id() == provider.id())
 6368        {
 6369            return;
 6370        }
 6371
 6372        self.code_action_providers.push(provider);
 6373        self.refresh_code_actions(window, cx);
 6374    }
 6375
 6376    pub fn remove_code_action_provider(
 6377        &mut self,
 6378        id: Arc<str>,
 6379        window: &mut Window,
 6380        cx: &mut Context<Self>,
 6381    ) {
 6382        self.code_action_providers
 6383            .retain(|provider| provider.id() != id);
 6384        self.refresh_code_actions(window, cx);
 6385    }
 6386
 6387    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6388        !self.code_action_providers.is_empty()
 6389            && EditorSettings::get_global(cx).toolbar.code_actions
 6390    }
 6391
 6392    pub fn has_available_code_actions(&self) -> bool {
 6393        self.available_code_actions
 6394            .as_ref()
 6395            .is_some_and(|(_, actions)| !actions.is_empty())
 6396    }
 6397
 6398    fn render_inline_code_actions(
 6399        &self,
 6400        icon_size: ui::IconSize,
 6401        display_row: DisplayRow,
 6402        is_active: bool,
 6403        cx: &mut Context<Self>,
 6404    ) -> AnyElement {
 6405        let show_tooltip = !self.context_menu_visible();
 6406        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6407            .icon_size(icon_size)
 6408            .shape(ui::IconButtonShape::Square)
 6409            .icon_color(ui::Color::Hidden)
 6410            .toggle_state(is_active)
 6411            .when(show_tooltip, |this| {
 6412                this.tooltip({
 6413                    let focus_handle = self.focus_handle.clone();
 6414                    move |window, cx| {
 6415                        Tooltip::for_action_in(
 6416                            "Toggle Code Actions",
 6417                            &ToggleCodeActions {
 6418                                deployed_from: None,
 6419                                quick_launch: false,
 6420                            },
 6421                            &focus_handle,
 6422                            window,
 6423                            cx,
 6424                        )
 6425                    }
 6426                })
 6427            })
 6428            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6429                window.focus(&editor.focus_handle(cx));
 6430                editor.toggle_code_actions(
 6431                    &crate::actions::ToggleCodeActions {
 6432                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6433                            display_row,
 6434                        )),
 6435                        quick_launch: false,
 6436                    },
 6437                    window,
 6438                    cx,
 6439                );
 6440            }))
 6441            .into_any_element()
 6442    }
 6443
 6444    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6445        &self.context_menu
 6446    }
 6447
 6448    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6449        let newest_selection = self.selections.newest_anchor().clone();
 6450        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6451        let buffer = self.buffer.read(cx);
 6452        if newest_selection.head().diff_base_anchor.is_some() {
 6453            return None;
 6454        }
 6455        let (start_buffer, start) =
 6456            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6457        let (end_buffer, end) =
 6458            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6459        if start_buffer != end_buffer {
 6460            return None;
 6461        }
 6462
 6463        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6464            cx.background_executor()
 6465                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6466                .await;
 6467
 6468            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6469                let providers = this.code_action_providers.clone();
 6470                let tasks = this
 6471                    .code_action_providers
 6472                    .iter()
 6473                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6474                    .collect::<Vec<_>>();
 6475                (providers, tasks)
 6476            })?;
 6477
 6478            let mut actions = Vec::new();
 6479            for (provider, provider_actions) in
 6480                providers.into_iter().zip(future::join_all(tasks).await)
 6481            {
 6482                if let Some(provider_actions) = provider_actions.log_err() {
 6483                    actions.extend(provider_actions.into_iter().map(|action| {
 6484                        AvailableCodeAction {
 6485                            excerpt_id: newest_selection.start.excerpt_id,
 6486                            action,
 6487                            provider: provider.clone(),
 6488                        }
 6489                    }));
 6490                }
 6491            }
 6492
 6493            this.update(cx, |this, cx| {
 6494                this.available_code_actions = if actions.is_empty() {
 6495                    None
 6496                } else {
 6497                    Some((
 6498                        Location {
 6499                            buffer: start_buffer,
 6500                            range: start..end,
 6501                        },
 6502                        actions.into(),
 6503                    ))
 6504                };
 6505                cx.notify();
 6506            })
 6507        }));
 6508        None
 6509    }
 6510
 6511    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6512        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6513            self.show_git_blame_inline = false;
 6514
 6515            self.show_git_blame_inline_delay_task =
 6516                Some(cx.spawn_in(window, async move |this, cx| {
 6517                    cx.background_executor().timer(delay).await;
 6518
 6519                    this.update(cx, |this, cx| {
 6520                        this.show_git_blame_inline = true;
 6521                        cx.notify();
 6522                    })
 6523                    .log_err();
 6524                }));
 6525        }
 6526    }
 6527
 6528    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6529        let snapshot = self.snapshot(window, cx);
 6530        let cursor = self.selections.newest::<Point>(cx).head();
 6531        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6532        else {
 6533            return;
 6534        };
 6535
 6536        let Some(blame) = self.blame.as_ref() else {
 6537            return;
 6538        };
 6539
 6540        let row_info = RowInfo {
 6541            buffer_id: Some(buffer.remote_id()),
 6542            buffer_row: Some(point.row),
 6543            ..Default::default()
 6544        };
 6545        let Some(blame_entry) = blame
 6546            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6547            .flatten()
 6548        else {
 6549            return;
 6550        };
 6551
 6552        let anchor = self.selections.newest_anchor().head();
 6553        let position = self.to_pixel_point(anchor, &snapshot, window);
 6554        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6555            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6556        };
 6557    }
 6558
 6559    fn show_blame_popover(
 6560        &mut self,
 6561        blame_entry: &BlameEntry,
 6562        position: gpui::Point<Pixels>,
 6563        ignore_timeout: bool,
 6564        cx: &mut Context<Self>,
 6565    ) {
 6566        if let Some(state) = &mut self.inline_blame_popover {
 6567            state.hide_task.take();
 6568        } else {
 6569            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6570            let blame_entry = blame_entry.clone();
 6571            let show_task = cx.spawn(async move |editor, cx| {
 6572                if !ignore_timeout {
 6573                    cx.background_executor()
 6574                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6575                        .await;
 6576                }
 6577                editor
 6578                    .update(cx, |editor, cx| {
 6579                        editor.inline_blame_popover_show_task.take();
 6580                        let Some(blame) = editor.blame.as_ref() else {
 6581                            return;
 6582                        };
 6583                        let blame = blame.read(cx);
 6584                        let details = blame.details_for_entry(&blame_entry);
 6585                        let markdown = cx.new(|cx| {
 6586                            Markdown::new(
 6587                                details
 6588                                    .as_ref()
 6589                                    .map(|message| message.message.clone())
 6590                                    .unwrap_or_default(),
 6591                                None,
 6592                                None,
 6593                                cx,
 6594                            )
 6595                        });
 6596                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6597                            position,
 6598                            hide_task: None,
 6599                            popover_bounds: None,
 6600                            popover_state: InlineBlamePopoverState {
 6601                                scroll_handle: ScrollHandle::new(),
 6602                                commit_message: details,
 6603                                markdown,
 6604                            },
 6605                            keyboard_grace: ignore_timeout,
 6606                        });
 6607                        cx.notify();
 6608                    })
 6609                    .ok();
 6610            });
 6611            self.inline_blame_popover_show_task = Some(show_task);
 6612        }
 6613    }
 6614
 6615    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6616        self.inline_blame_popover_show_task.take();
 6617        if let Some(state) = &mut self.inline_blame_popover {
 6618            let hide_task = cx.spawn(async move |editor, cx| {
 6619                cx.background_executor()
 6620                    .timer(std::time::Duration::from_millis(100))
 6621                    .await;
 6622                editor
 6623                    .update(cx, |editor, cx| {
 6624                        editor.inline_blame_popover.take();
 6625                        cx.notify();
 6626                    })
 6627                    .ok();
 6628            });
 6629            state.hide_task = Some(hide_task);
 6630        }
 6631    }
 6632
 6633    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6634        if self.pending_rename.is_some() {
 6635            return None;
 6636        }
 6637
 6638        let provider = self.semantics_provider.clone()?;
 6639        let buffer = self.buffer.read(cx);
 6640        let newest_selection = self.selections.newest_anchor().clone();
 6641        let cursor_position = newest_selection.head();
 6642        let (cursor_buffer, cursor_buffer_position) =
 6643            buffer.text_anchor_for_position(cursor_position, cx)?;
 6644        let (tail_buffer, tail_buffer_position) =
 6645            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6646        if cursor_buffer != tail_buffer {
 6647            return None;
 6648        }
 6649
 6650        let snapshot = cursor_buffer.read(cx).snapshot();
 6651        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6652        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6653        if start_word_range != end_word_range {
 6654            self.document_highlights_task.take();
 6655            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6656            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6657            return None;
 6658        }
 6659
 6660        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6661        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6662            cx.background_executor()
 6663                .timer(Duration::from_millis(debounce))
 6664                .await;
 6665
 6666            let highlights = if let Some(highlights) = cx
 6667                .update(|cx| {
 6668                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6669                })
 6670                .ok()
 6671                .flatten()
 6672            {
 6673                highlights.await.log_err()
 6674            } else {
 6675                None
 6676            };
 6677
 6678            if let Some(highlights) = highlights {
 6679                this.update(cx, |this, cx| {
 6680                    if this.pending_rename.is_some() {
 6681                        return;
 6682                    }
 6683
 6684                    let buffer_id = cursor_position.buffer_id;
 6685                    let buffer = this.buffer.read(cx);
 6686                    if !buffer
 6687                        .text_anchor_for_position(cursor_position, cx)
 6688                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6689                    {
 6690                        return;
 6691                    }
 6692
 6693                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6694                    let mut write_ranges = Vec::new();
 6695                    let mut read_ranges = Vec::new();
 6696                    for highlight in highlights {
 6697                        for (excerpt_id, excerpt_range) in
 6698                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6699                        {
 6700                            let start = highlight
 6701                                .range
 6702                                .start
 6703                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6704                            let end = highlight
 6705                                .range
 6706                                .end
 6707                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6708                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6709                                continue;
 6710                            }
 6711
 6712                            let range = Anchor {
 6713                                buffer_id,
 6714                                excerpt_id,
 6715                                text_anchor: start,
 6716                                diff_base_anchor: None,
 6717                            }..Anchor {
 6718                                buffer_id,
 6719                                excerpt_id,
 6720                                text_anchor: end,
 6721                                diff_base_anchor: None,
 6722                            };
 6723                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6724                                write_ranges.push(range);
 6725                            } else {
 6726                                read_ranges.push(range);
 6727                            }
 6728                        }
 6729                    }
 6730
 6731                    this.highlight_background::<DocumentHighlightRead>(
 6732                        &read_ranges,
 6733                        |theme| theme.colors().editor_document_highlight_read_background,
 6734                        cx,
 6735                    );
 6736                    this.highlight_background::<DocumentHighlightWrite>(
 6737                        &write_ranges,
 6738                        |theme| theme.colors().editor_document_highlight_write_background,
 6739                        cx,
 6740                    );
 6741                    cx.notify();
 6742                })
 6743                .log_err();
 6744            }
 6745        }));
 6746        None
 6747    }
 6748
 6749    fn prepare_highlight_query_from_selection(
 6750        &mut self,
 6751        cx: &mut Context<Editor>,
 6752    ) -> Option<(String, Range<Anchor>)> {
 6753        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6754            return None;
 6755        }
 6756        if !EditorSettings::get_global(cx).selection_highlight {
 6757            return None;
 6758        }
 6759        if self.selections.count() != 1 || self.selections.line_mode {
 6760            return None;
 6761        }
 6762        let selection = self.selections.newest::<Point>(cx);
 6763        if selection.is_empty() || selection.start.row != selection.end.row {
 6764            return None;
 6765        }
 6766        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6767        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6768        let query = multi_buffer_snapshot
 6769            .text_for_range(selection_anchor_range.clone())
 6770            .collect::<String>();
 6771        if query.trim().is_empty() {
 6772            return None;
 6773        }
 6774        Some((query, selection_anchor_range))
 6775    }
 6776
 6777    fn update_selection_occurrence_highlights(
 6778        &mut self,
 6779        query_text: String,
 6780        query_range: Range<Anchor>,
 6781        multi_buffer_range_to_query: Range<Point>,
 6782        use_debounce: bool,
 6783        window: &mut Window,
 6784        cx: &mut Context<Editor>,
 6785    ) -> Task<()> {
 6786        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6787        cx.spawn_in(window, async move |editor, cx| {
 6788            if use_debounce {
 6789                cx.background_executor()
 6790                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6791                    .await;
 6792            }
 6793            let match_task = cx.background_spawn(async move {
 6794                let buffer_ranges = multi_buffer_snapshot
 6795                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6796                    .into_iter()
 6797                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6798                let mut match_ranges = Vec::new();
 6799                let Ok(regex) = project::search::SearchQuery::text(
 6800                    query_text.clone(),
 6801                    false,
 6802                    false,
 6803                    false,
 6804                    Default::default(),
 6805                    Default::default(),
 6806                    false,
 6807                    None,
 6808                ) else {
 6809                    return Vec::default();
 6810                };
 6811                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6812                    match_ranges.extend(
 6813                        regex
 6814                            .search(&buffer_snapshot, Some(search_range.clone()))
 6815                            .await
 6816                            .into_iter()
 6817                            .filter_map(|match_range| {
 6818                                let match_start = buffer_snapshot
 6819                                    .anchor_after(search_range.start + match_range.start);
 6820                                let match_end = buffer_snapshot
 6821                                    .anchor_before(search_range.start + match_range.end);
 6822                                let match_anchor_range = Anchor::range_in_buffer(
 6823                                    excerpt_id,
 6824                                    buffer_snapshot.remote_id(),
 6825                                    match_start..match_end,
 6826                                );
 6827                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6828                            }),
 6829                    );
 6830                }
 6831                match_ranges
 6832            });
 6833            let match_ranges = match_task.await;
 6834            editor
 6835                .update_in(cx, |editor, _, cx| {
 6836                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6837                    if !match_ranges.is_empty() {
 6838                        editor.highlight_background::<SelectedTextHighlight>(
 6839                            &match_ranges,
 6840                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6841                            cx,
 6842                        )
 6843                    }
 6844                })
 6845                .log_err();
 6846        })
 6847    }
 6848
 6849    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6850        struct NewlineFold;
 6851        let type_id = std::any::TypeId::of::<NewlineFold>();
 6852        if !self.mode.is_single_line() {
 6853            return;
 6854        }
 6855        let snapshot = self.snapshot(window, cx);
 6856        if snapshot.buffer_snapshot.max_point().row == 0 {
 6857            return;
 6858        }
 6859        let task = cx.background_spawn(async move {
 6860            let new_newlines = snapshot
 6861                .buffer_chars_at(0)
 6862                .filter_map(|(c, i)| {
 6863                    if c == '\n' {
 6864                        Some(
 6865                            snapshot.buffer_snapshot.anchor_after(i)
 6866                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6867                        )
 6868                    } else {
 6869                        None
 6870                    }
 6871                })
 6872                .collect::<Vec<_>>();
 6873            let existing_newlines = snapshot
 6874                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6875                .filter_map(|fold| {
 6876                    if fold.placeholder.type_tag == Some(type_id) {
 6877                        Some(fold.range.start..fold.range.end)
 6878                    } else {
 6879                        None
 6880                    }
 6881                })
 6882                .collect::<Vec<_>>();
 6883
 6884            (new_newlines, existing_newlines)
 6885        });
 6886        self.folding_newlines = cx.spawn(async move |this, cx| {
 6887            let (new_newlines, existing_newlines) = task.await;
 6888            if new_newlines == existing_newlines {
 6889                return;
 6890            }
 6891            let placeholder = FoldPlaceholder {
 6892                render: Arc::new(move |_, _, cx| {
 6893                    div()
 6894                        .bg(cx.theme().status().hint_background)
 6895                        .border_b_1()
 6896                        .size_full()
 6897                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6898                        .border_color(cx.theme().status().hint)
 6899                        .child("\\n")
 6900                        .into_any()
 6901                }),
 6902                constrain_width: false,
 6903                merge_adjacent: false,
 6904                type_tag: Some(type_id),
 6905            };
 6906            let creases = new_newlines
 6907                .into_iter()
 6908                .map(|range| Crease::simple(range, placeholder.clone()))
 6909                .collect();
 6910            this.update(cx, |this, cx| {
 6911                this.display_map.update(cx, |display_map, cx| {
 6912                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6913                    display_map.fold(creases, cx);
 6914                });
 6915            })
 6916            .ok();
 6917        });
 6918    }
 6919
 6920    fn refresh_selected_text_highlights(
 6921        &mut self,
 6922        on_buffer_edit: bool,
 6923        window: &mut Window,
 6924        cx: &mut Context<Editor>,
 6925    ) {
 6926        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6927        else {
 6928            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6929            self.quick_selection_highlight_task.take();
 6930            self.debounced_selection_highlight_task.take();
 6931            return;
 6932        };
 6933        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6934        if on_buffer_edit
 6935            || self
 6936                .quick_selection_highlight_task
 6937                .as_ref()
 6938                .map_or(true, |(prev_anchor_range, _)| {
 6939                    prev_anchor_range != &query_range
 6940                })
 6941        {
 6942            let multi_buffer_visible_start = self
 6943                .scroll_manager
 6944                .anchor()
 6945                .anchor
 6946                .to_point(&multi_buffer_snapshot);
 6947            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6948                multi_buffer_visible_start
 6949                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6950                Bias::Left,
 6951            );
 6952            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6953            self.quick_selection_highlight_task = Some((
 6954                query_range.clone(),
 6955                self.update_selection_occurrence_highlights(
 6956                    query_text.clone(),
 6957                    query_range.clone(),
 6958                    multi_buffer_visible_range,
 6959                    false,
 6960                    window,
 6961                    cx,
 6962                ),
 6963            ));
 6964        }
 6965        if on_buffer_edit
 6966            || self
 6967                .debounced_selection_highlight_task
 6968                .as_ref()
 6969                .map_or(true, |(prev_anchor_range, _)| {
 6970                    prev_anchor_range != &query_range
 6971                })
 6972        {
 6973            let multi_buffer_start = multi_buffer_snapshot
 6974                .anchor_before(0)
 6975                .to_point(&multi_buffer_snapshot);
 6976            let multi_buffer_end = multi_buffer_snapshot
 6977                .anchor_after(multi_buffer_snapshot.len())
 6978                .to_point(&multi_buffer_snapshot);
 6979            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6980            self.debounced_selection_highlight_task = Some((
 6981                query_range.clone(),
 6982                self.update_selection_occurrence_highlights(
 6983                    query_text,
 6984                    query_range,
 6985                    multi_buffer_full_range,
 6986                    true,
 6987                    window,
 6988                    cx,
 6989                ),
 6990            ));
 6991        }
 6992    }
 6993
 6994    pub fn refresh_edit_prediction(
 6995        &mut self,
 6996        debounce: bool,
 6997        user_requested: bool,
 6998        window: &mut Window,
 6999        cx: &mut Context<Self>,
 7000    ) -> Option<()> {
 7001        if DisableAiSettings::get_global(cx).disable_ai {
 7002            return None;
 7003        }
 7004
 7005        let provider = self.edit_prediction_provider()?;
 7006        let cursor = self.selections.newest_anchor().head();
 7007        let (buffer, cursor_buffer_position) =
 7008            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7009
 7010        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7011            self.discard_edit_prediction(false, cx);
 7012            return None;
 7013        }
 7014
 7015        if !user_requested
 7016            && (!self.should_show_edit_predictions()
 7017                || !self.is_focused(window)
 7018                || buffer.read(cx).is_empty())
 7019        {
 7020            self.discard_edit_prediction(false, cx);
 7021            return None;
 7022        }
 7023
 7024        self.update_visible_edit_prediction(window, cx);
 7025        provider.refresh(
 7026            self.project.clone(),
 7027            buffer,
 7028            cursor_buffer_position,
 7029            debounce,
 7030            cx,
 7031        );
 7032        Some(())
 7033    }
 7034
 7035    fn show_edit_predictions_in_menu(&self) -> bool {
 7036        match self.edit_prediction_settings {
 7037            EditPredictionSettings::Disabled => false,
 7038            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7039        }
 7040    }
 7041
 7042    pub fn edit_predictions_enabled(&self) -> bool {
 7043        match self.edit_prediction_settings {
 7044            EditPredictionSettings::Disabled => false,
 7045            EditPredictionSettings::Enabled { .. } => true,
 7046        }
 7047    }
 7048
 7049    fn edit_prediction_requires_modifier(&self) -> bool {
 7050        match self.edit_prediction_settings {
 7051            EditPredictionSettings::Disabled => false,
 7052            EditPredictionSettings::Enabled {
 7053                preview_requires_modifier,
 7054                ..
 7055            } => preview_requires_modifier,
 7056        }
 7057    }
 7058
 7059    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7060        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7061            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7062            self.discard_edit_prediction(false, cx);
 7063        } else {
 7064            let selection = self.selections.newest_anchor();
 7065            let cursor = selection.head();
 7066
 7067            if let Some((buffer, cursor_buffer_position)) =
 7068                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7069            {
 7070                self.edit_prediction_settings =
 7071                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7072            }
 7073        }
 7074    }
 7075
 7076    fn edit_prediction_settings_at_position(
 7077        &self,
 7078        buffer: &Entity<Buffer>,
 7079        buffer_position: language::Anchor,
 7080        cx: &App,
 7081    ) -> EditPredictionSettings {
 7082        if !self.mode.is_full()
 7083            || !self.show_edit_predictions_override.unwrap_or(true)
 7084            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7085        {
 7086            return EditPredictionSettings::Disabled;
 7087        }
 7088
 7089        let buffer = buffer.read(cx);
 7090
 7091        let file = buffer.file();
 7092
 7093        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7094            return EditPredictionSettings::Disabled;
 7095        };
 7096
 7097        let by_provider = matches!(
 7098            self.menu_edit_predictions_policy,
 7099            MenuEditPredictionsPolicy::ByProvider
 7100        );
 7101
 7102        let show_in_menu = by_provider
 7103            && self
 7104                .edit_prediction_provider
 7105                .as_ref()
 7106                .map_or(false, |provider| {
 7107                    provider.provider.show_completions_in_menu()
 7108                });
 7109
 7110        let preview_requires_modifier =
 7111            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7112
 7113        EditPredictionSettings::Enabled {
 7114            show_in_menu,
 7115            preview_requires_modifier,
 7116        }
 7117    }
 7118
 7119    fn should_show_edit_predictions(&self) -> bool {
 7120        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7121    }
 7122
 7123    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7124        matches!(
 7125            self.edit_prediction_preview,
 7126            EditPredictionPreview::Active { .. }
 7127        )
 7128    }
 7129
 7130    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7131        let cursor = self.selections.newest_anchor().head();
 7132        if let Some((buffer, cursor_position)) =
 7133            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134        {
 7135            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7136        } else {
 7137            false
 7138        }
 7139    }
 7140
 7141    pub fn supports_minimap(&self, cx: &App) -> bool {
 7142        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7143    }
 7144
 7145    fn edit_predictions_enabled_in_buffer(
 7146        &self,
 7147        buffer: &Entity<Buffer>,
 7148        buffer_position: language::Anchor,
 7149        cx: &App,
 7150    ) -> bool {
 7151        maybe!({
 7152            if self.read_only(cx) {
 7153                return Some(false);
 7154            }
 7155            let provider = self.edit_prediction_provider()?;
 7156            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7157                return Some(false);
 7158            }
 7159            let buffer = buffer.read(cx);
 7160            let Some(file) = buffer.file() else {
 7161                return Some(true);
 7162            };
 7163            let settings = all_language_settings(Some(file), cx);
 7164            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7165        })
 7166        .unwrap_or(false)
 7167    }
 7168
 7169    fn cycle_edit_prediction(
 7170        &mut self,
 7171        direction: Direction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) -> Option<()> {
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7180            return None;
 7181        }
 7182
 7183        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7184        self.update_visible_edit_prediction(window, cx);
 7185
 7186        Some(())
 7187    }
 7188
 7189    pub fn show_edit_prediction(
 7190        &mut self,
 7191        _: &ShowEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if !self.has_active_edit_prediction() {
 7196            self.refresh_edit_prediction(false, true, window, cx);
 7197            return;
 7198        }
 7199
 7200        self.update_visible_edit_prediction(window, cx);
 7201    }
 7202
 7203    pub fn display_cursor_names(
 7204        &mut self,
 7205        _: &DisplayCursorNames,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        self.show_cursor_names(window, cx);
 7210    }
 7211
 7212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7213        self.show_cursor_names = true;
 7214        cx.notify();
 7215        cx.spawn_in(window, async move |this, cx| {
 7216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7217            this.update(cx, |this, cx| {
 7218                this.show_cursor_names = false;
 7219                cx.notify()
 7220            })
 7221            .ok()
 7222        })
 7223        .detach();
 7224    }
 7225
 7226    pub fn next_edit_prediction(
 7227        &mut self,
 7228        _: &NextEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if self.has_active_edit_prediction() {
 7233            self.cycle_edit_prediction(Direction::Next, window, cx);
 7234        } else {
 7235            let is_copilot_disabled = self
 7236                .refresh_edit_prediction(false, true, window, cx)
 7237                .is_none();
 7238            if is_copilot_disabled {
 7239                cx.propagate();
 7240            }
 7241        }
 7242    }
 7243
 7244    pub fn previous_edit_prediction(
 7245        &mut self,
 7246        _: &PreviousEditPrediction,
 7247        window: &mut Window,
 7248        cx: &mut Context<Self>,
 7249    ) {
 7250        if self.has_active_edit_prediction() {
 7251            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7252        } else {
 7253            let is_copilot_disabled = self
 7254                .refresh_edit_prediction(false, true, window, cx)
 7255                .is_none();
 7256            if is_copilot_disabled {
 7257                cx.propagate();
 7258            }
 7259        }
 7260    }
 7261
 7262    pub fn accept_edit_prediction(
 7263        &mut self,
 7264        _: &AcceptEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        if self.show_edit_predictions_in_menu() {
 7269            self.hide_context_menu(window, cx);
 7270        }
 7271
 7272        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7273            return;
 7274        };
 7275
 7276        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7277
 7278        match &active_edit_prediction.completion {
 7279            EditPrediction::Move { target, .. } => {
 7280                let target = *target;
 7281
 7282                if let Some(position_map) = &self.last_position_map {
 7283                    if position_map
 7284                        .visible_row_range
 7285                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7286                        || !self.edit_prediction_requires_modifier()
 7287                    {
 7288                        self.unfold_ranges(&[target..target], true, false, cx);
 7289                        // Note that this is also done in vim's handler of the Tab action.
 7290                        self.change_selections(
 7291                            SelectionEffects::scroll(Autoscroll::newest()),
 7292                            window,
 7293                            cx,
 7294                            |selections| {
 7295                                selections.select_anchor_ranges([target..target]);
 7296                            },
 7297                        );
 7298                        self.clear_row_highlights::<EditPredictionPreview>();
 7299
 7300                        self.edit_prediction_preview
 7301                            .set_previous_scroll_position(None);
 7302                    } else {
 7303                        self.edit_prediction_preview
 7304                            .set_previous_scroll_position(Some(
 7305                                position_map.snapshot.scroll_anchor,
 7306                            ));
 7307
 7308                        self.highlight_rows::<EditPredictionPreview>(
 7309                            target..target,
 7310                            cx.theme().colors().editor_highlighted_line_background,
 7311                            RowHighlightOptions {
 7312                                autoscroll: true,
 7313                                ..Default::default()
 7314                            },
 7315                            cx,
 7316                        );
 7317                        self.request_autoscroll(Autoscroll::fit(), cx);
 7318                    }
 7319                }
 7320            }
 7321            EditPrediction::Edit { edits, .. } => {
 7322                if let Some(provider) = self.edit_prediction_provider() {
 7323                    provider.accept(cx);
 7324                }
 7325
 7326                // Store the transaction ID and selections before applying the edit
 7327                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7328
 7329                let snapshot = self.buffer.read(cx).snapshot(cx);
 7330                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7331
 7332                self.buffer.update(cx, |buffer, cx| {
 7333                    buffer.edit(edits.iter().cloned(), None, cx)
 7334                });
 7335
 7336                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7337                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7338                });
 7339
 7340                let selections = self.selections.disjoint_anchors();
 7341                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7342                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7343                    if has_new_transaction {
 7344                        self.selection_history
 7345                            .insert_transaction(transaction_id_now, selections);
 7346                    }
 7347                }
 7348
 7349                self.update_visible_edit_prediction(window, cx);
 7350                if self.active_edit_prediction.is_none() {
 7351                    self.refresh_edit_prediction(true, true, window, cx);
 7352                }
 7353
 7354                cx.notify();
 7355            }
 7356        }
 7357
 7358        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7359    }
 7360
 7361    pub fn accept_partial_edit_prediction(
 7362        &mut self,
 7363        _: &AcceptPartialEditPrediction,
 7364        window: &mut Window,
 7365        cx: &mut Context<Self>,
 7366    ) {
 7367        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7368            return;
 7369        };
 7370        if self.selections.count() != 1 {
 7371            return;
 7372        }
 7373
 7374        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7375
 7376        match &active_edit_prediction.completion {
 7377            EditPrediction::Move { target, .. } => {
 7378                let target = *target;
 7379                self.change_selections(
 7380                    SelectionEffects::scroll(Autoscroll::newest()),
 7381                    window,
 7382                    cx,
 7383                    |selections| {
 7384                        selections.select_anchor_ranges([target..target]);
 7385                    },
 7386                );
 7387            }
 7388            EditPrediction::Edit { edits, .. } => {
 7389                // Find an insertion that starts at the cursor position.
 7390                let snapshot = self.buffer.read(cx).snapshot(cx);
 7391                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7392                let insertion = edits.iter().find_map(|(range, text)| {
 7393                    let range = range.to_offset(&snapshot);
 7394                    if range.is_empty() && range.start == cursor_offset {
 7395                        Some(text)
 7396                    } else {
 7397                        None
 7398                    }
 7399                });
 7400
 7401                if let Some(text) = insertion {
 7402                    let mut partial_completion = text
 7403                        .chars()
 7404                        .by_ref()
 7405                        .take_while(|c| c.is_alphabetic())
 7406                        .collect::<String>();
 7407                    if partial_completion.is_empty() {
 7408                        partial_completion = text
 7409                            .chars()
 7410                            .by_ref()
 7411                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7412                            .collect::<String>();
 7413                    }
 7414
 7415                    cx.emit(EditorEvent::InputHandled {
 7416                        utf16_range_to_replace: None,
 7417                        text: partial_completion.clone().into(),
 7418                    });
 7419
 7420                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7421
 7422                    self.refresh_edit_prediction(true, true, window, cx);
 7423                    cx.notify();
 7424                } else {
 7425                    self.accept_edit_prediction(&Default::default(), window, cx);
 7426                }
 7427            }
 7428        }
 7429    }
 7430
 7431    fn discard_edit_prediction(
 7432        &mut self,
 7433        should_report_edit_prediction_event: bool,
 7434        cx: &mut Context<Self>,
 7435    ) -> bool {
 7436        if should_report_edit_prediction_event {
 7437            let completion_id = self
 7438                .active_edit_prediction
 7439                .as_ref()
 7440                .and_then(|active_completion| active_completion.completion_id.clone());
 7441
 7442            self.report_edit_prediction_event(completion_id, false, cx);
 7443        }
 7444
 7445        if let Some(provider) = self.edit_prediction_provider() {
 7446            provider.discard(cx);
 7447        }
 7448
 7449        self.take_active_edit_prediction(cx)
 7450    }
 7451
 7452    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7453        let Some(provider) = self.edit_prediction_provider() else {
 7454            return;
 7455        };
 7456
 7457        let Some((_, buffer, _)) = self
 7458            .buffer
 7459            .read(cx)
 7460            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7461        else {
 7462            return;
 7463        };
 7464
 7465        let extension = buffer
 7466            .read(cx)
 7467            .file()
 7468            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7469
 7470        let event_type = match accepted {
 7471            true => "Edit Prediction Accepted",
 7472            false => "Edit Prediction Discarded",
 7473        };
 7474        telemetry::event!(
 7475            event_type,
 7476            provider = provider.name(),
 7477            prediction_id = id,
 7478            suggestion_accepted = accepted,
 7479            file_extension = extension,
 7480        );
 7481    }
 7482
 7483    pub fn has_active_edit_prediction(&self) -> bool {
 7484        self.active_edit_prediction.is_some()
 7485    }
 7486
 7487    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7488        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7489            return false;
 7490        };
 7491
 7492        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7493        self.clear_highlights::<EditPredictionHighlight>(cx);
 7494        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7495        true
 7496    }
 7497
 7498    /// Returns true when we're displaying the edit prediction popover below the cursor
 7499    /// like we are not previewing and the LSP autocomplete menu is visible
 7500    /// or we are in `when_holding_modifier` mode.
 7501    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7502        if self.edit_prediction_preview_is_active()
 7503            || !self.show_edit_predictions_in_menu()
 7504            || !self.edit_predictions_enabled()
 7505        {
 7506            return false;
 7507        }
 7508
 7509        if self.has_visible_completions_menu() {
 7510            return true;
 7511        }
 7512
 7513        has_completion && self.edit_prediction_requires_modifier()
 7514    }
 7515
 7516    fn handle_modifiers_changed(
 7517        &mut self,
 7518        modifiers: Modifiers,
 7519        position_map: &PositionMap,
 7520        window: &mut Window,
 7521        cx: &mut Context<Self>,
 7522    ) {
 7523        if self.show_edit_predictions_in_menu() {
 7524            self.update_edit_prediction_preview(&modifiers, window, cx);
 7525        }
 7526
 7527        self.update_selection_mode(&modifiers, position_map, window, cx);
 7528
 7529        let mouse_position = window.mouse_position();
 7530        if !position_map.text_hitbox.is_hovered(window) {
 7531            return;
 7532        }
 7533
 7534        self.update_hovered_link(
 7535            position_map.point_for_position(mouse_position),
 7536            &position_map.snapshot,
 7537            modifiers,
 7538            window,
 7539            cx,
 7540        )
 7541    }
 7542
 7543    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7544        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7545        if invert {
 7546            match multi_cursor_setting {
 7547                MultiCursorModifier::Alt => modifiers.alt,
 7548                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7549            }
 7550        } else {
 7551            match multi_cursor_setting {
 7552                MultiCursorModifier::Alt => modifiers.secondary(),
 7553                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7554            }
 7555        }
 7556    }
 7557
 7558    fn columnar_selection_mode(
 7559        modifiers: &Modifiers,
 7560        cx: &mut Context<Self>,
 7561    ) -> Option<ColumnarMode> {
 7562        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7563            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7564                Some(ColumnarMode::FromMouse)
 7565            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7566                Some(ColumnarMode::FromSelection)
 7567            } else {
 7568                None
 7569            }
 7570        } else {
 7571            None
 7572        }
 7573    }
 7574
 7575    fn update_selection_mode(
 7576        &mut self,
 7577        modifiers: &Modifiers,
 7578        position_map: &PositionMap,
 7579        window: &mut Window,
 7580        cx: &mut Context<Self>,
 7581    ) {
 7582        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7583            return;
 7584        };
 7585        if self.selections.pending.is_none() {
 7586            return;
 7587        }
 7588
 7589        let mouse_position = window.mouse_position();
 7590        let point_for_position = position_map.point_for_position(mouse_position);
 7591        let position = point_for_position.previous_valid;
 7592
 7593        self.select(
 7594            SelectPhase::BeginColumnar {
 7595                position,
 7596                reset: false,
 7597                mode,
 7598                goal_column: point_for_position.exact_unclipped.column(),
 7599            },
 7600            window,
 7601            cx,
 7602        );
 7603    }
 7604
 7605    fn update_edit_prediction_preview(
 7606        &mut self,
 7607        modifiers: &Modifiers,
 7608        window: &mut Window,
 7609        cx: &mut Context<Self>,
 7610    ) {
 7611        let mut modifiers_held = false;
 7612        if let Some(accept_keystroke) = self
 7613            .accept_edit_prediction_keybind(false, window, cx)
 7614            .keystroke()
 7615        {
 7616            modifiers_held = modifiers_held
 7617                || (&accept_keystroke.modifiers == modifiers
 7618                    && accept_keystroke.modifiers.modified());
 7619        };
 7620        if let Some(accept_partial_keystroke) = self
 7621            .accept_edit_prediction_keybind(true, window, cx)
 7622            .keystroke()
 7623        {
 7624            modifiers_held = modifiers_held
 7625                || (&accept_partial_keystroke.modifiers == modifiers
 7626                    && accept_partial_keystroke.modifiers.modified());
 7627        }
 7628
 7629        if modifiers_held {
 7630            if matches!(
 7631                self.edit_prediction_preview,
 7632                EditPredictionPreview::Inactive { .. }
 7633            ) {
 7634                self.edit_prediction_preview = EditPredictionPreview::Active {
 7635                    previous_scroll_position: None,
 7636                    since: Instant::now(),
 7637                };
 7638
 7639                self.update_visible_edit_prediction(window, cx);
 7640                cx.notify();
 7641            }
 7642        } else if let EditPredictionPreview::Active {
 7643            previous_scroll_position,
 7644            since,
 7645        } = self.edit_prediction_preview
 7646        {
 7647            if let (Some(previous_scroll_position), Some(position_map)) =
 7648                (previous_scroll_position, self.last_position_map.as_ref())
 7649            {
 7650                self.set_scroll_position(
 7651                    previous_scroll_position
 7652                        .scroll_position(&position_map.snapshot.display_snapshot),
 7653                    window,
 7654                    cx,
 7655                );
 7656            }
 7657
 7658            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7659                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7660            };
 7661            self.clear_row_highlights::<EditPredictionPreview>();
 7662            self.update_visible_edit_prediction(window, cx);
 7663            cx.notify();
 7664        }
 7665    }
 7666
 7667    fn update_visible_edit_prediction(
 7668        &mut self,
 7669        _window: &mut Window,
 7670        cx: &mut Context<Self>,
 7671    ) -> Option<()> {
 7672        if DisableAiSettings::get_global(cx).disable_ai {
 7673            return None;
 7674        }
 7675
 7676        let selection = self.selections.newest_anchor();
 7677        let cursor = selection.head();
 7678        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7679        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7680        let excerpt_id = cursor.excerpt_id;
 7681
 7682        let show_in_menu = self.show_edit_predictions_in_menu();
 7683        let completions_menu_has_precedence = !show_in_menu
 7684            && (self.context_menu.borrow().is_some()
 7685                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7686
 7687        if completions_menu_has_precedence
 7688            || !offset_selection.is_empty()
 7689            || self
 7690                .active_edit_prediction
 7691                .as_ref()
 7692                .map_or(false, |completion| {
 7693                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7694                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7695                    !invalidation_range.contains(&offset_selection.head())
 7696                })
 7697        {
 7698            self.discard_edit_prediction(false, cx);
 7699            return None;
 7700        }
 7701
 7702        self.take_active_edit_prediction(cx);
 7703        let Some(provider) = self.edit_prediction_provider() else {
 7704            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7705            return None;
 7706        };
 7707
 7708        let (buffer, cursor_buffer_position) =
 7709            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7710
 7711        self.edit_prediction_settings =
 7712            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7713
 7714        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7715
 7716        if self.edit_prediction_indent_conflict {
 7717            let cursor_point = cursor.to_point(&multibuffer);
 7718
 7719            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7720
 7721            if let Some((_, indent)) = indents.iter().next() {
 7722                if indent.len == cursor_point.column {
 7723                    self.edit_prediction_indent_conflict = false;
 7724                }
 7725            }
 7726        }
 7727
 7728        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7729        let edits = edit_prediction
 7730            .edits
 7731            .into_iter()
 7732            .flat_map(|(range, new_text)| {
 7733                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7734                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7735                Some((start..end, new_text))
 7736            })
 7737            .collect::<Vec<_>>();
 7738        if edits.is_empty() {
 7739            return None;
 7740        }
 7741
 7742        let first_edit_start = edits.first().unwrap().0.start;
 7743        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7744        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7745
 7746        let last_edit_end = edits.last().unwrap().0.end;
 7747        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7748        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7749
 7750        let cursor_row = cursor.to_point(&multibuffer).row;
 7751
 7752        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7753
 7754        let mut inlay_ids = Vec::new();
 7755        let invalidation_row_range;
 7756        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7757            Some(cursor_row..edit_end_row)
 7758        } else if cursor_row > edit_end_row {
 7759            Some(edit_start_row..cursor_row)
 7760        } else {
 7761            None
 7762        };
 7763        let is_move =
 7764            move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode;
 7765        let completion = if is_move {
 7766            invalidation_row_range =
 7767                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7768            let target = first_edit_start;
 7769            EditPrediction::Move { target, snapshot }
 7770        } else {
 7771            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7772                && !self.edit_predictions_hidden_for_vim_mode;
 7773
 7774            if show_completions_in_buffer {
 7775                if edits
 7776                    .iter()
 7777                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7778                {
 7779                    let mut inlays = Vec::new();
 7780                    for (range, new_text) in &edits {
 7781                        let inlay = Inlay::edit_prediction(
 7782                            post_inc(&mut self.next_inlay_id),
 7783                            range.start,
 7784                            new_text.as_str(),
 7785                        );
 7786                        inlay_ids.push(inlay.id);
 7787                        inlays.push(inlay);
 7788                    }
 7789
 7790                    self.splice_inlays(&[], inlays, cx);
 7791                } else {
 7792                    let background_color = cx.theme().status().deleted_background;
 7793                    self.highlight_text::<EditPredictionHighlight>(
 7794                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7795                        HighlightStyle {
 7796                            background_color: Some(background_color),
 7797                            ..Default::default()
 7798                        },
 7799                        cx,
 7800                    );
 7801                }
 7802            }
 7803
 7804            invalidation_row_range = edit_start_row..edit_end_row;
 7805
 7806            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7807                if provider.show_tab_accept_marker() {
 7808                    EditDisplayMode::TabAccept
 7809                } else {
 7810                    EditDisplayMode::Inline
 7811                }
 7812            } else {
 7813                EditDisplayMode::DiffPopover
 7814            };
 7815
 7816            EditPrediction::Edit {
 7817                edits,
 7818                edit_preview: edit_prediction.edit_preview,
 7819                display_mode,
 7820                snapshot,
 7821            }
 7822        };
 7823
 7824        let invalidation_range = multibuffer
 7825            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7826            ..multibuffer.anchor_after(Point::new(
 7827                invalidation_row_range.end,
 7828                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7829            ));
 7830
 7831        self.stale_edit_prediction_in_menu = None;
 7832        self.active_edit_prediction = Some(EditPredictionState {
 7833            inlay_ids,
 7834            completion,
 7835            completion_id: edit_prediction.id,
 7836            invalidation_range,
 7837        });
 7838
 7839        cx.notify();
 7840
 7841        Some(())
 7842    }
 7843
 7844    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7845        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7846    }
 7847
 7848    fn clear_tasks(&mut self) {
 7849        self.tasks.clear()
 7850    }
 7851
 7852    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7853        if self.tasks.insert(key, value).is_some() {
 7854            // This case should hopefully be rare, but just in case...
 7855            log::error!(
 7856                "multiple different run targets found on a single line, only the last target will be rendered"
 7857            )
 7858        }
 7859    }
 7860
 7861    /// Get all display points of breakpoints that will be rendered within editor
 7862    ///
 7863    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7864    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7865    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7866    fn active_breakpoints(
 7867        &self,
 7868        range: Range<DisplayRow>,
 7869        window: &mut Window,
 7870        cx: &mut Context<Self>,
 7871    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7872        let mut breakpoint_display_points = HashMap::default();
 7873
 7874        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7875            return breakpoint_display_points;
 7876        };
 7877
 7878        let snapshot = self.snapshot(window, cx);
 7879
 7880        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7881        let Some(project) = self.project.as_ref() else {
 7882            return breakpoint_display_points;
 7883        };
 7884
 7885        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7886            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7887
 7888        for (buffer_snapshot, range, excerpt_id) in
 7889            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7890        {
 7891            let Some(buffer) = project
 7892                .read(cx)
 7893                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7894            else {
 7895                continue;
 7896            };
 7897            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7898                &buffer,
 7899                Some(
 7900                    buffer_snapshot.anchor_before(range.start)
 7901                        ..buffer_snapshot.anchor_after(range.end),
 7902                ),
 7903                buffer_snapshot,
 7904                cx,
 7905            );
 7906            for (breakpoint, state) in breakpoints {
 7907                let multi_buffer_anchor =
 7908                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7909                let position = multi_buffer_anchor
 7910                    .to_point(&multi_buffer_snapshot)
 7911                    .to_display_point(&snapshot);
 7912
 7913                breakpoint_display_points.insert(
 7914                    position.row(),
 7915                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7916                );
 7917            }
 7918        }
 7919
 7920        breakpoint_display_points
 7921    }
 7922
 7923    fn breakpoint_context_menu(
 7924        &self,
 7925        anchor: Anchor,
 7926        window: &mut Window,
 7927        cx: &mut Context<Self>,
 7928    ) -> Entity<ui::ContextMenu> {
 7929        let weak_editor = cx.weak_entity();
 7930        let focus_handle = self.focus_handle(cx);
 7931
 7932        let row = self
 7933            .buffer
 7934            .read(cx)
 7935            .snapshot(cx)
 7936            .summary_for_anchor::<Point>(&anchor)
 7937            .row;
 7938
 7939        let breakpoint = self
 7940            .breakpoint_at_row(row, window, cx)
 7941            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7942
 7943        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7944            "Edit Log Breakpoint"
 7945        } else {
 7946            "Set Log Breakpoint"
 7947        };
 7948
 7949        let condition_breakpoint_msg = if breakpoint
 7950            .as_ref()
 7951            .is_some_and(|bp| bp.1.condition.is_some())
 7952        {
 7953            "Edit Condition Breakpoint"
 7954        } else {
 7955            "Set Condition Breakpoint"
 7956        };
 7957
 7958        let hit_condition_breakpoint_msg = if breakpoint
 7959            .as_ref()
 7960            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7961        {
 7962            "Edit Hit Condition Breakpoint"
 7963        } else {
 7964            "Set Hit Condition Breakpoint"
 7965        };
 7966
 7967        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7968            "Unset Breakpoint"
 7969        } else {
 7970            "Set Breakpoint"
 7971        };
 7972
 7973        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7974
 7975        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7976            BreakpointState::Enabled => Some("Disable"),
 7977            BreakpointState::Disabled => Some("Enable"),
 7978        });
 7979
 7980        let (anchor, breakpoint) =
 7981            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7982
 7983        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7984            menu.on_blur_subscription(Subscription::new(|| {}))
 7985                .context(focus_handle)
 7986                .when(run_to_cursor, |this| {
 7987                    let weak_editor = weak_editor.clone();
 7988                    this.entry("Run to cursor", None, move |window, cx| {
 7989                        weak_editor
 7990                            .update(cx, |editor, cx| {
 7991                                editor.change_selections(
 7992                                    SelectionEffects::no_scroll(),
 7993                                    window,
 7994                                    cx,
 7995                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7996                                );
 7997                            })
 7998                            .ok();
 7999
 8000                        window.dispatch_action(Box::new(RunToCursor), cx);
 8001                    })
 8002                    .separator()
 8003                })
 8004                .when_some(toggle_state_msg, |this, msg| {
 8005                    this.entry(msg, None, {
 8006                        let weak_editor = weak_editor.clone();
 8007                        let breakpoint = breakpoint.clone();
 8008                        move |_window, cx| {
 8009                            weak_editor
 8010                                .update(cx, |this, cx| {
 8011                                    this.edit_breakpoint_at_anchor(
 8012                                        anchor,
 8013                                        breakpoint.as_ref().clone(),
 8014                                        BreakpointEditAction::InvertState,
 8015                                        cx,
 8016                                    );
 8017                                })
 8018                                .log_err();
 8019                        }
 8020                    })
 8021                })
 8022                .entry(set_breakpoint_msg, None, {
 8023                    let weak_editor = weak_editor.clone();
 8024                    let breakpoint = breakpoint.clone();
 8025                    move |_window, cx| {
 8026                        weak_editor
 8027                            .update(cx, |this, cx| {
 8028                                this.edit_breakpoint_at_anchor(
 8029                                    anchor,
 8030                                    breakpoint.as_ref().clone(),
 8031                                    BreakpointEditAction::Toggle,
 8032                                    cx,
 8033                                );
 8034                            })
 8035                            .log_err();
 8036                    }
 8037                })
 8038                .entry(log_breakpoint_msg, None, {
 8039                    let breakpoint = breakpoint.clone();
 8040                    let weak_editor = weak_editor.clone();
 8041                    move |window, cx| {
 8042                        weak_editor
 8043                            .update(cx, |this, cx| {
 8044                                this.add_edit_breakpoint_block(
 8045                                    anchor,
 8046                                    breakpoint.as_ref(),
 8047                                    BreakpointPromptEditAction::Log,
 8048                                    window,
 8049                                    cx,
 8050                                );
 8051                            })
 8052                            .log_err();
 8053                    }
 8054                })
 8055                .entry(condition_breakpoint_msg, None, {
 8056                    let breakpoint = breakpoint.clone();
 8057                    let weak_editor = weak_editor.clone();
 8058                    move |window, cx| {
 8059                        weak_editor
 8060                            .update(cx, |this, cx| {
 8061                                this.add_edit_breakpoint_block(
 8062                                    anchor,
 8063                                    breakpoint.as_ref(),
 8064                                    BreakpointPromptEditAction::Condition,
 8065                                    window,
 8066                                    cx,
 8067                                );
 8068                            })
 8069                            .log_err();
 8070                    }
 8071                })
 8072                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8073                    weak_editor
 8074                        .update(cx, |this, cx| {
 8075                            this.add_edit_breakpoint_block(
 8076                                anchor,
 8077                                breakpoint.as_ref(),
 8078                                BreakpointPromptEditAction::HitCondition,
 8079                                window,
 8080                                cx,
 8081                            );
 8082                        })
 8083                        .log_err();
 8084                })
 8085        })
 8086    }
 8087
 8088    fn render_breakpoint(
 8089        &self,
 8090        position: Anchor,
 8091        row: DisplayRow,
 8092        breakpoint: &Breakpoint,
 8093        state: Option<BreakpointSessionState>,
 8094        cx: &mut Context<Self>,
 8095    ) -> IconButton {
 8096        let is_rejected = state.is_some_and(|s| !s.verified);
 8097        // Is it a breakpoint that shows up when hovering over gutter?
 8098        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8099            (false, false),
 8100            |PhantomBreakpointIndicator {
 8101                 is_active,
 8102                 display_row,
 8103                 collides_with_existing_breakpoint,
 8104             }| {
 8105                (
 8106                    is_active && display_row == row,
 8107                    collides_with_existing_breakpoint,
 8108                )
 8109            },
 8110        );
 8111
 8112        let (color, icon) = {
 8113            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8114                (false, false) => ui::IconName::DebugBreakpoint,
 8115                (true, false) => ui::IconName::DebugLogBreakpoint,
 8116                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8117                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8118            };
 8119
 8120            let color = if is_phantom {
 8121                Color::Hint
 8122            } else if is_rejected {
 8123                Color::Disabled
 8124            } else {
 8125                Color::Debugger
 8126            };
 8127
 8128            (color, icon)
 8129        };
 8130
 8131        let breakpoint = Arc::from(breakpoint.clone());
 8132
 8133        let alt_as_text = gpui::Keystroke {
 8134            modifiers: Modifiers::secondary_key(),
 8135            ..Default::default()
 8136        };
 8137        let primary_action_text = if breakpoint.is_disabled() {
 8138            "Enable breakpoint"
 8139        } else if is_phantom && !collides_with_existing {
 8140            "Set breakpoint"
 8141        } else {
 8142            "Unset breakpoint"
 8143        };
 8144        let focus_handle = self.focus_handle.clone();
 8145
 8146        let meta = if is_rejected {
 8147            SharedString::from("No executable code is associated with this line.")
 8148        } else if collides_with_existing && !breakpoint.is_disabled() {
 8149            SharedString::from(format!(
 8150                "{alt_as_text}-click to disable,\nright-click for more options."
 8151            ))
 8152        } else {
 8153            SharedString::from("Right-click for more options.")
 8154        };
 8155        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8156            .icon_size(IconSize::XSmall)
 8157            .size(ui::ButtonSize::None)
 8158            .when(is_rejected, |this| {
 8159                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8160            })
 8161            .icon_color(color)
 8162            .style(ButtonStyle::Transparent)
 8163            .on_click(cx.listener({
 8164                let breakpoint = breakpoint.clone();
 8165
 8166                move |editor, event: &ClickEvent, window, cx| {
 8167                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8168                        BreakpointEditAction::InvertState
 8169                    } else {
 8170                        BreakpointEditAction::Toggle
 8171                    };
 8172
 8173                    window.focus(&editor.focus_handle(cx));
 8174                    editor.edit_breakpoint_at_anchor(
 8175                        position,
 8176                        breakpoint.as_ref().clone(),
 8177                        edit_action,
 8178                        cx,
 8179                    );
 8180                }
 8181            }))
 8182            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8183                editor.set_breakpoint_context_menu(
 8184                    row,
 8185                    Some(position),
 8186                    event.position(),
 8187                    window,
 8188                    cx,
 8189                );
 8190            }))
 8191            .tooltip(move |window, cx| {
 8192                Tooltip::with_meta_in(
 8193                    primary_action_text,
 8194                    Some(&ToggleBreakpoint),
 8195                    meta.clone(),
 8196                    &focus_handle,
 8197                    window,
 8198                    cx,
 8199                )
 8200            })
 8201    }
 8202
 8203    fn build_tasks_context(
 8204        project: &Entity<Project>,
 8205        buffer: &Entity<Buffer>,
 8206        buffer_row: u32,
 8207        tasks: &Arc<RunnableTasks>,
 8208        cx: &mut Context<Self>,
 8209    ) -> Task<Option<task::TaskContext>> {
 8210        let position = Point::new(buffer_row, tasks.column);
 8211        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8212        let location = Location {
 8213            buffer: buffer.clone(),
 8214            range: range_start..range_start,
 8215        };
 8216        // Fill in the environmental variables from the tree-sitter captures
 8217        let mut captured_task_variables = TaskVariables::default();
 8218        for (capture_name, value) in tasks.extra_variables.clone() {
 8219            captured_task_variables.insert(
 8220                task::VariableName::Custom(capture_name.into()),
 8221                value.clone(),
 8222            );
 8223        }
 8224        project.update(cx, |project, cx| {
 8225            project.task_store().update(cx, |task_store, cx| {
 8226                task_store.task_context_for_location(captured_task_variables, location, cx)
 8227            })
 8228        })
 8229    }
 8230
 8231    pub fn spawn_nearest_task(
 8232        &mut self,
 8233        action: &SpawnNearestTask,
 8234        window: &mut Window,
 8235        cx: &mut Context<Self>,
 8236    ) {
 8237        let Some((workspace, _)) = self.workspace.clone() else {
 8238            return;
 8239        };
 8240        let Some(project) = self.project.clone() else {
 8241            return;
 8242        };
 8243
 8244        // Try to find a closest, enclosing node using tree-sitter that has a task
 8245        let Some((buffer, buffer_row, tasks)) = self
 8246            .find_enclosing_node_task(cx)
 8247            // Or find the task that's closest in row-distance.
 8248            .or_else(|| self.find_closest_task(cx))
 8249        else {
 8250            return;
 8251        };
 8252
 8253        let reveal_strategy = action.reveal;
 8254        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8255        cx.spawn_in(window, async move |_, cx| {
 8256            let context = task_context.await?;
 8257            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8258
 8259            let resolved = &mut resolved_task.resolved;
 8260            resolved.reveal = reveal_strategy;
 8261
 8262            workspace
 8263                .update_in(cx, |workspace, window, cx| {
 8264                    workspace.schedule_resolved_task(
 8265                        task_source_kind,
 8266                        resolved_task,
 8267                        false,
 8268                        window,
 8269                        cx,
 8270                    );
 8271                })
 8272                .ok()
 8273        })
 8274        .detach();
 8275    }
 8276
 8277    fn find_closest_task(
 8278        &mut self,
 8279        cx: &mut Context<Self>,
 8280    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8281        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8282
 8283        let ((buffer_id, row), tasks) = self
 8284            .tasks
 8285            .iter()
 8286            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8287
 8288        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8289        let tasks = Arc::new(tasks.to_owned());
 8290        Some((buffer, *row, tasks))
 8291    }
 8292
 8293    fn find_enclosing_node_task(
 8294        &mut self,
 8295        cx: &mut Context<Self>,
 8296    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8297        let snapshot = self.buffer.read(cx).snapshot(cx);
 8298        let offset = self.selections.newest::<usize>(cx).head();
 8299        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8300        let buffer_id = excerpt.buffer().remote_id();
 8301
 8302        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8303        let mut cursor = layer.node().walk();
 8304
 8305        while cursor.goto_first_child_for_byte(offset).is_some() {
 8306            if cursor.node().end_byte() == offset {
 8307                cursor.goto_next_sibling();
 8308            }
 8309        }
 8310
 8311        // Ascend to the smallest ancestor that contains the range and has a task.
 8312        loop {
 8313            let node = cursor.node();
 8314            let node_range = node.byte_range();
 8315            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8316
 8317            // Check if this node contains our offset
 8318            if node_range.start <= offset && node_range.end >= offset {
 8319                // If it contains offset, check for task
 8320                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8321                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8322                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8323                }
 8324            }
 8325
 8326            if !cursor.goto_parent() {
 8327                break;
 8328            }
 8329        }
 8330        None
 8331    }
 8332
 8333    fn render_run_indicator(
 8334        &self,
 8335        _style: &EditorStyle,
 8336        is_active: bool,
 8337        row: DisplayRow,
 8338        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8339        cx: &mut Context<Self>,
 8340    ) -> IconButton {
 8341        let color = Color::Muted;
 8342        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8343
 8344        IconButton::new(
 8345            ("run_indicator", row.0 as usize),
 8346            ui::IconName::PlayOutlined,
 8347        )
 8348        .shape(ui::IconButtonShape::Square)
 8349        .icon_size(IconSize::XSmall)
 8350        .icon_color(color)
 8351        .toggle_state(is_active)
 8352        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8353            let quick_launch = match e {
 8354                ClickEvent::Keyboard(_) => true,
 8355                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8356            };
 8357
 8358            window.focus(&editor.focus_handle(cx));
 8359            editor.toggle_code_actions(
 8360                &ToggleCodeActions {
 8361                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8362                    quick_launch,
 8363                },
 8364                window,
 8365                cx,
 8366            );
 8367        }))
 8368        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8369            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8370        }))
 8371    }
 8372
 8373    pub fn context_menu_visible(&self) -> bool {
 8374        !self.edit_prediction_preview_is_active()
 8375            && self
 8376                .context_menu
 8377                .borrow()
 8378                .as_ref()
 8379                .map_or(false, |menu| menu.visible())
 8380    }
 8381
 8382    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8383        self.context_menu
 8384            .borrow()
 8385            .as_ref()
 8386            .map(|menu| menu.origin())
 8387    }
 8388
 8389    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8390        self.context_menu_options = Some(options);
 8391    }
 8392
 8393    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8394    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8395
 8396    fn render_edit_prediction_popover(
 8397        &mut self,
 8398        text_bounds: &Bounds<Pixels>,
 8399        content_origin: gpui::Point<Pixels>,
 8400        right_margin: Pixels,
 8401        editor_snapshot: &EditorSnapshot,
 8402        visible_row_range: Range<DisplayRow>,
 8403        scroll_top: f32,
 8404        scroll_bottom: f32,
 8405        line_layouts: &[LineWithInvisibles],
 8406        line_height: Pixels,
 8407        scroll_pixel_position: gpui::Point<Pixels>,
 8408        newest_selection_head: Option<DisplayPoint>,
 8409        editor_width: Pixels,
 8410        style: &EditorStyle,
 8411        window: &mut Window,
 8412        cx: &mut App,
 8413    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8414        if self.mode().is_minimap() {
 8415            return None;
 8416        }
 8417        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8418
 8419        if self.edit_prediction_visible_in_cursor_popover(true) {
 8420            return None;
 8421        }
 8422
 8423        match &active_edit_prediction.completion {
 8424            EditPrediction::Move { target, .. } => {
 8425                let target_display_point = target.to_display_point(editor_snapshot);
 8426
 8427                if self.edit_prediction_requires_modifier() {
 8428                    if !self.edit_prediction_preview_is_active() {
 8429                        return None;
 8430                    }
 8431
 8432                    self.render_edit_prediction_modifier_jump_popover(
 8433                        text_bounds,
 8434                        content_origin,
 8435                        visible_row_range,
 8436                        line_layouts,
 8437                        line_height,
 8438                        scroll_pixel_position,
 8439                        newest_selection_head,
 8440                        target_display_point,
 8441                        window,
 8442                        cx,
 8443                    )
 8444                } else {
 8445                    self.render_edit_prediction_eager_jump_popover(
 8446                        text_bounds,
 8447                        content_origin,
 8448                        editor_snapshot,
 8449                        visible_row_range,
 8450                        scroll_top,
 8451                        scroll_bottom,
 8452                        line_height,
 8453                        scroll_pixel_position,
 8454                        target_display_point,
 8455                        editor_width,
 8456                        window,
 8457                        cx,
 8458                    )
 8459                }
 8460            }
 8461            EditPrediction::Edit {
 8462                display_mode: EditDisplayMode::Inline,
 8463                ..
 8464            } => None,
 8465            EditPrediction::Edit {
 8466                display_mode: EditDisplayMode::TabAccept,
 8467                edits,
 8468                ..
 8469            } => {
 8470                let range = &edits.first()?.0;
 8471                let target_display_point = range.end.to_display_point(editor_snapshot);
 8472
 8473                self.render_edit_prediction_end_of_line_popover(
 8474                    "Accept",
 8475                    editor_snapshot,
 8476                    visible_row_range,
 8477                    target_display_point,
 8478                    line_height,
 8479                    scroll_pixel_position,
 8480                    content_origin,
 8481                    editor_width,
 8482                    window,
 8483                    cx,
 8484                )
 8485            }
 8486            EditPrediction::Edit {
 8487                edits,
 8488                edit_preview,
 8489                display_mode: EditDisplayMode::DiffPopover,
 8490                snapshot,
 8491            } => self.render_edit_prediction_diff_popover(
 8492                text_bounds,
 8493                content_origin,
 8494                right_margin,
 8495                editor_snapshot,
 8496                visible_row_range,
 8497                line_layouts,
 8498                line_height,
 8499                scroll_pixel_position,
 8500                newest_selection_head,
 8501                editor_width,
 8502                style,
 8503                edits,
 8504                edit_preview,
 8505                snapshot,
 8506                window,
 8507                cx,
 8508            ),
 8509        }
 8510    }
 8511
 8512    fn render_edit_prediction_modifier_jump_popover(
 8513        &mut self,
 8514        text_bounds: &Bounds<Pixels>,
 8515        content_origin: gpui::Point<Pixels>,
 8516        visible_row_range: Range<DisplayRow>,
 8517        line_layouts: &[LineWithInvisibles],
 8518        line_height: Pixels,
 8519        scroll_pixel_position: gpui::Point<Pixels>,
 8520        newest_selection_head: Option<DisplayPoint>,
 8521        target_display_point: DisplayPoint,
 8522        window: &mut Window,
 8523        cx: &mut App,
 8524    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8525        let scrolled_content_origin =
 8526            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8527
 8528        const SCROLL_PADDING_Y: Pixels = px(12.);
 8529
 8530        if target_display_point.row() < visible_row_range.start {
 8531            return self.render_edit_prediction_scroll_popover(
 8532                |_| SCROLL_PADDING_Y,
 8533                IconName::ArrowUp,
 8534                visible_row_range,
 8535                line_layouts,
 8536                newest_selection_head,
 8537                scrolled_content_origin,
 8538                window,
 8539                cx,
 8540            );
 8541        } else if target_display_point.row() >= visible_row_range.end {
 8542            return self.render_edit_prediction_scroll_popover(
 8543                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8544                IconName::ArrowDown,
 8545                visible_row_range,
 8546                line_layouts,
 8547                newest_selection_head,
 8548                scrolled_content_origin,
 8549                window,
 8550                cx,
 8551            );
 8552        }
 8553
 8554        const POLE_WIDTH: Pixels = px(2.);
 8555
 8556        let line_layout =
 8557            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8558        let target_column = target_display_point.column() as usize;
 8559
 8560        let target_x = line_layout.x_for_index(target_column);
 8561        let target_y =
 8562            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8563
 8564        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8565
 8566        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8567        border_color.l += 0.001;
 8568
 8569        let mut element = v_flex()
 8570            .items_end()
 8571            .when(flag_on_right, |el| el.items_start())
 8572            .child(if flag_on_right {
 8573                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8574                    .rounded_bl(px(0.))
 8575                    .rounded_tl(px(0.))
 8576                    .border_l_2()
 8577                    .border_color(border_color)
 8578            } else {
 8579                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8580                    .rounded_br(px(0.))
 8581                    .rounded_tr(px(0.))
 8582                    .border_r_2()
 8583                    .border_color(border_color)
 8584            })
 8585            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8586            .into_any();
 8587
 8588        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8589
 8590        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8591            - point(
 8592                if flag_on_right {
 8593                    POLE_WIDTH
 8594                } else {
 8595                    size.width - POLE_WIDTH
 8596                },
 8597                size.height - line_height,
 8598            );
 8599
 8600        origin.x = origin.x.max(content_origin.x);
 8601
 8602        element.prepaint_at(origin, window, cx);
 8603
 8604        Some((element, origin))
 8605    }
 8606
 8607    fn render_edit_prediction_scroll_popover(
 8608        &mut self,
 8609        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8610        scroll_icon: IconName,
 8611        visible_row_range: Range<DisplayRow>,
 8612        line_layouts: &[LineWithInvisibles],
 8613        newest_selection_head: Option<DisplayPoint>,
 8614        scrolled_content_origin: gpui::Point<Pixels>,
 8615        window: &mut Window,
 8616        cx: &mut App,
 8617    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8618        let mut element = self
 8619            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8620            .into_any();
 8621
 8622        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8623
 8624        let cursor = newest_selection_head?;
 8625        let cursor_row_layout =
 8626            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8627        let cursor_column = cursor.column() as usize;
 8628
 8629        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8630
 8631        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8632
 8633        element.prepaint_at(origin, window, cx);
 8634        Some((element, origin))
 8635    }
 8636
 8637    fn render_edit_prediction_eager_jump_popover(
 8638        &mut self,
 8639        text_bounds: &Bounds<Pixels>,
 8640        content_origin: gpui::Point<Pixels>,
 8641        editor_snapshot: &EditorSnapshot,
 8642        visible_row_range: Range<DisplayRow>,
 8643        scroll_top: f32,
 8644        scroll_bottom: f32,
 8645        line_height: Pixels,
 8646        scroll_pixel_position: gpui::Point<Pixels>,
 8647        target_display_point: DisplayPoint,
 8648        editor_width: Pixels,
 8649        window: &mut Window,
 8650        cx: &mut App,
 8651    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8652        if target_display_point.row().as_f32() < scroll_top {
 8653            let mut element = self
 8654                .render_edit_prediction_line_popover(
 8655                    "Jump to Edit",
 8656                    Some(IconName::ArrowUp),
 8657                    window,
 8658                    cx,
 8659                )?
 8660                .into_any();
 8661
 8662            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8663            let offset = point(
 8664                (text_bounds.size.width - size.width) / 2.,
 8665                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8666            );
 8667
 8668            let origin = text_bounds.origin + offset;
 8669            element.prepaint_at(origin, window, cx);
 8670            Some((element, origin))
 8671        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8672            let mut element = self
 8673                .render_edit_prediction_line_popover(
 8674                    "Jump to Edit",
 8675                    Some(IconName::ArrowDown),
 8676                    window,
 8677                    cx,
 8678                )?
 8679                .into_any();
 8680
 8681            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8682            let offset = point(
 8683                (text_bounds.size.width - size.width) / 2.,
 8684                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8685            );
 8686
 8687            let origin = text_bounds.origin + offset;
 8688            element.prepaint_at(origin, window, cx);
 8689            Some((element, origin))
 8690        } else {
 8691            self.render_edit_prediction_end_of_line_popover(
 8692                "Jump to Edit",
 8693                editor_snapshot,
 8694                visible_row_range,
 8695                target_display_point,
 8696                line_height,
 8697                scroll_pixel_position,
 8698                content_origin,
 8699                editor_width,
 8700                window,
 8701                cx,
 8702            )
 8703        }
 8704    }
 8705
 8706    fn render_edit_prediction_end_of_line_popover(
 8707        self: &mut Editor,
 8708        label: &'static str,
 8709        editor_snapshot: &EditorSnapshot,
 8710        visible_row_range: Range<DisplayRow>,
 8711        target_display_point: DisplayPoint,
 8712        line_height: Pixels,
 8713        scroll_pixel_position: gpui::Point<Pixels>,
 8714        content_origin: gpui::Point<Pixels>,
 8715        editor_width: Pixels,
 8716        window: &mut Window,
 8717        cx: &mut App,
 8718    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8719        let target_line_end = DisplayPoint::new(
 8720            target_display_point.row(),
 8721            editor_snapshot.line_len(target_display_point.row()),
 8722        );
 8723
 8724        let mut element = self
 8725            .render_edit_prediction_line_popover(label, None, window, cx)?
 8726            .into_any();
 8727
 8728        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8729
 8730        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8731
 8732        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8733        let mut origin = start_point
 8734            + line_origin
 8735            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8736        origin.x = origin.x.max(content_origin.x);
 8737
 8738        let max_x = content_origin.x + editor_width - size.width;
 8739
 8740        if origin.x > max_x {
 8741            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8742
 8743            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8744                origin.y += offset;
 8745                IconName::ArrowUp
 8746            } else {
 8747                origin.y -= offset;
 8748                IconName::ArrowDown
 8749            };
 8750
 8751            element = self
 8752                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8753                .into_any();
 8754
 8755            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8756
 8757            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8758        }
 8759
 8760        element.prepaint_at(origin, window, cx);
 8761        Some((element, origin))
 8762    }
 8763
 8764    fn render_edit_prediction_diff_popover(
 8765        self: &Editor,
 8766        text_bounds: &Bounds<Pixels>,
 8767        content_origin: gpui::Point<Pixels>,
 8768        right_margin: Pixels,
 8769        editor_snapshot: &EditorSnapshot,
 8770        visible_row_range: Range<DisplayRow>,
 8771        line_layouts: &[LineWithInvisibles],
 8772        line_height: Pixels,
 8773        scroll_pixel_position: gpui::Point<Pixels>,
 8774        newest_selection_head: Option<DisplayPoint>,
 8775        editor_width: Pixels,
 8776        style: &EditorStyle,
 8777        edits: &Vec<(Range<Anchor>, String)>,
 8778        edit_preview: &Option<language::EditPreview>,
 8779        snapshot: &language::BufferSnapshot,
 8780        window: &mut Window,
 8781        cx: &mut App,
 8782    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8783        let edit_start = edits
 8784            .first()
 8785            .unwrap()
 8786            .0
 8787            .start
 8788            .to_display_point(editor_snapshot);
 8789        let edit_end = edits
 8790            .last()
 8791            .unwrap()
 8792            .0
 8793            .end
 8794            .to_display_point(editor_snapshot);
 8795
 8796        let is_visible = visible_row_range.contains(&edit_start.row())
 8797            || visible_row_range.contains(&edit_end.row());
 8798        if !is_visible {
 8799            return None;
 8800        }
 8801
 8802        let highlighted_edits =
 8803            crate::edit_prediction_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8804
 8805        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8806        let line_count = highlighted_edits.text.lines().count();
 8807
 8808        const BORDER_WIDTH: Pixels = px(1.);
 8809
 8810        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8811        let has_keybind = keybind.is_some();
 8812
 8813        let mut element = h_flex()
 8814            .items_start()
 8815            .child(
 8816                h_flex()
 8817                    .bg(cx.theme().colors().editor_background)
 8818                    .border(BORDER_WIDTH)
 8819                    .shadow_xs()
 8820                    .border_color(cx.theme().colors().border)
 8821                    .rounded_l_lg()
 8822                    .when(line_count > 1, |el| el.rounded_br_lg())
 8823                    .pr_1()
 8824                    .child(styled_text),
 8825            )
 8826            .child(
 8827                h_flex()
 8828                    .h(line_height + BORDER_WIDTH * 2.)
 8829                    .px_1p5()
 8830                    .gap_1()
 8831                    // Workaround: For some reason, there's a gap if we don't do this
 8832                    .ml(-BORDER_WIDTH)
 8833                    .shadow(vec![gpui::BoxShadow {
 8834                        color: gpui::black().opacity(0.05),
 8835                        offset: point(px(1.), px(1.)),
 8836                        blur_radius: px(2.),
 8837                        spread_radius: px(0.),
 8838                    }])
 8839                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8840                    .border(BORDER_WIDTH)
 8841                    .border_color(cx.theme().colors().border)
 8842                    .rounded_r_lg()
 8843                    .id("edit_prediction_diff_popover_keybind")
 8844                    .when(!has_keybind, |el| {
 8845                        let status_colors = cx.theme().status();
 8846
 8847                        el.bg(status_colors.error_background)
 8848                            .border_color(status_colors.error.opacity(0.6))
 8849                            .child(Icon::new(IconName::Info).color(Color::Error))
 8850                            .cursor_default()
 8851                            .hoverable_tooltip(move |_window, cx| {
 8852                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8853                            })
 8854                    })
 8855                    .children(keybind),
 8856            )
 8857            .into_any();
 8858
 8859        let longest_row =
 8860            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8861        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8862            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8863        } else {
 8864            layout_line(
 8865                longest_row,
 8866                editor_snapshot,
 8867                style,
 8868                editor_width,
 8869                |_| false,
 8870                window,
 8871                cx,
 8872            )
 8873            .width
 8874        };
 8875
 8876        let viewport_bounds =
 8877            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8878                right: -right_margin,
 8879                ..Default::default()
 8880            });
 8881
 8882        let x_after_longest =
 8883            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8884                - scroll_pixel_position.x;
 8885
 8886        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8887
 8888        // Fully visible if it can be displayed within the window (allow overlapping other
 8889        // panes). However, this is only allowed if the popover starts within text_bounds.
 8890        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8891            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8892
 8893        let mut origin = if can_position_to_the_right {
 8894            point(
 8895                x_after_longest,
 8896                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8897                    - scroll_pixel_position.y,
 8898            )
 8899        } else {
 8900            let cursor_row = newest_selection_head.map(|head| head.row());
 8901            let above_edit = edit_start
 8902                .row()
 8903                .0
 8904                .checked_sub(line_count as u32)
 8905                .map(DisplayRow);
 8906            let below_edit = Some(edit_end.row() + 1);
 8907            let above_cursor =
 8908                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8909            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8910
 8911            // Place the edit popover adjacent to the edit if there is a location
 8912            // available that is onscreen and does not obscure the cursor. Otherwise,
 8913            // place it adjacent to the cursor.
 8914            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8915                .into_iter()
 8916                .flatten()
 8917                .find(|&start_row| {
 8918                    let end_row = start_row + line_count as u32;
 8919                    visible_row_range.contains(&start_row)
 8920                        && visible_row_range.contains(&end_row)
 8921                        && cursor_row.map_or(true, |cursor_row| {
 8922                            !((start_row..end_row).contains(&cursor_row))
 8923                        })
 8924                })?;
 8925
 8926            content_origin
 8927                + point(
 8928                    -scroll_pixel_position.x,
 8929                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8930                )
 8931        };
 8932
 8933        origin.x -= BORDER_WIDTH;
 8934
 8935        window.defer_draw(element, origin, 1);
 8936
 8937        // Do not return an element, since it will already be drawn due to defer_draw.
 8938        None
 8939    }
 8940
 8941    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8942        px(30.)
 8943    }
 8944
 8945    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8946        if self.read_only(cx) {
 8947            cx.theme().players().read_only()
 8948        } else {
 8949            self.style.as_ref().unwrap().local_player
 8950        }
 8951    }
 8952
 8953    fn render_edit_prediction_accept_keybind(
 8954        &self,
 8955        window: &mut Window,
 8956        cx: &App,
 8957    ) -> Option<AnyElement> {
 8958        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8959        let accept_keystroke = accept_binding.keystroke()?;
 8960
 8961        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8962
 8963        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8964            Color::Accent
 8965        } else {
 8966            Color::Muted
 8967        };
 8968
 8969        h_flex()
 8970            .px_0p5()
 8971            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8972            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8973            .text_size(TextSize::XSmall.rems(cx))
 8974            .child(h_flex().children(ui::render_modifiers(
 8975                &accept_keystroke.modifiers,
 8976                PlatformStyle::platform(),
 8977                Some(modifiers_color),
 8978                Some(IconSize::XSmall.rems().into()),
 8979                true,
 8980            )))
 8981            .when(is_platform_style_mac, |parent| {
 8982                parent.child(accept_keystroke.key.clone())
 8983            })
 8984            .when(!is_platform_style_mac, |parent| {
 8985                parent.child(
 8986                    Key::new(
 8987                        util::capitalize(&accept_keystroke.key),
 8988                        Some(Color::Default),
 8989                    )
 8990                    .size(Some(IconSize::XSmall.rems().into())),
 8991                )
 8992            })
 8993            .into_any()
 8994            .into()
 8995    }
 8996
 8997    fn render_edit_prediction_line_popover(
 8998        &self,
 8999        label: impl Into<SharedString>,
 9000        icon: Option<IconName>,
 9001        window: &mut Window,
 9002        cx: &App,
 9003    ) -> Option<Stateful<Div>> {
 9004        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9005
 9006        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9007        let has_keybind = keybind.is_some();
 9008
 9009        let result = h_flex()
 9010            .id("ep-line-popover")
 9011            .py_0p5()
 9012            .pl_1()
 9013            .pr(padding_right)
 9014            .gap_1()
 9015            .rounded_md()
 9016            .border_1()
 9017            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9018            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9019            .shadow_xs()
 9020            .when(!has_keybind, |el| {
 9021                let status_colors = cx.theme().status();
 9022
 9023                el.bg(status_colors.error_background)
 9024                    .border_color(status_colors.error.opacity(0.6))
 9025                    .pl_2()
 9026                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9027                    .cursor_default()
 9028                    .hoverable_tooltip(move |_window, cx| {
 9029                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9030                    })
 9031            })
 9032            .children(keybind)
 9033            .child(
 9034                Label::new(label)
 9035                    .size(LabelSize::Small)
 9036                    .when(!has_keybind, |el| {
 9037                        el.color(cx.theme().status().error.into()).strikethrough()
 9038                    }),
 9039            )
 9040            .when(!has_keybind, |el| {
 9041                el.child(
 9042                    h_flex().ml_1().child(
 9043                        Icon::new(IconName::Info)
 9044                            .size(IconSize::Small)
 9045                            .color(cx.theme().status().error.into()),
 9046                    ),
 9047                )
 9048            })
 9049            .when_some(icon, |element, icon| {
 9050                element.child(
 9051                    div()
 9052                        .mt(px(1.5))
 9053                        .child(Icon::new(icon).size(IconSize::Small)),
 9054                )
 9055            });
 9056
 9057        Some(result)
 9058    }
 9059
 9060    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9061        let accent_color = cx.theme().colors().text_accent;
 9062        let editor_bg_color = cx.theme().colors().editor_background;
 9063        editor_bg_color.blend(accent_color.opacity(0.1))
 9064    }
 9065
 9066    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9067        let accent_color = cx.theme().colors().text_accent;
 9068        let editor_bg_color = cx.theme().colors().editor_background;
 9069        editor_bg_color.blend(accent_color.opacity(0.6))
 9070    }
 9071
 9072    fn render_edit_prediction_cursor_popover(
 9073        &self,
 9074        min_width: Pixels,
 9075        max_width: Pixels,
 9076        cursor_point: Point,
 9077        style: &EditorStyle,
 9078        accept_keystroke: Option<&gpui::Keystroke>,
 9079        _window: &Window,
 9080        cx: &mut Context<Editor>,
 9081    ) -> Option<AnyElement> {
 9082        let provider = self.edit_prediction_provider.as_ref()?;
 9083
 9084        if provider.provider.needs_terms_acceptance(cx) {
 9085            return Some(
 9086                h_flex()
 9087                    .min_w(min_width)
 9088                    .flex_1()
 9089                    .px_2()
 9090                    .py_1()
 9091                    .gap_3()
 9092                    .elevation_2(cx)
 9093                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9094                    .id("accept-terms")
 9095                    .cursor_pointer()
 9096                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9097                    .on_click(cx.listener(|this, _event, window, cx| {
 9098                        cx.stop_propagation();
 9099                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9100                        window.dispatch_action(
 9101                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9102                            cx,
 9103                        );
 9104                    }))
 9105                    .child(
 9106                        h_flex()
 9107                            .flex_1()
 9108                            .gap_2()
 9109                            .child(Icon::new(IconName::ZedPredict))
 9110                            .child(Label::new("Accept Terms of Service"))
 9111                            .child(div().w_full())
 9112                            .child(
 9113                                Icon::new(IconName::ArrowUpRight)
 9114                                    .color(Color::Muted)
 9115                                    .size(IconSize::Small),
 9116                            )
 9117                            .into_any_element(),
 9118                    )
 9119                    .into_any(),
 9120            );
 9121        }
 9122
 9123        let is_refreshing = provider.provider.is_refreshing(cx);
 9124
 9125        fn pending_completion_container() -> Div {
 9126            h_flex()
 9127                .h_full()
 9128                .flex_1()
 9129                .gap_2()
 9130                .child(Icon::new(IconName::ZedPredict))
 9131        }
 9132
 9133        let completion = match &self.active_edit_prediction {
 9134            Some(prediction) => {
 9135                if !self.has_visible_completions_menu() {
 9136                    const RADIUS: Pixels = px(6.);
 9137                    const BORDER_WIDTH: Pixels = px(1.);
 9138
 9139                    return Some(
 9140                        h_flex()
 9141                            .elevation_2(cx)
 9142                            .border(BORDER_WIDTH)
 9143                            .border_color(cx.theme().colors().border)
 9144                            .when(accept_keystroke.is_none(), |el| {
 9145                                el.border_color(cx.theme().status().error)
 9146                            })
 9147                            .rounded(RADIUS)
 9148                            .rounded_tl(px(0.))
 9149                            .overflow_hidden()
 9150                            .child(div().px_1p5().child(match &prediction.completion {
 9151                                EditPrediction::Move { target, snapshot } => {
 9152                                    use text::ToPoint as _;
 9153                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9154                                    {
 9155                                        Icon::new(IconName::ZedPredictDown)
 9156                                    } else {
 9157                                        Icon::new(IconName::ZedPredictUp)
 9158                                    }
 9159                                }
 9160                                EditPrediction::Edit { .. } => Icon::new(IconName::ZedPredict),
 9161                            }))
 9162                            .child(
 9163                                h_flex()
 9164                                    .gap_1()
 9165                                    .py_1()
 9166                                    .px_2()
 9167                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9168                                    .border_l_1()
 9169                                    .border_color(cx.theme().colors().border)
 9170                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9171                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9172                                        el.child(
 9173                                            Label::new("Hold")
 9174                                                .size(LabelSize::Small)
 9175                                                .when(accept_keystroke.is_none(), |el| {
 9176                                                    el.strikethrough()
 9177                                                })
 9178                                                .line_height_style(LineHeightStyle::UiLabel),
 9179                                        )
 9180                                    })
 9181                                    .id("edit_prediction_cursor_popover_keybind")
 9182                                    .when(accept_keystroke.is_none(), |el| {
 9183                                        let status_colors = cx.theme().status();
 9184
 9185                                        el.bg(status_colors.error_background)
 9186                                            .border_color(status_colors.error.opacity(0.6))
 9187                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9188                                            .cursor_default()
 9189                                            .hoverable_tooltip(move |_window, cx| {
 9190                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9191                                                    .into()
 9192                                            })
 9193                                    })
 9194                                    .when_some(
 9195                                        accept_keystroke.as_ref(),
 9196                                        |el, accept_keystroke| {
 9197                                            el.child(h_flex().children(ui::render_modifiers(
 9198                                                &accept_keystroke.modifiers,
 9199                                                PlatformStyle::platform(),
 9200                                                Some(Color::Default),
 9201                                                Some(IconSize::XSmall.rems().into()),
 9202                                                false,
 9203                                            )))
 9204                                        },
 9205                                    ),
 9206                            )
 9207                            .into_any(),
 9208                    );
 9209                }
 9210
 9211                self.render_edit_prediction_cursor_popover_preview(
 9212                    prediction,
 9213                    cursor_point,
 9214                    style,
 9215                    cx,
 9216                )?
 9217            }
 9218
 9219            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9220                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9221                    stale_completion,
 9222                    cursor_point,
 9223                    style,
 9224                    cx,
 9225                )?,
 9226
 9227                None => {
 9228                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9229                }
 9230            },
 9231
 9232            None => pending_completion_container().child(Label::new("No Prediction")),
 9233        };
 9234
 9235        let completion = if is_refreshing {
 9236            completion
 9237                .with_animation(
 9238                    "loading-completion",
 9239                    Animation::new(Duration::from_secs(2))
 9240                        .repeat()
 9241                        .with_easing(pulsating_between(0.4, 0.8)),
 9242                    |label, delta| label.opacity(delta),
 9243                )
 9244                .into_any_element()
 9245        } else {
 9246            completion.into_any_element()
 9247        };
 9248
 9249        let has_completion = self.active_edit_prediction.is_some();
 9250
 9251        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9252        Some(
 9253            h_flex()
 9254                .min_w(min_width)
 9255                .max_w(max_width)
 9256                .flex_1()
 9257                .elevation_2(cx)
 9258                .border_color(cx.theme().colors().border)
 9259                .child(
 9260                    div()
 9261                        .flex_1()
 9262                        .py_1()
 9263                        .px_2()
 9264                        .overflow_hidden()
 9265                        .child(completion),
 9266                )
 9267                .when_some(accept_keystroke, |el, accept_keystroke| {
 9268                    if !accept_keystroke.modifiers.modified() {
 9269                        return el;
 9270                    }
 9271
 9272                    el.child(
 9273                        h_flex()
 9274                            .h_full()
 9275                            .border_l_1()
 9276                            .rounded_r_lg()
 9277                            .border_color(cx.theme().colors().border)
 9278                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9279                            .gap_1()
 9280                            .py_1()
 9281                            .px_2()
 9282                            .child(
 9283                                h_flex()
 9284                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9285                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9286                                    .child(h_flex().children(ui::render_modifiers(
 9287                                        &accept_keystroke.modifiers,
 9288                                        PlatformStyle::platform(),
 9289                                        Some(if !has_completion {
 9290                                            Color::Muted
 9291                                        } else {
 9292                                            Color::Default
 9293                                        }),
 9294                                        None,
 9295                                        false,
 9296                                    ))),
 9297                            )
 9298                            .child(Label::new("Preview").into_any_element())
 9299                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9300                    )
 9301                })
 9302                .into_any(),
 9303        )
 9304    }
 9305
 9306    fn render_edit_prediction_cursor_popover_preview(
 9307        &self,
 9308        completion: &EditPredictionState,
 9309        cursor_point: Point,
 9310        style: &EditorStyle,
 9311        cx: &mut Context<Editor>,
 9312    ) -> Option<Div> {
 9313        use text::ToPoint as _;
 9314
 9315        fn render_relative_row_jump(
 9316            prefix: impl Into<String>,
 9317            current_row: u32,
 9318            target_row: u32,
 9319        ) -> Div {
 9320            let (row_diff, arrow) = if target_row < current_row {
 9321                (current_row - target_row, IconName::ArrowUp)
 9322            } else {
 9323                (target_row - current_row, IconName::ArrowDown)
 9324            };
 9325
 9326            h_flex()
 9327                .child(
 9328                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9329                        .color(Color::Muted)
 9330                        .size(LabelSize::Small),
 9331                )
 9332                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9333        }
 9334
 9335        match &completion.completion {
 9336            EditPrediction::Move {
 9337                target, snapshot, ..
 9338            } => Some(
 9339                h_flex()
 9340                    .px_2()
 9341                    .gap_2()
 9342                    .flex_1()
 9343                    .child(
 9344                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9345                            Icon::new(IconName::ZedPredictDown)
 9346                        } else {
 9347                            Icon::new(IconName::ZedPredictUp)
 9348                        },
 9349                    )
 9350                    .child(Label::new("Jump to Edit")),
 9351            ),
 9352
 9353            EditPrediction::Edit {
 9354                edits,
 9355                edit_preview,
 9356                snapshot,
 9357                display_mode: _,
 9358            } => {
 9359                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9360
 9361                let (highlighted_edits, has_more_lines) = crate::edit_prediction_edit_text(
 9362                    &snapshot,
 9363                    &edits,
 9364                    edit_preview.as_ref()?,
 9365                    true,
 9366                    cx,
 9367                )
 9368                .first_line_preview();
 9369
 9370                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9371                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9372
 9373                let preview = h_flex()
 9374                    .gap_1()
 9375                    .min_w_16()
 9376                    .child(styled_text)
 9377                    .when(has_more_lines, |parent| parent.child(""));
 9378
 9379                let left = if first_edit_row != cursor_point.row {
 9380                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9381                        .into_any_element()
 9382                } else {
 9383                    Icon::new(IconName::ZedPredict).into_any_element()
 9384                };
 9385
 9386                Some(
 9387                    h_flex()
 9388                        .h_full()
 9389                        .flex_1()
 9390                        .gap_2()
 9391                        .pr_1()
 9392                        .overflow_x_hidden()
 9393                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9394                        .child(left)
 9395                        .child(preview),
 9396                )
 9397            }
 9398        }
 9399    }
 9400
 9401    pub fn render_context_menu(
 9402        &self,
 9403        style: &EditorStyle,
 9404        max_height_in_lines: u32,
 9405        window: &mut Window,
 9406        cx: &mut Context<Editor>,
 9407    ) -> Option<AnyElement> {
 9408        let menu = self.context_menu.borrow();
 9409        let menu = menu.as_ref()?;
 9410        if !menu.visible() {
 9411            return None;
 9412        };
 9413        Some(menu.render(style, max_height_in_lines, window, cx))
 9414    }
 9415
 9416    fn render_context_menu_aside(
 9417        &mut self,
 9418        max_size: Size<Pixels>,
 9419        window: &mut Window,
 9420        cx: &mut Context<Editor>,
 9421    ) -> Option<AnyElement> {
 9422        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9423            if menu.visible() {
 9424                menu.render_aside(max_size, window, cx)
 9425            } else {
 9426                None
 9427            }
 9428        })
 9429    }
 9430
 9431    fn hide_context_menu(
 9432        &mut self,
 9433        window: &mut Window,
 9434        cx: &mut Context<Self>,
 9435    ) -> Option<CodeContextMenu> {
 9436        cx.notify();
 9437        self.completion_tasks.clear();
 9438        let context_menu = self.context_menu.borrow_mut().take();
 9439        self.stale_edit_prediction_in_menu.take();
 9440        self.update_visible_edit_prediction(window, cx);
 9441        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9442            if let Some(completion_provider) = &self.completion_provider {
 9443                completion_provider.selection_changed(None, window, cx);
 9444            }
 9445        }
 9446        context_menu
 9447    }
 9448
 9449    fn show_snippet_choices(
 9450        &mut self,
 9451        choices: &Vec<String>,
 9452        selection: Range<Anchor>,
 9453        cx: &mut Context<Self>,
 9454    ) {
 9455        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9456            (Some(a), Some(b)) if a == b => a,
 9457            _ => {
 9458                log::error!("expected anchor range to have matching buffer IDs");
 9459                return;
 9460            }
 9461        };
 9462        let multi_buffer = self.buffer().read(cx);
 9463        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9464            return;
 9465        };
 9466
 9467        let id = post_inc(&mut self.next_completion_id);
 9468        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9469        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9470            CompletionsMenu::new_snippet_choices(
 9471                id,
 9472                true,
 9473                choices,
 9474                selection,
 9475                buffer,
 9476                snippet_sort_order,
 9477            ),
 9478        ));
 9479    }
 9480
 9481    pub fn insert_snippet(
 9482        &mut self,
 9483        insertion_ranges: &[Range<usize>],
 9484        snippet: Snippet,
 9485        window: &mut Window,
 9486        cx: &mut Context<Self>,
 9487    ) -> Result<()> {
 9488        struct Tabstop<T> {
 9489            is_end_tabstop: bool,
 9490            ranges: Vec<Range<T>>,
 9491            choices: Option<Vec<String>>,
 9492        }
 9493
 9494        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9495            let snippet_text: Arc<str> = snippet.text.clone().into();
 9496            let edits = insertion_ranges
 9497                .iter()
 9498                .cloned()
 9499                .map(|range| (range, snippet_text.clone()));
 9500            let autoindent_mode = AutoindentMode::Block {
 9501                original_indent_columns: Vec::new(),
 9502            };
 9503            buffer.edit(edits, Some(autoindent_mode), cx);
 9504
 9505            let snapshot = &*buffer.read(cx);
 9506            let snippet = &snippet;
 9507            snippet
 9508                .tabstops
 9509                .iter()
 9510                .map(|tabstop| {
 9511                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9512                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9513                    });
 9514                    let mut tabstop_ranges = tabstop
 9515                        .ranges
 9516                        .iter()
 9517                        .flat_map(|tabstop_range| {
 9518                            let mut delta = 0_isize;
 9519                            insertion_ranges.iter().map(move |insertion_range| {
 9520                                let insertion_start = insertion_range.start as isize + delta;
 9521                                delta +=
 9522                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9523
 9524                                let start = ((insertion_start + tabstop_range.start) as usize)
 9525                                    .min(snapshot.len());
 9526                                let end = ((insertion_start + tabstop_range.end) as usize)
 9527                                    .min(snapshot.len());
 9528                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9529                            })
 9530                        })
 9531                        .collect::<Vec<_>>();
 9532                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9533
 9534                    Tabstop {
 9535                        is_end_tabstop,
 9536                        ranges: tabstop_ranges,
 9537                        choices: tabstop.choices.clone(),
 9538                    }
 9539                })
 9540                .collect::<Vec<_>>()
 9541        });
 9542        if let Some(tabstop) = tabstops.first() {
 9543            self.change_selections(Default::default(), window, cx, |s| {
 9544                // Reverse order so that the first range is the newest created selection.
 9545                // Completions will use it and autoscroll will prioritize it.
 9546                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9547            });
 9548
 9549            if let Some(choices) = &tabstop.choices {
 9550                if let Some(selection) = tabstop.ranges.first() {
 9551                    self.show_snippet_choices(choices, selection.clone(), cx)
 9552                }
 9553            }
 9554
 9555            // If we're already at the last tabstop and it's at the end of the snippet,
 9556            // we're done, we don't need to keep the state around.
 9557            if !tabstop.is_end_tabstop {
 9558                let choices = tabstops
 9559                    .iter()
 9560                    .map(|tabstop| tabstop.choices.clone())
 9561                    .collect();
 9562
 9563                let ranges = tabstops
 9564                    .into_iter()
 9565                    .map(|tabstop| tabstop.ranges)
 9566                    .collect::<Vec<_>>();
 9567
 9568                self.snippet_stack.push(SnippetState {
 9569                    active_index: 0,
 9570                    ranges,
 9571                    choices,
 9572                });
 9573            }
 9574
 9575            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9576            if self.autoclose_regions.is_empty() {
 9577                let snapshot = self.buffer.read(cx).snapshot(cx);
 9578                let mut all_selections = self.selections.all::<Point>(cx);
 9579                for selection in &mut all_selections {
 9580                    let selection_head = selection.head();
 9581                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9582                        continue;
 9583                    };
 9584
 9585                    let mut bracket_pair = None;
 9586                    let max_lookup_length = scope
 9587                        .brackets()
 9588                        .map(|(pair, _)| {
 9589                            pair.start
 9590                                .as_str()
 9591                                .chars()
 9592                                .count()
 9593                                .max(pair.end.as_str().chars().count())
 9594                        })
 9595                        .max();
 9596                    if let Some(max_lookup_length) = max_lookup_length {
 9597                        let next_text = snapshot
 9598                            .chars_at(selection_head)
 9599                            .take(max_lookup_length)
 9600                            .collect::<String>();
 9601                        let prev_text = snapshot
 9602                            .reversed_chars_at(selection_head)
 9603                            .take(max_lookup_length)
 9604                            .collect::<String>();
 9605
 9606                        for (pair, enabled) in scope.brackets() {
 9607                            if enabled
 9608                                && pair.close
 9609                                && prev_text.starts_with(pair.start.as_str())
 9610                                && next_text.starts_with(pair.end.as_str())
 9611                            {
 9612                                bracket_pair = Some(pair.clone());
 9613                                break;
 9614                            }
 9615                        }
 9616                    }
 9617
 9618                    if let Some(pair) = bracket_pair {
 9619                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9620                        let autoclose_enabled =
 9621                            self.use_autoclose && snapshot_settings.use_autoclose;
 9622                        if autoclose_enabled {
 9623                            let start = snapshot.anchor_after(selection_head);
 9624                            let end = snapshot.anchor_after(selection_head);
 9625                            self.autoclose_regions.push(AutocloseRegion {
 9626                                selection_id: selection.id,
 9627                                range: start..end,
 9628                                pair,
 9629                            });
 9630                        }
 9631                    }
 9632                }
 9633            }
 9634        }
 9635        Ok(())
 9636    }
 9637
 9638    pub fn move_to_next_snippet_tabstop(
 9639        &mut self,
 9640        window: &mut Window,
 9641        cx: &mut Context<Self>,
 9642    ) -> bool {
 9643        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9644    }
 9645
 9646    pub fn move_to_prev_snippet_tabstop(
 9647        &mut self,
 9648        window: &mut Window,
 9649        cx: &mut Context<Self>,
 9650    ) -> bool {
 9651        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9652    }
 9653
 9654    pub fn move_to_snippet_tabstop(
 9655        &mut self,
 9656        bias: Bias,
 9657        window: &mut Window,
 9658        cx: &mut Context<Self>,
 9659    ) -> bool {
 9660        if let Some(mut snippet) = self.snippet_stack.pop() {
 9661            match bias {
 9662                Bias::Left => {
 9663                    if snippet.active_index > 0 {
 9664                        snippet.active_index -= 1;
 9665                    } else {
 9666                        self.snippet_stack.push(snippet);
 9667                        return false;
 9668                    }
 9669                }
 9670                Bias::Right => {
 9671                    if snippet.active_index + 1 < snippet.ranges.len() {
 9672                        snippet.active_index += 1;
 9673                    } else {
 9674                        self.snippet_stack.push(snippet);
 9675                        return false;
 9676                    }
 9677                }
 9678            }
 9679            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9680                self.change_selections(Default::default(), window, cx, |s| {
 9681                    // Reverse order so that the first range is the newest created selection.
 9682                    // Completions will use it and autoscroll will prioritize it.
 9683                    s.select_ranges(current_ranges.iter().rev().cloned())
 9684                });
 9685
 9686                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9687                    if let Some(selection) = current_ranges.first() {
 9688                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9689                    }
 9690                }
 9691
 9692                // If snippet state is not at the last tabstop, push it back on the stack
 9693                if snippet.active_index + 1 < snippet.ranges.len() {
 9694                    self.snippet_stack.push(snippet);
 9695                }
 9696                return true;
 9697            }
 9698        }
 9699
 9700        false
 9701    }
 9702
 9703    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9704        self.transact(window, cx, |this, window, cx| {
 9705            this.select_all(&SelectAll, window, cx);
 9706            this.insert("", window, cx);
 9707        });
 9708    }
 9709
 9710    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9712        self.transact(window, cx, |this, window, cx| {
 9713            this.select_autoclose_pair(window, cx);
 9714            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9715            if !this.linked_edit_ranges.is_empty() {
 9716                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9717                let snapshot = this.buffer.read(cx).snapshot(cx);
 9718
 9719                for selection in selections.iter() {
 9720                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9721                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9722                    if selection_start.buffer_id != selection_end.buffer_id {
 9723                        continue;
 9724                    }
 9725                    if let Some(ranges) =
 9726                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9727                    {
 9728                        for (buffer, entries) in ranges {
 9729                            linked_ranges.entry(buffer).or_default().extend(entries);
 9730                        }
 9731                    }
 9732                }
 9733            }
 9734
 9735            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9736            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9737            for selection in &mut selections {
 9738                if selection.is_empty() {
 9739                    let old_head = selection.head();
 9740                    let mut new_head =
 9741                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9742                            .to_point(&display_map);
 9743                    if let Some((buffer, line_buffer_range)) = display_map
 9744                        .buffer_snapshot
 9745                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9746                    {
 9747                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9748                        let indent_len = match indent_size.kind {
 9749                            IndentKind::Space => {
 9750                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9751                            }
 9752                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9753                        };
 9754                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9755                            let indent_len = indent_len.get();
 9756                            new_head = cmp::min(
 9757                                new_head,
 9758                                MultiBufferPoint::new(
 9759                                    old_head.row,
 9760                                    ((old_head.column - 1) / indent_len) * indent_len,
 9761                                ),
 9762                            );
 9763                        }
 9764                    }
 9765
 9766                    selection.set_head(new_head, SelectionGoal::None);
 9767                }
 9768            }
 9769
 9770            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9771            this.insert("", window, cx);
 9772            let empty_str: Arc<str> = Arc::from("");
 9773            for (buffer, edits) in linked_ranges {
 9774                let snapshot = buffer.read(cx).snapshot();
 9775                use text::ToPoint as TP;
 9776
 9777                let edits = edits
 9778                    .into_iter()
 9779                    .map(|range| {
 9780                        let end_point = TP::to_point(&range.end, &snapshot);
 9781                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9782
 9783                        if end_point == start_point {
 9784                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9785                                .saturating_sub(1);
 9786                            start_point =
 9787                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9788                        };
 9789
 9790                        (start_point..end_point, empty_str.clone())
 9791                    })
 9792                    .sorted_by_key(|(range, _)| range.start)
 9793                    .collect::<Vec<_>>();
 9794                buffer.update(cx, |this, cx| {
 9795                    this.edit(edits, None, cx);
 9796                })
 9797            }
 9798            this.refresh_edit_prediction(true, false, window, cx);
 9799            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9800        });
 9801    }
 9802
 9803    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9805        self.transact(window, cx, |this, window, cx| {
 9806            this.change_selections(Default::default(), window, cx, |s| {
 9807                s.move_with(|map, selection| {
 9808                    if selection.is_empty() {
 9809                        let cursor = movement::right(map, selection.head());
 9810                        selection.end = cursor;
 9811                        selection.reversed = true;
 9812                        selection.goal = SelectionGoal::None;
 9813                    }
 9814                })
 9815            });
 9816            this.insert("", window, cx);
 9817            this.refresh_edit_prediction(true, false, window, cx);
 9818        });
 9819    }
 9820
 9821    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9822        if self.mode.is_single_line() {
 9823            cx.propagate();
 9824            return;
 9825        }
 9826
 9827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9828        if self.move_to_prev_snippet_tabstop(window, cx) {
 9829            return;
 9830        }
 9831        self.outdent(&Outdent, window, cx);
 9832    }
 9833
 9834    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9835        if self.mode.is_single_line() {
 9836            cx.propagate();
 9837            return;
 9838        }
 9839
 9840        if self.move_to_next_snippet_tabstop(window, cx) {
 9841            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9842            return;
 9843        }
 9844        if self.read_only(cx) {
 9845            return;
 9846        }
 9847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9848        let mut selections = self.selections.all_adjusted(cx);
 9849        let buffer = self.buffer.read(cx);
 9850        let snapshot = buffer.snapshot(cx);
 9851        let rows_iter = selections.iter().map(|s| s.head().row);
 9852        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9853
 9854        let has_some_cursor_in_whitespace = selections
 9855            .iter()
 9856            .filter(|selection| selection.is_empty())
 9857            .any(|selection| {
 9858                let cursor = selection.head();
 9859                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9860                cursor.column < current_indent.len
 9861            });
 9862
 9863        let mut edits = Vec::new();
 9864        let mut prev_edited_row = 0;
 9865        let mut row_delta = 0;
 9866        for selection in &mut selections {
 9867            if selection.start.row != prev_edited_row {
 9868                row_delta = 0;
 9869            }
 9870            prev_edited_row = selection.end.row;
 9871
 9872            // If the selection is non-empty, then increase the indentation of the selected lines.
 9873            if !selection.is_empty() {
 9874                row_delta =
 9875                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9876                continue;
 9877            }
 9878
 9879            let cursor = selection.head();
 9880            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9881            if let Some(suggested_indent) =
 9882                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9883            {
 9884                // Don't do anything if already at suggested indent
 9885                // and there is any other cursor which is not
 9886                if has_some_cursor_in_whitespace
 9887                    && cursor.column == current_indent.len
 9888                    && current_indent.len == suggested_indent.len
 9889                {
 9890                    continue;
 9891                }
 9892
 9893                // Adjust line and move cursor to suggested indent
 9894                // if cursor is not at suggested indent
 9895                if cursor.column < suggested_indent.len
 9896                    && cursor.column <= current_indent.len
 9897                    && current_indent.len <= suggested_indent.len
 9898                {
 9899                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9900                    selection.end = selection.start;
 9901                    if row_delta == 0 {
 9902                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9903                            cursor.row,
 9904                            current_indent,
 9905                            suggested_indent,
 9906                        ));
 9907                        row_delta = suggested_indent.len - current_indent.len;
 9908                    }
 9909                    continue;
 9910                }
 9911
 9912                // If current indent is more than suggested indent
 9913                // only move cursor to current indent and skip indent
 9914                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9915                    selection.start = Point::new(cursor.row, current_indent.len);
 9916                    selection.end = selection.start;
 9917                    continue;
 9918                }
 9919            }
 9920
 9921            // Otherwise, insert a hard or soft tab.
 9922            let settings = buffer.language_settings_at(cursor, cx);
 9923            let tab_size = if settings.hard_tabs {
 9924                IndentSize::tab()
 9925            } else {
 9926                let tab_size = settings.tab_size.get();
 9927                let indent_remainder = snapshot
 9928                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9929                    .flat_map(str::chars)
 9930                    .fold(row_delta % tab_size, |counter: u32, c| {
 9931                        if c == '\t' {
 9932                            0
 9933                        } else {
 9934                            (counter + 1) % tab_size
 9935                        }
 9936                    });
 9937
 9938                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9939                IndentSize::spaces(chars_to_next_tab_stop)
 9940            };
 9941            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9942            selection.end = selection.start;
 9943            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9944            row_delta += tab_size.len;
 9945        }
 9946
 9947        self.transact(window, cx, |this, window, cx| {
 9948            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9949            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9950            this.refresh_edit_prediction(true, false, window, cx);
 9951        });
 9952    }
 9953
 9954    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9955        if self.read_only(cx) {
 9956            return;
 9957        }
 9958        if self.mode.is_single_line() {
 9959            cx.propagate();
 9960            return;
 9961        }
 9962
 9963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9964        let mut selections = self.selections.all::<Point>(cx);
 9965        let mut prev_edited_row = 0;
 9966        let mut row_delta = 0;
 9967        let mut edits = Vec::new();
 9968        let buffer = self.buffer.read(cx);
 9969        let snapshot = buffer.snapshot(cx);
 9970        for selection in &mut selections {
 9971            if selection.start.row != prev_edited_row {
 9972                row_delta = 0;
 9973            }
 9974            prev_edited_row = selection.end.row;
 9975
 9976            row_delta =
 9977                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9978        }
 9979
 9980        self.transact(window, cx, |this, window, cx| {
 9981            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9982            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9983        });
 9984    }
 9985
 9986    fn indent_selection(
 9987        buffer: &MultiBuffer,
 9988        snapshot: &MultiBufferSnapshot,
 9989        selection: &mut Selection<Point>,
 9990        edits: &mut Vec<(Range<Point>, String)>,
 9991        delta_for_start_row: u32,
 9992        cx: &App,
 9993    ) -> u32 {
 9994        let settings = buffer.language_settings_at(selection.start, cx);
 9995        let tab_size = settings.tab_size.get();
 9996        let indent_kind = if settings.hard_tabs {
 9997            IndentKind::Tab
 9998        } else {
 9999            IndentKind::Space
10000        };
10001        let mut start_row = selection.start.row;
10002        let mut end_row = selection.end.row + 1;
10003
10004        // If a selection ends at the beginning of a line, don't indent
10005        // that last line.
10006        if selection.end.column == 0 && selection.end.row > selection.start.row {
10007            end_row -= 1;
10008        }
10009
10010        // Avoid re-indenting a row that has already been indented by a
10011        // previous selection, but still update this selection's column
10012        // to reflect that indentation.
10013        if delta_for_start_row > 0 {
10014            start_row += 1;
10015            selection.start.column += delta_for_start_row;
10016            if selection.end.row == selection.start.row {
10017                selection.end.column += delta_for_start_row;
10018            }
10019        }
10020
10021        let mut delta_for_end_row = 0;
10022        let has_multiple_rows = start_row + 1 != end_row;
10023        for row in start_row..end_row {
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10025            let indent_delta = match (current_indent.kind, indent_kind) {
10026                (IndentKind::Space, IndentKind::Space) => {
10027                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10028                    IndentSize::spaces(columns_to_next_tab_stop)
10029                }
10030                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10031                (_, IndentKind::Tab) => IndentSize::tab(),
10032            };
10033
10034            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10035                0
10036            } else {
10037                selection.start.column
10038            };
10039            let row_start = Point::new(row, start);
10040            edits.push((
10041                row_start..row_start,
10042                indent_delta.chars().collect::<String>(),
10043            ));
10044
10045            // Update this selection's endpoints to reflect the indentation.
10046            if row == selection.start.row {
10047                selection.start.column += indent_delta.len;
10048            }
10049            if row == selection.end.row {
10050                selection.end.column += indent_delta.len;
10051                delta_for_end_row = indent_delta.len;
10052            }
10053        }
10054
10055        if selection.start.row == selection.end.row {
10056            delta_for_start_row + delta_for_end_row
10057        } else {
10058            delta_for_end_row
10059        }
10060    }
10061
10062    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10063        if self.read_only(cx) {
10064            return;
10065        }
10066        if self.mode.is_single_line() {
10067            cx.propagate();
10068            return;
10069        }
10070
10071        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10073        let selections = self.selections.all::<Point>(cx);
10074        let mut deletion_ranges = Vec::new();
10075        let mut last_outdent = None;
10076        {
10077            let buffer = self.buffer.read(cx);
10078            let snapshot = buffer.snapshot(cx);
10079            for selection in &selections {
10080                let settings = buffer.language_settings_at(selection.start, cx);
10081                let tab_size = settings.tab_size.get();
10082                let mut rows = selection.spanned_rows(false, &display_map);
10083
10084                // Avoid re-outdenting a row that has already been outdented by a
10085                // previous selection.
10086                if let Some(last_row) = last_outdent {
10087                    if last_row == rows.start {
10088                        rows.start = rows.start.next_row();
10089                    }
10090                }
10091                let has_multiple_rows = rows.len() > 1;
10092                for row in rows.iter_rows() {
10093                    let indent_size = snapshot.indent_size_for_line(row);
10094                    if indent_size.len > 0 {
10095                        let deletion_len = match indent_size.kind {
10096                            IndentKind::Space => {
10097                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10098                                if columns_to_prev_tab_stop == 0 {
10099                                    tab_size
10100                                } else {
10101                                    columns_to_prev_tab_stop
10102                                }
10103                            }
10104                            IndentKind::Tab => 1,
10105                        };
10106                        let start = if has_multiple_rows
10107                            || deletion_len > selection.start.column
10108                            || indent_size.len < selection.start.column
10109                        {
10110                            0
10111                        } else {
10112                            selection.start.column - deletion_len
10113                        };
10114                        deletion_ranges.push(
10115                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10116                        );
10117                        last_outdent = Some(row);
10118                    }
10119                }
10120            }
10121        }
10122
10123        self.transact(window, cx, |this, window, cx| {
10124            this.buffer.update(cx, |buffer, cx| {
10125                let empty_str: Arc<str> = Arc::default();
10126                buffer.edit(
10127                    deletion_ranges
10128                        .into_iter()
10129                        .map(|range| (range, empty_str.clone())),
10130                    None,
10131                    cx,
10132                );
10133            });
10134            let selections = this.selections.all::<usize>(cx);
10135            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10136        });
10137    }
10138
10139    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10140        if self.read_only(cx) {
10141            return;
10142        }
10143        if self.mode.is_single_line() {
10144            cx.propagate();
10145            return;
10146        }
10147
10148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10149        let selections = self
10150            .selections
10151            .all::<usize>(cx)
10152            .into_iter()
10153            .map(|s| s.range());
10154
10155        self.transact(window, cx, |this, window, cx| {
10156            this.buffer.update(cx, |buffer, cx| {
10157                buffer.autoindent_ranges(selections, cx);
10158            });
10159            let selections = this.selections.all::<usize>(cx);
10160            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10161        });
10162    }
10163
10164    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10167        let selections = self.selections.all::<Point>(cx);
10168
10169        let mut new_cursors = Vec::new();
10170        let mut edit_ranges = Vec::new();
10171        let mut selections = selections.iter().peekable();
10172        while let Some(selection) = selections.next() {
10173            let mut rows = selection.spanned_rows(false, &display_map);
10174            let goal_display_column = selection.head().to_display_point(&display_map).column();
10175
10176            // Accumulate contiguous regions of rows that we want to delete.
10177            while let Some(next_selection) = selections.peek() {
10178                let next_rows = next_selection.spanned_rows(false, &display_map);
10179                if next_rows.start <= rows.end {
10180                    rows.end = next_rows.end;
10181                    selections.next().unwrap();
10182                } else {
10183                    break;
10184                }
10185            }
10186
10187            let buffer = &display_map.buffer_snapshot;
10188            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10189            let edit_end;
10190            let cursor_buffer_row;
10191            if buffer.max_point().row >= rows.end.0 {
10192                // If there's a line after the range, delete the \n from the end of the row range
10193                // and position the cursor on the next line.
10194                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10195                cursor_buffer_row = rows.end;
10196            } else {
10197                // If there isn't a line after the range, delete the \n from the line before the
10198                // start of the row range and position the cursor there.
10199                edit_start = edit_start.saturating_sub(1);
10200                edit_end = buffer.len();
10201                cursor_buffer_row = rows.start.previous_row();
10202            }
10203
10204            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10205            *cursor.column_mut() =
10206                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10207
10208            new_cursors.push((
10209                selection.id,
10210                buffer.anchor_after(cursor.to_point(&display_map)),
10211            ));
10212            edit_ranges.push(edit_start..edit_end);
10213        }
10214
10215        self.transact(window, cx, |this, window, cx| {
10216            let buffer = this.buffer.update(cx, |buffer, cx| {
10217                let empty_str: Arc<str> = Arc::default();
10218                buffer.edit(
10219                    edit_ranges
10220                        .into_iter()
10221                        .map(|range| (range, empty_str.clone())),
10222                    None,
10223                    cx,
10224                );
10225                buffer.snapshot(cx)
10226            });
10227            let new_selections = new_cursors
10228                .into_iter()
10229                .map(|(id, cursor)| {
10230                    let cursor = cursor.to_point(&buffer);
10231                    Selection {
10232                        id,
10233                        start: cursor,
10234                        end: cursor,
10235                        reversed: false,
10236                        goal: SelectionGoal::None,
10237                    }
10238                })
10239                .collect();
10240
10241            this.change_selections(Default::default(), window, cx, |s| {
10242                s.select(new_selections);
10243            });
10244        });
10245    }
10246
10247    pub fn join_lines_impl(
10248        &mut self,
10249        insert_whitespace: bool,
10250        window: &mut Window,
10251        cx: &mut Context<Self>,
10252    ) {
10253        if self.read_only(cx) {
10254            return;
10255        }
10256        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10257        for selection in self.selections.all::<Point>(cx) {
10258            let start = MultiBufferRow(selection.start.row);
10259            // Treat single line selections as if they include the next line. Otherwise this action
10260            // would do nothing for single line selections individual cursors.
10261            let end = if selection.start.row == selection.end.row {
10262                MultiBufferRow(selection.start.row + 1)
10263            } else {
10264                MultiBufferRow(selection.end.row)
10265            };
10266
10267            if let Some(last_row_range) = row_ranges.last_mut() {
10268                if start <= last_row_range.end {
10269                    last_row_range.end = end;
10270                    continue;
10271                }
10272            }
10273            row_ranges.push(start..end);
10274        }
10275
10276        let snapshot = self.buffer.read(cx).snapshot(cx);
10277        let mut cursor_positions = Vec::new();
10278        for row_range in &row_ranges {
10279            let anchor = snapshot.anchor_before(Point::new(
10280                row_range.end.previous_row().0,
10281                snapshot.line_len(row_range.end.previous_row()),
10282            ));
10283            cursor_positions.push(anchor..anchor);
10284        }
10285
10286        self.transact(window, cx, |this, window, cx| {
10287            for row_range in row_ranges.into_iter().rev() {
10288                for row in row_range.iter_rows().rev() {
10289                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10290                    let next_line_row = row.next_row();
10291                    let indent = snapshot.indent_size_for_line(next_line_row);
10292                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10293
10294                    let replace =
10295                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10296                            " "
10297                        } else {
10298                            ""
10299                        };
10300
10301                    this.buffer.update(cx, |buffer, cx| {
10302                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10303                    });
10304                }
10305            }
10306
10307            this.change_selections(Default::default(), window, cx, |s| {
10308                s.select_anchor_ranges(cursor_positions)
10309            });
10310        });
10311    }
10312
10313    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10314        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10315        self.join_lines_impl(true, window, cx);
10316    }
10317
10318    pub fn sort_lines_case_sensitive(
10319        &mut self,
10320        _: &SortLinesCaseSensitive,
10321        window: &mut Window,
10322        cx: &mut Context<Self>,
10323    ) {
10324        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10325    }
10326
10327    pub fn sort_lines_by_length(
10328        &mut self,
10329        _: &SortLinesByLength,
10330        window: &mut Window,
10331        cx: &mut Context<Self>,
10332    ) {
10333        self.manipulate_immutable_lines(window, cx, |lines| {
10334            lines.sort_by_key(|&line| line.chars().count())
10335        })
10336    }
10337
10338    pub fn sort_lines_case_insensitive(
10339        &mut self,
10340        _: &SortLinesCaseInsensitive,
10341        window: &mut Window,
10342        cx: &mut Context<Self>,
10343    ) {
10344        self.manipulate_immutable_lines(window, cx, |lines| {
10345            lines.sort_by_key(|line| line.to_lowercase())
10346        })
10347    }
10348
10349    pub fn unique_lines_case_insensitive(
10350        &mut self,
10351        _: &UniqueLinesCaseInsensitive,
10352        window: &mut Window,
10353        cx: &mut Context<Self>,
10354    ) {
10355        self.manipulate_immutable_lines(window, cx, |lines| {
10356            let mut seen = HashSet::default();
10357            lines.retain(|line| seen.insert(line.to_lowercase()));
10358        })
10359    }
10360
10361    pub fn unique_lines_case_sensitive(
10362        &mut self,
10363        _: &UniqueLinesCaseSensitive,
10364        window: &mut Window,
10365        cx: &mut Context<Self>,
10366    ) {
10367        self.manipulate_immutable_lines(window, cx, |lines| {
10368            let mut seen = HashSet::default();
10369            lines.retain(|line| seen.insert(*line));
10370        })
10371    }
10372
10373    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10374        let Some(project) = self.project.clone() else {
10375            return;
10376        };
10377        self.reload(project, window, cx)
10378            .detach_and_notify_err(window, cx);
10379    }
10380
10381    pub fn restore_file(
10382        &mut self,
10383        _: &::git::RestoreFile,
10384        window: &mut Window,
10385        cx: &mut Context<Self>,
10386    ) {
10387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10388        let mut buffer_ids = HashSet::default();
10389        let snapshot = self.buffer().read(cx).snapshot(cx);
10390        for selection in self.selections.all::<usize>(cx) {
10391            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10392        }
10393
10394        let buffer = self.buffer().read(cx);
10395        let ranges = buffer_ids
10396            .into_iter()
10397            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10398            .collect::<Vec<_>>();
10399
10400        self.restore_hunks_in_ranges(ranges, window, cx);
10401    }
10402
10403    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10404        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10405        let selections = self
10406            .selections
10407            .all(cx)
10408            .into_iter()
10409            .map(|s| s.range())
10410            .collect();
10411        self.restore_hunks_in_ranges(selections, window, cx);
10412    }
10413
10414    pub fn restore_hunks_in_ranges(
10415        &mut self,
10416        ranges: Vec<Range<Point>>,
10417        window: &mut Window,
10418        cx: &mut Context<Editor>,
10419    ) {
10420        let mut revert_changes = HashMap::default();
10421        let chunk_by = self
10422            .snapshot(window, cx)
10423            .hunks_for_ranges(ranges)
10424            .into_iter()
10425            .chunk_by(|hunk| hunk.buffer_id);
10426        for (buffer_id, hunks) in &chunk_by {
10427            let hunks = hunks.collect::<Vec<_>>();
10428            for hunk in &hunks {
10429                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10430            }
10431            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10432        }
10433        drop(chunk_by);
10434        if !revert_changes.is_empty() {
10435            self.transact(window, cx, |editor, window, cx| {
10436                editor.restore(revert_changes, window, cx);
10437            });
10438        }
10439    }
10440
10441    pub fn open_active_item_in_terminal(
10442        &mut self,
10443        _: &OpenInTerminal,
10444        window: &mut Window,
10445        cx: &mut Context<Self>,
10446    ) {
10447        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10448            let project_path = buffer.read(cx).project_path(cx)?;
10449            let project = self.project.as_ref()?.read(cx);
10450            let entry = project.entry_for_path(&project_path, cx)?;
10451            let parent = match &entry.canonical_path {
10452                Some(canonical_path) => canonical_path.to_path_buf(),
10453                None => project.absolute_path(&project_path, cx)?,
10454            }
10455            .parent()?
10456            .to_path_buf();
10457            Some(parent)
10458        }) {
10459            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10460        }
10461    }
10462
10463    fn set_breakpoint_context_menu(
10464        &mut self,
10465        display_row: DisplayRow,
10466        position: Option<Anchor>,
10467        clicked_point: gpui::Point<Pixels>,
10468        window: &mut Window,
10469        cx: &mut Context<Self>,
10470    ) {
10471        let source = self
10472            .buffer
10473            .read(cx)
10474            .snapshot(cx)
10475            .anchor_before(Point::new(display_row.0, 0u32));
10476
10477        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10478
10479        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10480            self,
10481            source,
10482            clicked_point,
10483            context_menu,
10484            window,
10485            cx,
10486        );
10487    }
10488
10489    fn add_edit_breakpoint_block(
10490        &mut self,
10491        anchor: Anchor,
10492        breakpoint: &Breakpoint,
10493        edit_action: BreakpointPromptEditAction,
10494        window: &mut Window,
10495        cx: &mut Context<Self>,
10496    ) {
10497        let weak_editor = cx.weak_entity();
10498        let bp_prompt = cx.new(|cx| {
10499            BreakpointPromptEditor::new(
10500                weak_editor,
10501                anchor,
10502                breakpoint.clone(),
10503                edit_action,
10504                window,
10505                cx,
10506            )
10507        });
10508
10509        let height = bp_prompt.update(cx, |this, cx| {
10510            this.prompt
10511                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10512        });
10513        let cloned_prompt = bp_prompt.clone();
10514        let blocks = vec![BlockProperties {
10515            style: BlockStyle::Sticky,
10516            placement: BlockPlacement::Above(anchor),
10517            height: Some(height),
10518            render: Arc::new(move |cx| {
10519                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10520                cloned_prompt.clone().into_any_element()
10521            }),
10522            priority: 0,
10523        }];
10524
10525        let focus_handle = bp_prompt.focus_handle(cx);
10526        window.focus(&focus_handle);
10527
10528        let block_ids = self.insert_blocks(blocks, None, cx);
10529        bp_prompt.update(cx, |prompt, _| {
10530            prompt.add_block_ids(block_ids);
10531        });
10532    }
10533
10534    pub(crate) fn breakpoint_at_row(
10535        &self,
10536        row: u32,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) -> Option<(Anchor, Breakpoint)> {
10540        let snapshot = self.snapshot(window, cx);
10541        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10542
10543        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10544    }
10545
10546    pub(crate) fn breakpoint_at_anchor(
10547        &self,
10548        breakpoint_position: Anchor,
10549        snapshot: &EditorSnapshot,
10550        cx: &mut Context<Self>,
10551    ) -> Option<(Anchor, Breakpoint)> {
10552        let project = self.project.clone()?;
10553
10554        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10555            snapshot
10556                .buffer_snapshot
10557                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10558        })?;
10559
10560        let enclosing_excerpt = breakpoint_position.excerpt_id;
10561        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10562        let buffer_snapshot = buffer.read(cx).snapshot();
10563
10564        let row = buffer_snapshot
10565            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10566            .row;
10567
10568        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10569        let anchor_end = snapshot
10570            .buffer_snapshot
10571            .anchor_after(Point::new(row, line_len));
10572
10573        let bp = self
10574            .breakpoint_store
10575            .as_ref()?
10576            .read_with(cx, |breakpoint_store, cx| {
10577                breakpoint_store
10578                    .breakpoints(
10579                        &buffer,
10580                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10581                        &buffer_snapshot,
10582                        cx,
10583                    )
10584                    .next()
10585                    .and_then(|(bp, _)| {
10586                        let breakpoint_row = buffer_snapshot
10587                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10588                            .row;
10589
10590                        if breakpoint_row == row {
10591                            snapshot
10592                                .buffer_snapshot
10593                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10594                                .map(|position| (position, bp.bp.clone()))
10595                        } else {
10596                            None
10597                        }
10598                    })
10599            });
10600        bp
10601    }
10602
10603    pub fn edit_log_breakpoint(
10604        &mut self,
10605        _: &EditLogBreakpoint,
10606        window: &mut Window,
10607        cx: &mut Context<Self>,
10608    ) {
10609        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10610            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10611                message: None,
10612                state: BreakpointState::Enabled,
10613                condition: None,
10614                hit_condition: None,
10615            });
10616
10617            self.add_edit_breakpoint_block(
10618                anchor,
10619                &breakpoint,
10620                BreakpointPromptEditAction::Log,
10621                window,
10622                cx,
10623            );
10624        }
10625    }
10626
10627    fn breakpoints_at_cursors(
10628        &self,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10632        let snapshot = self.snapshot(window, cx);
10633        let cursors = self
10634            .selections
10635            .disjoint_anchors()
10636            .into_iter()
10637            .map(|selection| {
10638                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10639
10640                let breakpoint_position = self
10641                    .breakpoint_at_row(cursor_position.row, window, cx)
10642                    .map(|bp| bp.0)
10643                    .unwrap_or_else(|| {
10644                        snapshot
10645                            .display_snapshot
10646                            .buffer_snapshot
10647                            .anchor_after(Point::new(cursor_position.row, 0))
10648                    });
10649
10650                let breakpoint = self
10651                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10652                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10653
10654                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10655            })
10656            // 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.
10657            .collect::<HashMap<Anchor, _>>();
10658
10659        cursors.into_iter().collect()
10660    }
10661
10662    pub fn enable_breakpoint(
10663        &mut self,
10664        _: &crate::actions::EnableBreakpoint,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10669            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10670                continue;
10671            };
10672            self.edit_breakpoint_at_anchor(
10673                anchor,
10674                breakpoint,
10675                BreakpointEditAction::InvertState,
10676                cx,
10677            );
10678        }
10679    }
10680
10681    pub fn disable_breakpoint(
10682        &mut self,
10683        _: &crate::actions::DisableBreakpoint,
10684        window: &mut Window,
10685        cx: &mut Context<Self>,
10686    ) {
10687        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10688            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10689                continue;
10690            };
10691            self.edit_breakpoint_at_anchor(
10692                anchor,
10693                breakpoint,
10694                BreakpointEditAction::InvertState,
10695                cx,
10696            );
10697        }
10698    }
10699
10700    pub fn toggle_breakpoint(
10701        &mut self,
10702        _: &crate::actions::ToggleBreakpoint,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10707            if let Some(breakpoint) = breakpoint {
10708                self.edit_breakpoint_at_anchor(
10709                    anchor,
10710                    breakpoint,
10711                    BreakpointEditAction::Toggle,
10712                    cx,
10713                );
10714            } else {
10715                self.edit_breakpoint_at_anchor(
10716                    anchor,
10717                    Breakpoint::new_standard(),
10718                    BreakpointEditAction::Toggle,
10719                    cx,
10720                );
10721            }
10722        }
10723    }
10724
10725    pub fn edit_breakpoint_at_anchor(
10726        &mut self,
10727        breakpoint_position: Anchor,
10728        breakpoint: Breakpoint,
10729        edit_action: BreakpointEditAction,
10730        cx: &mut Context<Self>,
10731    ) {
10732        let Some(breakpoint_store) = &self.breakpoint_store else {
10733            return;
10734        };
10735
10736        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10737            if breakpoint_position == Anchor::min() {
10738                self.buffer()
10739                    .read(cx)
10740                    .excerpt_buffer_ids()
10741                    .into_iter()
10742                    .next()
10743            } else {
10744                None
10745            }
10746        }) else {
10747            return;
10748        };
10749
10750        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10751            return;
10752        };
10753
10754        breakpoint_store.update(cx, |breakpoint_store, cx| {
10755            breakpoint_store.toggle_breakpoint(
10756                buffer,
10757                BreakpointWithPosition {
10758                    position: breakpoint_position.text_anchor,
10759                    bp: breakpoint,
10760                },
10761                edit_action,
10762                cx,
10763            );
10764        });
10765
10766        cx.notify();
10767    }
10768
10769    #[cfg(any(test, feature = "test-support"))]
10770    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10771        self.breakpoint_store.clone()
10772    }
10773
10774    pub fn prepare_restore_change(
10775        &self,
10776        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10777        hunk: &MultiBufferDiffHunk,
10778        cx: &mut App,
10779    ) -> Option<()> {
10780        if hunk.is_created_file() {
10781            return None;
10782        }
10783        let buffer = self.buffer.read(cx);
10784        let diff = buffer.diff_for(hunk.buffer_id)?;
10785        let buffer = buffer.buffer(hunk.buffer_id)?;
10786        let buffer = buffer.read(cx);
10787        let original_text = diff
10788            .read(cx)
10789            .base_text()
10790            .as_rope()
10791            .slice(hunk.diff_base_byte_range.clone());
10792        let buffer_snapshot = buffer.snapshot();
10793        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10794        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10795            probe
10796                .0
10797                .start
10798                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10799                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10800        }) {
10801            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10802            Some(())
10803        } else {
10804            None
10805        }
10806    }
10807
10808    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10809        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10810    }
10811
10812    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10813        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10814    }
10815
10816    fn manipulate_lines<M>(
10817        &mut self,
10818        window: &mut Window,
10819        cx: &mut Context<Self>,
10820        mut manipulate: M,
10821    ) where
10822        M: FnMut(&str) -> LineManipulationResult,
10823    {
10824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10825
10826        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10827        let buffer = self.buffer.read(cx).snapshot(cx);
10828
10829        let mut edits = Vec::new();
10830
10831        let selections = self.selections.all::<Point>(cx);
10832        let mut selections = selections.iter().peekable();
10833        let mut contiguous_row_selections = Vec::new();
10834        let mut new_selections = Vec::new();
10835        let mut added_lines = 0;
10836        let mut removed_lines = 0;
10837
10838        while let Some(selection) = selections.next() {
10839            let (start_row, end_row) = consume_contiguous_rows(
10840                &mut contiguous_row_selections,
10841                selection,
10842                &display_map,
10843                &mut selections,
10844            );
10845
10846            let start_point = Point::new(start_row.0, 0);
10847            let end_point = Point::new(
10848                end_row.previous_row().0,
10849                buffer.line_len(end_row.previous_row()),
10850            );
10851            let text = buffer
10852                .text_for_range(start_point..end_point)
10853                .collect::<String>();
10854
10855            let LineManipulationResult {
10856                new_text,
10857                line_count_before,
10858                line_count_after,
10859            } = manipulate(&text);
10860
10861            edits.push((start_point..end_point, new_text));
10862
10863            // Selections must change based on added and removed line count
10864            let start_row =
10865                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10866            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10867            new_selections.push(Selection {
10868                id: selection.id,
10869                start: start_row,
10870                end: end_row,
10871                goal: SelectionGoal::None,
10872                reversed: selection.reversed,
10873            });
10874
10875            if line_count_after > line_count_before {
10876                added_lines += line_count_after - line_count_before;
10877            } else if line_count_before > line_count_after {
10878                removed_lines += line_count_before - line_count_after;
10879            }
10880        }
10881
10882        self.transact(window, cx, |this, window, cx| {
10883            let buffer = this.buffer.update(cx, |buffer, cx| {
10884                buffer.edit(edits, None, cx);
10885                buffer.snapshot(cx)
10886            });
10887
10888            // Recalculate offsets on newly edited buffer
10889            let new_selections = new_selections
10890                .iter()
10891                .map(|s| {
10892                    let start_point = Point::new(s.start.0, 0);
10893                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10894                    Selection {
10895                        id: s.id,
10896                        start: buffer.point_to_offset(start_point),
10897                        end: buffer.point_to_offset(end_point),
10898                        goal: s.goal,
10899                        reversed: s.reversed,
10900                    }
10901                })
10902                .collect();
10903
10904            this.change_selections(Default::default(), window, cx, |s| {
10905                s.select(new_selections);
10906            });
10907
10908            this.request_autoscroll(Autoscroll::fit(), cx);
10909        });
10910    }
10911
10912    fn manipulate_immutable_lines<Fn>(
10913        &mut self,
10914        window: &mut Window,
10915        cx: &mut Context<Self>,
10916        mut callback: Fn,
10917    ) where
10918        Fn: FnMut(&mut Vec<&str>),
10919    {
10920        self.manipulate_lines(window, cx, |text| {
10921            let mut lines: Vec<&str> = text.split('\n').collect();
10922            let line_count_before = lines.len();
10923
10924            callback(&mut lines);
10925
10926            LineManipulationResult {
10927                new_text: lines.join("\n"),
10928                line_count_before,
10929                line_count_after: lines.len(),
10930            }
10931        });
10932    }
10933
10934    fn manipulate_mutable_lines<Fn>(
10935        &mut self,
10936        window: &mut Window,
10937        cx: &mut Context<Self>,
10938        mut callback: Fn,
10939    ) where
10940        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10941    {
10942        self.manipulate_lines(window, cx, |text| {
10943            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10944            let line_count_before = lines.len();
10945
10946            callback(&mut lines);
10947
10948            LineManipulationResult {
10949                new_text: lines.join("\n"),
10950                line_count_before,
10951                line_count_after: lines.len(),
10952            }
10953        });
10954    }
10955
10956    pub fn convert_indentation_to_spaces(
10957        &mut self,
10958        _: &ConvertIndentationToSpaces,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        let settings = self.buffer.read(cx).language_settings(cx);
10963        let tab_size = settings.tab_size.get() as usize;
10964
10965        self.manipulate_mutable_lines(window, cx, |lines| {
10966            // Allocates a reasonably sized scratch buffer once for the whole loop
10967            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10968            // Avoids recomputing spaces that could be inserted many times
10969            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10970                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10971                .collect();
10972
10973            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10974                let mut chars = line.as_ref().chars();
10975                let mut col = 0;
10976                let mut changed = false;
10977
10978                while let Some(ch) = chars.next() {
10979                    match ch {
10980                        ' ' => {
10981                            reindented_line.push(' ');
10982                            col += 1;
10983                        }
10984                        '\t' => {
10985                            // \t are converted to spaces depending on the current column
10986                            let spaces_len = tab_size - (col % tab_size);
10987                            reindented_line.extend(&space_cache[spaces_len - 1]);
10988                            col += spaces_len;
10989                            changed = true;
10990                        }
10991                        _ => {
10992                            // If we dont append before break, the character is consumed
10993                            reindented_line.push(ch);
10994                            break;
10995                        }
10996                    }
10997                }
10998
10999                if !changed {
11000                    reindented_line.clear();
11001                    continue;
11002                }
11003                // Append the rest of the line and replace old reference with new one
11004                reindented_line.extend(chars);
11005                *line = Cow::Owned(reindented_line.clone());
11006                reindented_line.clear();
11007            }
11008        });
11009    }
11010
11011    pub fn convert_indentation_to_tabs(
11012        &mut self,
11013        _: &ConvertIndentationToTabs,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        let settings = self.buffer.read(cx).language_settings(cx);
11018        let tab_size = settings.tab_size.get() as usize;
11019
11020        self.manipulate_mutable_lines(window, cx, |lines| {
11021            // Allocates a reasonably sized buffer once for the whole loop
11022            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11023            // Avoids recomputing spaces that could be inserted many times
11024            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11025                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11026                .collect();
11027
11028            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11029                let mut chars = line.chars();
11030                let mut spaces_count = 0;
11031                let mut first_non_indent_char = None;
11032                let mut changed = false;
11033
11034                while let Some(ch) = chars.next() {
11035                    match ch {
11036                        ' ' => {
11037                            // Keep track of spaces. Append \t when we reach tab_size
11038                            spaces_count += 1;
11039                            changed = true;
11040                            if spaces_count == tab_size {
11041                                reindented_line.push('\t');
11042                                spaces_count = 0;
11043                            }
11044                        }
11045                        '\t' => {
11046                            reindented_line.push('\t');
11047                            spaces_count = 0;
11048                        }
11049                        _ => {
11050                            // Dont append it yet, we might have remaining spaces
11051                            first_non_indent_char = Some(ch);
11052                            break;
11053                        }
11054                    }
11055                }
11056
11057                if !changed {
11058                    reindented_line.clear();
11059                    continue;
11060                }
11061                // Remaining spaces that didn't make a full tab stop
11062                if spaces_count > 0 {
11063                    reindented_line.extend(&space_cache[spaces_count - 1]);
11064                }
11065                // If we consume an extra character that was not indentation, add it back
11066                if let Some(extra_char) = first_non_indent_char {
11067                    reindented_line.push(extra_char);
11068                }
11069                // Append the rest of the line and replace old reference with new one
11070                reindented_line.extend(chars);
11071                *line = Cow::Owned(reindented_line.clone());
11072                reindented_line.clear();
11073            }
11074        });
11075    }
11076
11077    pub fn convert_to_upper_case(
11078        &mut self,
11079        _: &ConvertToUpperCase,
11080        window: &mut Window,
11081        cx: &mut Context<Self>,
11082    ) {
11083        self.manipulate_text(window, cx, |text| text.to_uppercase())
11084    }
11085
11086    pub fn convert_to_lower_case(
11087        &mut self,
11088        _: &ConvertToLowerCase,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        self.manipulate_text(window, cx, |text| text.to_lowercase())
11093    }
11094
11095    pub fn convert_to_title_case(
11096        &mut self,
11097        _: &ConvertToTitleCase,
11098        window: &mut Window,
11099        cx: &mut Context<Self>,
11100    ) {
11101        self.manipulate_text(window, cx, |text| {
11102            text.split('\n')
11103                .map(|line| line.to_case(Case::Title))
11104                .join("\n")
11105        })
11106    }
11107
11108    pub fn convert_to_snake_case(
11109        &mut self,
11110        _: &ConvertToSnakeCase,
11111        window: &mut Window,
11112        cx: &mut Context<Self>,
11113    ) {
11114        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11115    }
11116
11117    pub fn convert_to_kebab_case(
11118        &mut self,
11119        _: &ConvertToKebabCase,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11124    }
11125
11126    pub fn convert_to_upper_camel_case(
11127        &mut self,
11128        _: &ConvertToUpperCamelCase,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        self.manipulate_text(window, cx, |text| {
11133            text.split('\n')
11134                .map(|line| line.to_case(Case::UpperCamel))
11135                .join("\n")
11136        })
11137    }
11138
11139    pub fn convert_to_lower_camel_case(
11140        &mut self,
11141        _: &ConvertToLowerCamelCase,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11146    }
11147
11148    pub fn convert_to_opposite_case(
11149        &mut self,
11150        _: &ConvertToOppositeCase,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153    ) {
11154        self.manipulate_text(window, cx, |text| {
11155            text.chars()
11156                .fold(String::with_capacity(text.len()), |mut t, c| {
11157                    if c.is_uppercase() {
11158                        t.extend(c.to_lowercase());
11159                    } else {
11160                        t.extend(c.to_uppercase());
11161                    }
11162                    t
11163                })
11164        })
11165    }
11166
11167    pub fn convert_to_sentence_case(
11168        &mut self,
11169        _: &ConvertToSentenceCase,
11170        window: &mut Window,
11171        cx: &mut Context<Self>,
11172    ) {
11173        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11174    }
11175
11176    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11177        self.manipulate_text(window, cx, |text| {
11178            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11179            if has_upper_case_characters {
11180                text.to_lowercase()
11181            } else {
11182                text.to_uppercase()
11183            }
11184        })
11185    }
11186
11187    pub fn convert_to_rot13(
11188        &mut self,
11189        _: &ConvertToRot13,
11190        window: &mut Window,
11191        cx: &mut Context<Self>,
11192    ) {
11193        self.manipulate_text(window, cx, |text| {
11194            text.chars()
11195                .map(|c| match c {
11196                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11197                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11198                    _ => c,
11199                })
11200                .collect()
11201        })
11202    }
11203
11204    pub fn convert_to_rot47(
11205        &mut self,
11206        _: &ConvertToRot47,
11207        window: &mut Window,
11208        cx: &mut Context<Self>,
11209    ) {
11210        self.manipulate_text(window, cx, |text| {
11211            text.chars()
11212                .map(|c| {
11213                    let code_point = c as u32;
11214                    if code_point >= 33 && code_point <= 126 {
11215                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11216                    }
11217                    c
11218                })
11219                .collect()
11220        })
11221    }
11222
11223    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11224    where
11225        Fn: FnMut(&str) -> String,
11226    {
11227        let buffer = self.buffer.read(cx).snapshot(cx);
11228
11229        let mut new_selections = Vec::new();
11230        let mut edits = Vec::new();
11231        let mut selection_adjustment = 0i32;
11232
11233        for selection in self.selections.all::<usize>(cx) {
11234            let selection_is_empty = selection.is_empty();
11235
11236            let (start, end) = if selection_is_empty {
11237                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11238                (word_range.start, word_range.end)
11239            } else {
11240                (selection.start, selection.end)
11241            };
11242
11243            let text = buffer.text_for_range(start..end).collect::<String>();
11244            let old_length = text.len() as i32;
11245            let text = callback(&text);
11246
11247            new_selections.push(Selection {
11248                start: (start as i32 - selection_adjustment) as usize,
11249                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11250                goal: SelectionGoal::None,
11251                ..selection
11252            });
11253
11254            selection_adjustment += old_length - text.len() as i32;
11255
11256            edits.push((start..end, text));
11257        }
11258
11259        self.transact(window, cx, |this, window, cx| {
11260            this.buffer.update(cx, |buffer, cx| {
11261                buffer.edit(edits, None, cx);
11262            });
11263
11264            this.change_selections(Default::default(), window, cx, |s| {
11265                s.select(new_selections);
11266            });
11267
11268            this.request_autoscroll(Autoscroll::fit(), cx);
11269        });
11270    }
11271
11272    pub fn move_selection_on_drop(
11273        &mut self,
11274        selection: &Selection<Anchor>,
11275        target: DisplayPoint,
11276        is_cut: bool,
11277        window: &mut Window,
11278        cx: &mut Context<Self>,
11279    ) {
11280        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11281        let buffer = &display_map.buffer_snapshot;
11282        let mut edits = Vec::new();
11283        let insert_point = display_map
11284            .clip_point(target, Bias::Left)
11285            .to_point(&display_map);
11286        let text = buffer
11287            .text_for_range(selection.start..selection.end)
11288            .collect::<String>();
11289        if is_cut {
11290            edits.push(((selection.start..selection.end), String::new()));
11291        }
11292        let insert_anchor = buffer.anchor_before(insert_point);
11293        edits.push(((insert_anchor..insert_anchor), text));
11294        let last_edit_start = insert_anchor.bias_left(buffer);
11295        let last_edit_end = insert_anchor.bias_right(buffer);
11296        self.transact(window, cx, |this, window, cx| {
11297            this.buffer.update(cx, |buffer, cx| {
11298                buffer.edit(edits, None, cx);
11299            });
11300            this.change_selections(Default::default(), window, cx, |s| {
11301                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11302            });
11303        });
11304    }
11305
11306    pub fn clear_selection_drag_state(&mut self) {
11307        self.selection_drag_state = SelectionDragState::None;
11308    }
11309
11310    pub fn duplicate(
11311        &mut self,
11312        upwards: bool,
11313        whole_lines: bool,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11318
11319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11320        let buffer = &display_map.buffer_snapshot;
11321        let selections = self.selections.all::<Point>(cx);
11322
11323        let mut edits = Vec::new();
11324        let mut selections_iter = selections.iter().peekable();
11325        while let Some(selection) = selections_iter.next() {
11326            let mut rows = selection.spanned_rows(false, &display_map);
11327            // duplicate line-wise
11328            if whole_lines || selection.start == selection.end {
11329                // Avoid duplicating the same lines twice.
11330                while let Some(next_selection) = selections_iter.peek() {
11331                    let next_rows = next_selection.spanned_rows(false, &display_map);
11332                    if next_rows.start < rows.end {
11333                        rows.end = next_rows.end;
11334                        selections_iter.next().unwrap();
11335                    } else {
11336                        break;
11337                    }
11338                }
11339
11340                // Copy the text from the selected row region and splice it either at the start
11341                // or end of the region.
11342                let start = Point::new(rows.start.0, 0);
11343                let end = Point::new(
11344                    rows.end.previous_row().0,
11345                    buffer.line_len(rows.end.previous_row()),
11346                );
11347                let text = buffer
11348                    .text_for_range(start..end)
11349                    .chain(Some("\n"))
11350                    .collect::<String>();
11351                let insert_location = if upwards {
11352                    Point::new(rows.end.0, 0)
11353                } else {
11354                    start
11355                };
11356                edits.push((insert_location..insert_location, text));
11357            } else {
11358                // duplicate character-wise
11359                let start = selection.start;
11360                let end = selection.end;
11361                let text = buffer.text_for_range(start..end).collect::<String>();
11362                edits.push((selection.end..selection.end, text));
11363            }
11364        }
11365
11366        self.transact(window, cx, |this, _, cx| {
11367            this.buffer.update(cx, |buffer, cx| {
11368                buffer.edit(edits, None, cx);
11369            });
11370
11371            this.request_autoscroll(Autoscroll::fit(), cx);
11372        });
11373    }
11374
11375    pub fn duplicate_line_up(
11376        &mut self,
11377        _: &DuplicateLineUp,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.duplicate(true, true, window, cx);
11382    }
11383
11384    pub fn duplicate_line_down(
11385        &mut self,
11386        _: &DuplicateLineDown,
11387        window: &mut Window,
11388        cx: &mut Context<Self>,
11389    ) {
11390        self.duplicate(false, true, window, cx);
11391    }
11392
11393    pub fn duplicate_selection(
11394        &mut self,
11395        _: &DuplicateSelection,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        self.duplicate(false, false, window, cx);
11400    }
11401
11402    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11403        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11404        if self.mode.is_single_line() {
11405            cx.propagate();
11406            return;
11407        }
11408
11409        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11410        let buffer = self.buffer.read(cx).snapshot(cx);
11411
11412        let mut edits = Vec::new();
11413        let mut unfold_ranges = Vec::new();
11414        let mut refold_creases = Vec::new();
11415
11416        let selections = self.selections.all::<Point>(cx);
11417        let mut selections = selections.iter().peekable();
11418        let mut contiguous_row_selections = Vec::new();
11419        let mut new_selections = Vec::new();
11420
11421        while let Some(selection) = selections.next() {
11422            // Find all the selections that span a contiguous row range
11423            let (start_row, end_row) = consume_contiguous_rows(
11424                &mut contiguous_row_selections,
11425                selection,
11426                &display_map,
11427                &mut selections,
11428            );
11429
11430            // Move the text spanned by the row range to be before the line preceding the row range
11431            if start_row.0 > 0 {
11432                let range_to_move = Point::new(
11433                    start_row.previous_row().0,
11434                    buffer.line_len(start_row.previous_row()),
11435                )
11436                    ..Point::new(
11437                        end_row.previous_row().0,
11438                        buffer.line_len(end_row.previous_row()),
11439                    );
11440                let insertion_point = display_map
11441                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11442                    .0;
11443
11444                // Don't move lines across excerpts
11445                if buffer
11446                    .excerpt_containing(insertion_point..range_to_move.end)
11447                    .is_some()
11448                {
11449                    let text = buffer
11450                        .text_for_range(range_to_move.clone())
11451                        .flat_map(|s| s.chars())
11452                        .skip(1)
11453                        .chain(['\n'])
11454                        .collect::<String>();
11455
11456                    edits.push((
11457                        buffer.anchor_after(range_to_move.start)
11458                            ..buffer.anchor_before(range_to_move.end),
11459                        String::new(),
11460                    ));
11461                    let insertion_anchor = buffer.anchor_after(insertion_point);
11462                    edits.push((insertion_anchor..insertion_anchor, text));
11463
11464                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11465
11466                    // Move selections up
11467                    new_selections.extend(contiguous_row_selections.drain(..).map(
11468                        |mut selection| {
11469                            selection.start.row -= row_delta;
11470                            selection.end.row -= row_delta;
11471                            selection
11472                        },
11473                    ));
11474
11475                    // Move folds up
11476                    unfold_ranges.push(range_to_move.clone());
11477                    for fold in display_map.folds_in_range(
11478                        buffer.anchor_before(range_to_move.start)
11479                            ..buffer.anchor_after(range_to_move.end),
11480                    ) {
11481                        let mut start = fold.range.start.to_point(&buffer);
11482                        let mut end = fold.range.end.to_point(&buffer);
11483                        start.row -= row_delta;
11484                        end.row -= row_delta;
11485                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11486                    }
11487                }
11488            }
11489
11490            // If we didn't move line(s), preserve the existing selections
11491            new_selections.append(&mut contiguous_row_selections);
11492        }
11493
11494        self.transact(window, cx, |this, window, cx| {
11495            this.unfold_ranges(&unfold_ranges, true, true, cx);
11496            this.buffer.update(cx, |buffer, cx| {
11497                for (range, text) in edits {
11498                    buffer.edit([(range, text)], None, cx);
11499                }
11500            });
11501            this.fold_creases(refold_creases, true, window, cx);
11502            this.change_selections(Default::default(), window, cx, |s| {
11503                s.select(new_selections);
11504            })
11505        });
11506    }
11507
11508    pub fn move_line_down(
11509        &mut self,
11510        _: &MoveLineDown,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) {
11514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11515        if self.mode.is_single_line() {
11516            cx.propagate();
11517            return;
11518        }
11519
11520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11521        let buffer = self.buffer.read(cx).snapshot(cx);
11522
11523        let mut edits = Vec::new();
11524        let mut unfold_ranges = Vec::new();
11525        let mut refold_creases = Vec::new();
11526
11527        let selections = self.selections.all::<Point>(cx);
11528        let mut selections = selections.iter().peekable();
11529        let mut contiguous_row_selections = Vec::new();
11530        let mut new_selections = Vec::new();
11531
11532        while let Some(selection) = selections.next() {
11533            // Find all the selections that span a contiguous row range
11534            let (start_row, end_row) = consume_contiguous_rows(
11535                &mut contiguous_row_selections,
11536                selection,
11537                &display_map,
11538                &mut selections,
11539            );
11540
11541            // Move the text spanned by the row range to be after the last line of the row range
11542            if end_row.0 <= buffer.max_point().row {
11543                let range_to_move =
11544                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11545                let insertion_point = display_map
11546                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11547                    .0;
11548
11549                // Don't move lines across excerpt boundaries
11550                if buffer
11551                    .excerpt_containing(range_to_move.start..insertion_point)
11552                    .is_some()
11553                {
11554                    let mut text = String::from("\n");
11555                    text.extend(buffer.text_for_range(range_to_move.clone()));
11556                    text.pop(); // Drop trailing newline
11557                    edits.push((
11558                        buffer.anchor_after(range_to_move.start)
11559                            ..buffer.anchor_before(range_to_move.end),
11560                        String::new(),
11561                    ));
11562                    let insertion_anchor = buffer.anchor_after(insertion_point);
11563                    edits.push((insertion_anchor..insertion_anchor, text));
11564
11565                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11566
11567                    // Move selections down
11568                    new_selections.extend(contiguous_row_selections.drain(..).map(
11569                        |mut selection| {
11570                            selection.start.row += row_delta;
11571                            selection.end.row += row_delta;
11572                            selection
11573                        },
11574                    ));
11575
11576                    // Move folds down
11577                    unfold_ranges.push(range_to_move.clone());
11578                    for fold in display_map.folds_in_range(
11579                        buffer.anchor_before(range_to_move.start)
11580                            ..buffer.anchor_after(range_to_move.end),
11581                    ) {
11582                        let mut start = fold.range.start.to_point(&buffer);
11583                        let mut end = fold.range.end.to_point(&buffer);
11584                        start.row += row_delta;
11585                        end.row += row_delta;
11586                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11587                    }
11588                }
11589            }
11590
11591            // If we didn't move line(s), preserve the existing selections
11592            new_selections.append(&mut contiguous_row_selections);
11593        }
11594
11595        self.transact(window, cx, |this, window, cx| {
11596            this.unfold_ranges(&unfold_ranges, true, true, cx);
11597            this.buffer.update(cx, |buffer, cx| {
11598                for (range, text) in edits {
11599                    buffer.edit([(range, text)], None, cx);
11600                }
11601            });
11602            this.fold_creases(refold_creases, true, window, cx);
11603            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11604        });
11605    }
11606
11607    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11609        let text_layout_details = &self.text_layout_details(window);
11610        self.transact(window, cx, |this, window, cx| {
11611            let edits = this.change_selections(Default::default(), window, cx, |s| {
11612                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11613                s.move_with(|display_map, selection| {
11614                    if !selection.is_empty() {
11615                        return;
11616                    }
11617
11618                    let mut head = selection.head();
11619                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11620                    if head.column() == display_map.line_len(head.row()) {
11621                        transpose_offset = display_map
11622                            .buffer_snapshot
11623                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11624                    }
11625
11626                    if transpose_offset == 0 {
11627                        return;
11628                    }
11629
11630                    *head.column_mut() += 1;
11631                    head = display_map.clip_point(head, Bias::Right);
11632                    let goal = SelectionGoal::HorizontalPosition(
11633                        display_map
11634                            .x_for_display_point(head, text_layout_details)
11635                            .into(),
11636                    );
11637                    selection.collapse_to(head, goal);
11638
11639                    let transpose_start = display_map
11640                        .buffer_snapshot
11641                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11642                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11643                        let transpose_end = display_map
11644                            .buffer_snapshot
11645                            .clip_offset(transpose_offset + 1, Bias::Right);
11646                        if let Some(ch) =
11647                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11648                        {
11649                            edits.push((transpose_start..transpose_offset, String::new()));
11650                            edits.push((transpose_end..transpose_end, ch.to_string()));
11651                        }
11652                    }
11653                });
11654                edits
11655            });
11656            this.buffer
11657                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11658            let selections = this.selections.all::<usize>(cx);
11659            this.change_selections(Default::default(), window, cx, |s| {
11660                s.select(selections);
11661            });
11662        });
11663    }
11664
11665    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11667        if self.mode.is_single_line() {
11668            cx.propagate();
11669            return;
11670        }
11671
11672        self.rewrap_impl(RewrapOptions::default(), cx)
11673    }
11674
11675    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11676        let buffer = self.buffer.read(cx).snapshot(cx);
11677        let selections = self.selections.all::<Point>(cx);
11678
11679        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11680        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11681            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11682                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11683                .peekable();
11684
11685            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11686                row
11687            } else {
11688                return Vec::new();
11689            };
11690
11691            let language_settings = buffer.language_settings_at(selection.head(), cx);
11692            let language_scope = buffer.language_scope_at(selection.head());
11693
11694            let indent_and_prefix_for_row =
11695                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11696                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11697                    let (comment_prefix, rewrap_prefix) =
11698                        if let Some(language_scope) = &language_scope {
11699                            let indent_end = Point::new(row, indent.len);
11700                            let comment_prefix = language_scope
11701                                .line_comment_prefixes()
11702                                .iter()
11703                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11704                                .map(|prefix| prefix.to_string());
11705                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11706                            let line_text_after_indent = buffer
11707                                .text_for_range(indent_end..line_end)
11708                                .collect::<String>();
11709                            let rewrap_prefix = language_scope
11710                                .rewrap_prefixes()
11711                                .iter()
11712                                .find_map(|prefix_regex| {
11713                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11714                                        if mat.start() == 0 {
11715                                            Some(mat.as_str().to_string())
11716                                        } else {
11717                                            None
11718                                        }
11719                                    })
11720                                })
11721                                .flatten();
11722                            (comment_prefix, rewrap_prefix)
11723                        } else {
11724                            (None, None)
11725                        };
11726                    (indent, comment_prefix, rewrap_prefix)
11727                };
11728
11729            let mut ranges = Vec::new();
11730            let from_empty_selection = selection.is_empty();
11731
11732            let mut current_range_start = first_row;
11733            let mut prev_row = first_row;
11734            let (
11735                mut current_range_indent,
11736                mut current_range_comment_prefix,
11737                mut current_range_rewrap_prefix,
11738            ) = indent_and_prefix_for_row(first_row);
11739
11740            for row in non_blank_rows_iter.skip(1) {
11741                let has_paragraph_break = row > prev_row + 1;
11742
11743                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11744                    indent_and_prefix_for_row(row);
11745
11746                let has_indent_change = row_indent != current_range_indent;
11747                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11748
11749                let has_boundary_change = has_comment_change
11750                    || row_rewrap_prefix.is_some()
11751                    || (has_indent_change && current_range_comment_prefix.is_some());
11752
11753                if has_paragraph_break || has_boundary_change {
11754                    ranges.push((
11755                        language_settings.clone(),
11756                        Point::new(current_range_start, 0)
11757                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11758                        current_range_indent,
11759                        current_range_comment_prefix.clone(),
11760                        current_range_rewrap_prefix.clone(),
11761                        from_empty_selection,
11762                    ));
11763                    current_range_start = row;
11764                    current_range_indent = row_indent;
11765                    current_range_comment_prefix = row_comment_prefix;
11766                    current_range_rewrap_prefix = row_rewrap_prefix;
11767                }
11768                prev_row = row;
11769            }
11770
11771            ranges.push((
11772                language_settings.clone(),
11773                Point::new(current_range_start, 0)
11774                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11775                current_range_indent,
11776                current_range_comment_prefix,
11777                current_range_rewrap_prefix,
11778                from_empty_selection,
11779            ));
11780
11781            ranges
11782        });
11783
11784        let mut edits = Vec::new();
11785        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11786
11787        for (
11788            language_settings,
11789            wrap_range,
11790            indent_size,
11791            comment_prefix,
11792            rewrap_prefix,
11793            from_empty_selection,
11794        ) in wrap_ranges
11795        {
11796            let mut start_row = wrap_range.start.row;
11797            let mut end_row = wrap_range.end.row;
11798
11799            // Skip selections that overlap with a range that has already been rewrapped.
11800            let selection_range = start_row..end_row;
11801            if rewrapped_row_ranges
11802                .iter()
11803                .any(|range| range.overlaps(&selection_range))
11804            {
11805                continue;
11806            }
11807
11808            let tab_size = language_settings.tab_size;
11809
11810            let indent_prefix = indent_size.chars().collect::<String>();
11811            let mut line_prefix = indent_prefix.clone();
11812            let mut inside_comment = false;
11813            if let Some(prefix) = &comment_prefix {
11814                line_prefix.push_str(prefix);
11815                inside_comment = true;
11816            }
11817            if let Some(prefix) = &rewrap_prefix {
11818                line_prefix.push_str(prefix);
11819            }
11820
11821            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11822                RewrapBehavior::InComments => inside_comment,
11823                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11824                RewrapBehavior::Anywhere => true,
11825            };
11826
11827            let should_rewrap = options.override_language_settings
11828                || allow_rewrap_based_on_language
11829                || self.hard_wrap.is_some();
11830            if !should_rewrap {
11831                continue;
11832            }
11833
11834            if from_empty_selection {
11835                'expand_upwards: while start_row > 0 {
11836                    let prev_row = start_row - 1;
11837                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11838                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11839                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11840                    {
11841                        start_row = prev_row;
11842                    } else {
11843                        break 'expand_upwards;
11844                    }
11845                }
11846
11847                'expand_downwards: while end_row < buffer.max_point().row {
11848                    let next_row = end_row + 1;
11849                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11850                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11851                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11852                    {
11853                        end_row = next_row;
11854                    } else {
11855                        break 'expand_downwards;
11856                    }
11857                }
11858            }
11859
11860            let start = Point::new(start_row, 0);
11861            let start_offset = start.to_offset(&buffer);
11862            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11863            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11864            let Some(lines_without_prefixes) = selection_text
11865                .lines()
11866                .enumerate()
11867                .map(|(ix, line)| {
11868                    let line_trimmed = line.trim_start();
11869                    if rewrap_prefix.is_some() && ix > 0 {
11870                        Ok(line_trimmed)
11871                    } else {
11872                        line_trimmed
11873                            .strip_prefix(&line_prefix.trim_start())
11874                            .with_context(|| {
11875                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11876                            })
11877                    }
11878                })
11879                .collect::<Result<Vec<_>, _>>()
11880                .log_err()
11881            else {
11882                continue;
11883            };
11884
11885            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11886                buffer
11887                    .language_settings_at(Point::new(start_row, 0), cx)
11888                    .preferred_line_length as usize
11889            });
11890
11891            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11892                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11893            } else {
11894                line_prefix.clone()
11895            };
11896
11897            let wrapped_text = wrap_with_prefix(
11898                line_prefix,
11899                subsequent_lines_prefix,
11900                lines_without_prefixes.join("\n"),
11901                wrap_column,
11902                tab_size,
11903                options.preserve_existing_whitespace,
11904            );
11905
11906            // TODO: should always use char-based diff while still supporting cursor behavior that
11907            // matches vim.
11908            let mut diff_options = DiffOptions::default();
11909            if options.override_language_settings {
11910                diff_options.max_word_diff_len = 0;
11911                diff_options.max_word_diff_line_count = 0;
11912            } else {
11913                diff_options.max_word_diff_len = usize::MAX;
11914                diff_options.max_word_diff_line_count = usize::MAX;
11915            }
11916
11917            for (old_range, new_text) in
11918                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11919            {
11920                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11921                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11922                edits.push((edit_start..edit_end, new_text));
11923            }
11924
11925            rewrapped_row_ranges.push(start_row..=end_row);
11926        }
11927
11928        self.buffer
11929            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11930    }
11931
11932    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11933        let mut text = String::new();
11934        let buffer = self.buffer.read(cx).snapshot(cx);
11935        let mut selections = self.selections.all::<Point>(cx);
11936        let mut clipboard_selections = Vec::with_capacity(selections.len());
11937        {
11938            let max_point = buffer.max_point();
11939            let mut is_first = true;
11940            for selection in &mut selections {
11941                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11942                if is_entire_line {
11943                    selection.start = Point::new(selection.start.row, 0);
11944                    if !selection.is_empty() && selection.end.column == 0 {
11945                        selection.end = cmp::min(max_point, selection.end);
11946                    } else {
11947                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11948                    }
11949                    selection.goal = SelectionGoal::None;
11950                }
11951                if is_first {
11952                    is_first = false;
11953                } else {
11954                    text += "\n";
11955                }
11956                let mut len = 0;
11957                for chunk in buffer.text_for_range(selection.start..selection.end) {
11958                    text.push_str(chunk);
11959                    len += chunk.len();
11960                }
11961                clipboard_selections.push(ClipboardSelection {
11962                    len,
11963                    is_entire_line,
11964                    first_line_indent: buffer
11965                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11966                        .len,
11967                });
11968            }
11969        }
11970
11971        self.transact(window, cx, |this, window, cx| {
11972            this.change_selections(Default::default(), window, cx, |s| {
11973                s.select(selections);
11974            });
11975            this.insert("", window, cx);
11976        });
11977        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11978    }
11979
11980    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11981        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11982        let item = self.cut_common(window, cx);
11983        cx.write_to_clipboard(item);
11984    }
11985
11986    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11988        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11989            s.move_with(|snapshot, sel| {
11990                if sel.is_empty() {
11991                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11992                }
11993            });
11994        });
11995        let item = self.cut_common(window, cx);
11996        cx.set_global(KillRing(item))
11997    }
11998
11999    pub fn kill_ring_yank(
12000        &mut self,
12001        _: &KillRingYank,
12002        window: &mut Window,
12003        cx: &mut Context<Self>,
12004    ) {
12005        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12006        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12007            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12008                (kill_ring.text().to_string(), kill_ring.metadata_json())
12009            } else {
12010                return;
12011            }
12012        } else {
12013            return;
12014        };
12015        self.do_paste(&text, metadata, false, window, cx);
12016    }
12017
12018    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12019        self.do_copy(true, cx);
12020    }
12021
12022    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12023        self.do_copy(false, cx);
12024    }
12025
12026    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12027        let selections = self.selections.all::<Point>(cx);
12028        let buffer = self.buffer.read(cx).read(cx);
12029        let mut text = String::new();
12030
12031        let mut clipboard_selections = Vec::with_capacity(selections.len());
12032        {
12033            let max_point = buffer.max_point();
12034            let mut is_first = true;
12035            for selection in &selections {
12036                let mut start = selection.start;
12037                let mut end = selection.end;
12038                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12039                if is_entire_line {
12040                    start = Point::new(start.row, 0);
12041                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12042                }
12043
12044                let mut trimmed_selections = Vec::new();
12045                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12046                    let row = MultiBufferRow(start.row);
12047                    let first_indent = buffer.indent_size_for_line(row);
12048                    if first_indent.len == 0 || start.column > first_indent.len {
12049                        trimmed_selections.push(start..end);
12050                    } else {
12051                        trimmed_selections.push(
12052                            Point::new(row.0, first_indent.len)
12053                                ..Point::new(row.0, buffer.line_len(row)),
12054                        );
12055                        for row in start.row + 1..=end.row {
12056                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12057                            if row == end.row {
12058                                line_len = end.column;
12059                            }
12060                            if line_len == 0 {
12061                                trimmed_selections
12062                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12063                                continue;
12064                            }
12065                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12066                            if row_indent_size.len >= first_indent.len {
12067                                trimmed_selections.push(
12068                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12069                                );
12070                            } else {
12071                                trimmed_selections.clear();
12072                                trimmed_selections.push(start..end);
12073                                break;
12074                            }
12075                        }
12076                    }
12077                } else {
12078                    trimmed_selections.push(start..end);
12079                }
12080
12081                for trimmed_range in trimmed_selections {
12082                    if is_first {
12083                        is_first = false;
12084                    } else {
12085                        text += "\n";
12086                    }
12087                    let mut len = 0;
12088                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12089                        text.push_str(chunk);
12090                        len += chunk.len();
12091                    }
12092                    clipboard_selections.push(ClipboardSelection {
12093                        len,
12094                        is_entire_line,
12095                        first_line_indent: buffer
12096                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12097                            .len,
12098                    });
12099                }
12100            }
12101        }
12102
12103        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12104            text,
12105            clipboard_selections,
12106        ));
12107    }
12108
12109    pub fn do_paste(
12110        &mut self,
12111        text: &String,
12112        clipboard_selections: Option<Vec<ClipboardSelection>>,
12113        handle_entire_lines: bool,
12114        window: &mut Window,
12115        cx: &mut Context<Self>,
12116    ) {
12117        if self.read_only(cx) {
12118            return;
12119        }
12120
12121        let clipboard_text = Cow::Borrowed(text);
12122
12123        self.transact(window, cx, |this, window, cx| {
12124            if let Some(mut clipboard_selections) = clipboard_selections {
12125                let old_selections = this.selections.all::<usize>(cx);
12126                let all_selections_were_entire_line =
12127                    clipboard_selections.iter().all(|s| s.is_entire_line);
12128                let first_selection_indent_column =
12129                    clipboard_selections.first().map(|s| s.first_line_indent);
12130                if clipboard_selections.len() != old_selections.len() {
12131                    clipboard_selections.drain(..);
12132                }
12133                let cursor_offset = this.selections.last::<usize>(cx).head();
12134                let mut auto_indent_on_paste = true;
12135
12136                this.buffer.update(cx, |buffer, cx| {
12137                    let snapshot = buffer.read(cx);
12138                    auto_indent_on_paste = snapshot
12139                        .language_settings_at(cursor_offset, cx)
12140                        .auto_indent_on_paste;
12141
12142                    let mut start_offset = 0;
12143                    let mut edits = Vec::new();
12144                    let mut original_indent_columns = Vec::new();
12145                    for (ix, selection) in old_selections.iter().enumerate() {
12146                        let to_insert;
12147                        let entire_line;
12148                        let original_indent_column;
12149                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12150                            let end_offset = start_offset + clipboard_selection.len;
12151                            to_insert = &clipboard_text[start_offset..end_offset];
12152                            entire_line = clipboard_selection.is_entire_line;
12153                            start_offset = end_offset + 1;
12154                            original_indent_column = Some(clipboard_selection.first_line_indent);
12155                        } else {
12156                            to_insert = clipboard_text.as_str();
12157                            entire_line = all_selections_were_entire_line;
12158                            original_indent_column = first_selection_indent_column
12159                        }
12160
12161                        // If the corresponding selection was empty when this slice of the
12162                        // clipboard text was written, then the entire line containing the
12163                        // selection was copied. If this selection is also currently empty,
12164                        // then paste the line before the current line of the buffer.
12165                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12166                            let column = selection.start.to_point(&snapshot).column as usize;
12167                            let line_start = selection.start - column;
12168                            line_start..line_start
12169                        } else {
12170                            selection.range()
12171                        };
12172
12173                        edits.push((range, to_insert));
12174                        original_indent_columns.push(original_indent_column);
12175                    }
12176                    drop(snapshot);
12177
12178                    buffer.edit(
12179                        edits,
12180                        if auto_indent_on_paste {
12181                            Some(AutoindentMode::Block {
12182                                original_indent_columns,
12183                            })
12184                        } else {
12185                            None
12186                        },
12187                        cx,
12188                    );
12189                });
12190
12191                let selections = this.selections.all::<usize>(cx);
12192                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12193            } else {
12194                this.insert(&clipboard_text, window, cx);
12195            }
12196        });
12197    }
12198
12199    pub fn diff_clipboard_with_selection(
12200        &mut self,
12201        _: &DiffClipboardWithSelection,
12202        window: &mut Window,
12203        cx: &mut Context<Self>,
12204    ) {
12205        let selections = self.selections.all::<usize>(cx);
12206
12207        if selections.is_empty() {
12208            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12209            return;
12210        };
12211
12212        let clipboard_text = match cx.read_from_clipboard() {
12213            Some(item) => match item.entries().first() {
12214                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12215                _ => None,
12216            },
12217            None => None,
12218        };
12219
12220        let Some(clipboard_text) = clipboard_text else {
12221            log::warn!("Clipboard doesn't contain text.");
12222            return;
12223        };
12224
12225        window.dispatch_action(
12226            Box::new(DiffClipboardWithSelectionData {
12227                clipboard_text,
12228                editor: cx.entity(),
12229            }),
12230            cx,
12231        );
12232    }
12233
12234    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12236        if let Some(item) = cx.read_from_clipboard() {
12237            let entries = item.entries();
12238
12239            match entries.first() {
12240                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12241                // of all the pasted entries.
12242                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12243                    .do_paste(
12244                        clipboard_string.text(),
12245                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12246                        true,
12247                        window,
12248                        cx,
12249                    ),
12250                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12251            }
12252        }
12253    }
12254
12255    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12256        if self.read_only(cx) {
12257            return;
12258        }
12259
12260        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12261
12262        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12263            if let Some((selections, _)) =
12264                self.selection_history.transaction(transaction_id).cloned()
12265            {
12266                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12267                    s.select_anchors(selections.to_vec());
12268                });
12269            } else {
12270                log::error!(
12271                    "No entry in selection_history found for undo. \
12272                     This may correspond to a bug where undo does not update the selection. \
12273                     If this is occurring, please add details to \
12274                     https://github.com/zed-industries/zed/issues/22692"
12275                );
12276            }
12277            self.request_autoscroll(Autoscroll::fit(), cx);
12278            self.unmark_text(window, cx);
12279            self.refresh_edit_prediction(true, false, window, cx);
12280            cx.emit(EditorEvent::Edited { transaction_id });
12281            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12282        }
12283    }
12284
12285    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12286        if self.read_only(cx) {
12287            return;
12288        }
12289
12290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12291
12292        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12293            if let Some((_, Some(selections))) =
12294                self.selection_history.transaction(transaction_id).cloned()
12295            {
12296                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12297                    s.select_anchors(selections.to_vec());
12298                });
12299            } else {
12300                log::error!(
12301                    "No entry in selection_history found for redo. \
12302                     This may correspond to a bug where undo does not update the selection. \
12303                     If this is occurring, please add details to \
12304                     https://github.com/zed-industries/zed/issues/22692"
12305                );
12306            }
12307            self.request_autoscroll(Autoscroll::fit(), cx);
12308            self.unmark_text(window, cx);
12309            self.refresh_edit_prediction(true, false, window, cx);
12310            cx.emit(EditorEvent::Edited { transaction_id });
12311        }
12312    }
12313
12314    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12315        self.buffer
12316            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12317    }
12318
12319    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12320        self.buffer
12321            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12322    }
12323
12324    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12325        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12326        self.change_selections(Default::default(), window, cx, |s| {
12327            s.move_with(|map, selection| {
12328                let cursor = if selection.is_empty() {
12329                    movement::left(map, selection.start)
12330                } else {
12331                    selection.start
12332                };
12333                selection.collapse_to(cursor, SelectionGoal::None);
12334            });
12335        })
12336    }
12337
12338    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12340        self.change_selections(Default::default(), window, cx, |s| {
12341            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12342        })
12343    }
12344
12345    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12346        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12347        self.change_selections(Default::default(), window, cx, |s| {
12348            s.move_with(|map, selection| {
12349                let cursor = if selection.is_empty() {
12350                    movement::right(map, selection.end)
12351                } else {
12352                    selection.end
12353                };
12354                selection.collapse_to(cursor, SelectionGoal::None)
12355            });
12356        })
12357    }
12358
12359    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12361        self.change_selections(Default::default(), window, cx, |s| {
12362            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12363        })
12364    }
12365
12366    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12367        if self.take_rename(true, window, cx).is_some() {
12368            return;
12369        }
12370
12371        if self.mode.is_single_line() {
12372            cx.propagate();
12373            return;
12374        }
12375
12376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12377
12378        let text_layout_details = &self.text_layout_details(window);
12379        let selection_count = self.selections.count();
12380        let first_selection = self.selections.first_anchor();
12381
12382        self.change_selections(Default::default(), window, cx, |s| {
12383            s.move_with(|map, selection| {
12384                if !selection.is_empty() {
12385                    selection.goal = SelectionGoal::None;
12386                }
12387                let (cursor, goal) = movement::up(
12388                    map,
12389                    selection.start,
12390                    selection.goal,
12391                    false,
12392                    text_layout_details,
12393                );
12394                selection.collapse_to(cursor, goal);
12395            });
12396        });
12397
12398        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12399        {
12400            cx.propagate();
12401        }
12402    }
12403
12404    pub fn move_up_by_lines(
12405        &mut self,
12406        action: &MoveUpByLines,
12407        window: &mut Window,
12408        cx: &mut Context<Self>,
12409    ) {
12410        if self.take_rename(true, window, cx).is_some() {
12411            return;
12412        }
12413
12414        if self.mode.is_single_line() {
12415            cx.propagate();
12416            return;
12417        }
12418
12419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12420
12421        let text_layout_details = &self.text_layout_details(window);
12422
12423        self.change_selections(Default::default(), window, cx, |s| {
12424            s.move_with(|map, selection| {
12425                if !selection.is_empty() {
12426                    selection.goal = SelectionGoal::None;
12427                }
12428                let (cursor, goal) = movement::up_by_rows(
12429                    map,
12430                    selection.start,
12431                    action.lines,
12432                    selection.goal,
12433                    false,
12434                    text_layout_details,
12435                );
12436                selection.collapse_to(cursor, goal);
12437            });
12438        })
12439    }
12440
12441    pub fn move_down_by_lines(
12442        &mut self,
12443        action: &MoveDownByLines,
12444        window: &mut Window,
12445        cx: &mut Context<Self>,
12446    ) {
12447        if self.take_rename(true, window, cx).is_some() {
12448            return;
12449        }
12450
12451        if self.mode.is_single_line() {
12452            cx.propagate();
12453            return;
12454        }
12455
12456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12457
12458        let text_layout_details = &self.text_layout_details(window);
12459
12460        self.change_selections(Default::default(), window, cx, |s| {
12461            s.move_with(|map, selection| {
12462                if !selection.is_empty() {
12463                    selection.goal = SelectionGoal::None;
12464                }
12465                let (cursor, goal) = movement::down_by_rows(
12466                    map,
12467                    selection.start,
12468                    action.lines,
12469                    selection.goal,
12470                    false,
12471                    text_layout_details,
12472                );
12473                selection.collapse_to(cursor, goal);
12474            });
12475        })
12476    }
12477
12478    pub fn select_down_by_lines(
12479        &mut self,
12480        action: &SelectDownByLines,
12481        window: &mut Window,
12482        cx: &mut Context<Self>,
12483    ) {
12484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12485        let text_layout_details = &self.text_layout_details(window);
12486        self.change_selections(Default::default(), window, cx, |s| {
12487            s.move_heads_with(|map, head, goal| {
12488                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12489            })
12490        })
12491    }
12492
12493    pub fn select_up_by_lines(
12494        &mut self,
12495        action: &SelectUpByLines,
12496        window: &mut Window,
12497        cx: &mut Context<Self>,
12498    ) {
12499        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12500        let text_layout_details = &self.text_layout_details(window);
12501        self.change_selections(Default::default(), window, cx, |s| {
12502            s.move_heads_with(|map, head, goal| {
12503                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12504            })
12505        })
12506    }
12507
12508    pub fn select_page_up(
12509        &mut self,
12510        _: &SelectPageUp,
12511        window: &mut Window,
12512        cx: &mut Context<Self>,
12513    ) {
12514        let Some(row_count) = self.visible_row_count() else {
12515            return;
12516        };
12517
12518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12519
12520        let text_layout_details = &self.text_layout_details(window);
12521
12522        self.change_selections(Default::default(), window, cx, |s| {
12523            s.move_heads_with(|map, head, goal| {
12524                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12525            })
12526        })
12527    }
12528
12529    pub fn move_page_up(
12530        &mut self,
12531        action: &MovePageUp,
12532        window: &mut Window,
12533        cx: &mut Context<Self>,
12534    ) {
12535        if self.take_rename(true, window, cx).is_some() {
12536            return;
12537        }
12538
12539        if self
12540            .context_menu
12541            .borrow_mut()
12542            .as_mut()
12543            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12544            .unwrap_or(false)
12545        {
12546            return;
12547        }
12548
12549        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12550            cx.propagate();
12551            return;
12552        }
12553
12554        let Some(row_count) = self.visible_row_count() else {
12555            return;
12556        };
12557
12558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12559
12560        let effects = if action.center_cursor {
12561            SelectionEffects::scroll(Autoscroll::center())
12562        } else {
12563            SelectionEffects::default()
12564        };
12565
12566        let text_layout_details = &self.text_layout_details(window);
12567
12568        self.change_selections(effects, window, cx, |s| {
12569            s.move_with(|map, selection| {
12570                if !selection.is_empty() {
12571                    selection.goal = SelectionGoal::None;
12572                }
12573                let (cursor, goal) = movement::up_by_rows(
12574                    map,
12575                    selection.end,
12576                    row_count,
12577                    selection.goal,
12578                    false,
12579                    text_layout_details,
12580                );
12581                selection.collapse_to(cursor, goal);
12582            });
12583        });
12584    }
12585
12586    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12588        let text_layout_details = &self.text_layout_details(window);
12589        self.change_selections(Default::default(), window, cx, |s| {
12590            s.move_heads_with(|map, head, goal| {
12591                movement::up(map, head, goal, false, text_layout_details)
12592            })
12593        })
12594    }
12595
12596    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12597        self.take_rename(true, window, cx);
12598
12599        if self.mode.is_single_line() {
12600            cx.propagate();
12601            return;
12602        }
12603
12604        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12605
12606        let text_layout_details = &self.text_layout_details(window);
12607        let selection_count = self.selections.count();
12608        let first_selection = self.selections.first_anchor();
12609
12610        self.change_selections(Default::default(), window, cx, |s| {
12611            s.move_with(|map, selection| {
12612                if !selection.is_empty() {
12613                    selection.goal = SelectionGoal::None;
12614                }
12615                let (cursor, goal) = movement::down(
12616                    map,
12617                    selection.end,
12618                    selection.goal,
12619                    false,
12620                    text_layout_details,
12621                );
12622                selection.collapse_to(cursor, goal);
12623            });
12624        });
12625
12626        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12627        {
12628            cx.propagate();
12629        }
12630    }
12631
12632    pub fn select_page_down(
12633        &mut self,
12634        _: &SelectPageDown,
12635        window: &mut Window,
12636        cx: &mut Context<Self>,
12637    ) {
12638        let Some(row_count) = self.visible_row_count() else {
12639            return;
12640        };
12641
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12643
12644        let text_layout_details = &self.text_layout_details(window);
12645
12646        self.change_selections(Default::default(), window, cx, |s| {
12647            s.move_heads_with(|map, head, goal| {
12648                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12649            })
12650        })
12651    }
12652
12653    pub fn move_page_down(
12654        &mut self,
12655        action: &MovePageDown,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658    ) {
12659        if self.take_rename(true, window, cx).is_some() {
12660            return;
12661        }
12662
12663        if self
12664            .context_menu
12665            .borrow_mut()
12666            .as_mut()
12667            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12668            .unwrap_or(false)
12669        {
12670            return;
12671        }
12672
12673        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12674            cx.propagate();
12675            return;
12676        }
12677
12678        let Some(row_count) = self.visible_row_count() else {
12679            return;
12680        };
12681
12682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12683
12684        let effects = if action.center_cursor {
12685            SelectionEffects::scroll(Autoscroll::center())
12686        } else {
12687            SelectionEffects::default()
12688        };
12689
12690        let text_layout_details = &self.text_layout_details(window);
12691        self.change_selections(effects, window, cx, |s| {
12692            s.move_with(|map, selection| {
12693                if !selection.is_empty() {
12694                    selection.goal = SelectionGoal::None;
12695                }
12696                let (cursor, goal) = movement::down_by_rows(
12697                    map,
12698                    selection.end,
12699                    row_count,
12700                    selection.goal,
12701                    false,
12702                    text_layout_details,
12703                );
12704                selection.collapse_to(cursor, goal);
12705            });
12706        });
12707    }
12708
12709    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12711        let text_layout_details = &self.text_layout_details(window);
12712        self.change_selections(Default::default(), window, cx, |s| {
12713            s.move_heads_with(|map, head, goal| {
12714                movement::down(map, head, goal, false, text_layout_details)
12715            })
12716        });
12717    }
12718
12719    pub fn context_menu_first(
12720        &mut self,
12721        _: &ContextMenuFirst,
12722        window: &mut Window,
12723        cx: &mut Context<Self>,
12724    ) {
12725        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12726            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12727        }
12728    }
12729
12730    pub fn context_menu_prev(
12731        &mut self,
12732        _: &ContextMenuPrevious,
12733        window: &mut Window,
12734        cx: &mut Context<Self>,
12735    ) {
12736        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12737            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12738        }
12739    }
12740
12741    pub fn context_menu_next(
12742        &mut self,
12743        _: &ContextMenuNext,
12744        window: &mut Window,
12745        cx: &mut Context<Self>,
12746    ) {
12747        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12748            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12749        }
12750    }
12751
12752    pub fn context_menu_last(
12753        &mut self,
12754        _: &ContextMenuLast,
12755        window: &mut Window,
12756        cx: &mut Context<Self>,
12757    ) {
12758        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12759            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12760        }
12761    }
12762
12763    pub fn signature_help_prev(
12764        &mut self,
12765        _: &SignatureHelpPrevious,
12766        _: &mut Window,
12767        cx: &mut Context<Self>,
12768    ) {
12769        if let Some(popover) = self.signature_help_state.popover_mut() {
12770            if popover.current_signature == 0 {
12771                popover.current_signature = popover.signatures.len() - 1;
12772            } else {
12773                popover.current_signature -= 1;
12774            }
12775            cx.notify();
12776        }
12777    }
12778
12779    pub fn signature_help_next(
12780        &mut self,
12781        _: &SignatureHelpNext,
12782        _: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if let Some(popover) = self.signature_help_state.popover_mut() {
12786            if popover.current_signature + 1 == popover.signatures.len() {
12787                popover.current_signature = 0;
12788            } else {
12789                popover.current_signature += 1;
12790            }
12791            cx.notify();
12792        }
12793    }
12794
12795    pub fn move_to_previous_word_start(
12796        &mut self,
12797        _: &MoveToPreviousWordStart,
12798        window: &mut Window,
12799        cx: &mut Context<Self>,
12800    ) {
12801        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12802        self.change_selections(Default::default(), window, cx, |s| {
12803            s.move_cursors_with(|map, head, _| {
12804                (
12805                    movement::previous_word_start(map, head),
12806                    SelectionGoal::None,
12807                )
12808            });
12809        })
12810    }
12811
12812    pub fn move_to_previous_subword_start(
12813        &mut self,
12814        _: &MoveToPreviousSubwordStart,
12815        window: &mut Window,
12816        cx: &mut Context<Self>,
12817    ) {
12818        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12819        self.change_selections(Default::default(), window, cx, |s| {
12820            s.move_cursors_with(|map, head, _| {
12821                (
12822                    movement::previous_subword_start(map, head),
12823                    SelectionGoal::None,
12824                )
12825            });
12826        })
12827    }
12828
12829    pub fn select_to_previous_word_start(
12830        &mut self,
12831        _: &SelectToPreviousWordStart,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) {
12835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12836        self.change_selections(Default::default(), window, cx, |s| {
12837            s.move_heads_with(|map, head, _| {
12838                (
12839                    movement::previous_word_start(map, head),
12840                    SelectionGoal::None,
12841                )
12842            });
12843        })
12844    }
12845
12846    pub fn select_to_previous_subword_start(
12847        &mut self,
12848        _: &SelectToPreviousSubwordStart,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12853        self.change_selections(Default::default(), window, cx, |s| {
12854            s.move_heads_with(|map, head, _| {
12855                (
12856                    movement::previous_subword_start(map, head),
12857                    SelectionGoal::None,
12858                )
12859            });
12860        })
12861    }
12862
12863    pub fn delete_to_previous_word_start(
12864        &mut self,
12865        action: &DeleteToPreviousWordStart,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12870        self.transact(window, cx, |this, window, cx| {
12871            this.select_autoclose_pair(window, cx);
12872            this.change_selections(Default::default(), window, cx, |s| {
12873                s.move_with(|map, selection| {
12874                    if selection.is_empty() {
12875                        let cursor = if action.ignore_newlines {
12876                            movement::previous_word_start(map, selection.head())
12877                        } else {
12878                            movement::previous_word_start_or_newline(map, selection.head())
12879                        };
12880                        selection.set_head(cursor, SelectionGoal::None);
12881                    }
12882                });
12883            });
12884            this.insert("", window, cx);
12885        });
12886    }
12887
12888    pub fn delete_to_previous_subword_start(
12889        &mut self,
12890        _: &DeleteToPreviousSubwordStart,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12895        self.transact(window, cx, |this, window, cx| {
12896            this.select_autoclose_pair(window, cx);
12897            this.change_selections(Default::default(), window, cx, |s| {
12898                s.move_with(|map, selection| {
12899                    if selection.is_empty() {
12900                        let cursor = movement::previous_subword_start(map, selection.head());
12901                        selection.set_head(cursor, SelectionGoal::None);
12902                    }
12903                });
12904            });
12905            this.insert("", window, cx);
12906        });
12907    }
12908
12909    pub fn move_to_next_word_end(
12910        &mut self,
12911        _: &MoveToNextWordEnd,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12916        self.change_selections(Default::default(), window, cx, |s| {
12917            s.move_cursors_with(|map, head, _| {
12918                (movement::next_word_end(map, head), SelectionGoal::None)
12919            });
12920        })
12921    }
12922
12923    pub fn move_to_next_subword_end(
12924        &mut self,
12925        _: &MoveToNextSubwordEnd,
12926        window: &mut Window,
12927        cx: &mut Context<Self>,
12928    ) {
12929        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12930        self.change_selections(Default::default(), window, cx, |s| {
12931            s.move_cursors_with(|map, head, _| {
12932                (movement::next_subword_end(map, head), SelectionGoal::None)
12933            });
12934        })
12935    }
12936
12937    pub fn select_to_next_word_end(
12938        &mut self,
12939        _: &SelectToNextWordEnd,
12940        window: &mut Window,
12941        cx: &mut Context<Self>,
12942    ) {
12943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12944        self.change_selections(Default::default(), window, cx, |s| {
12945            s.move_heads_with(|map, head, _| {
12946                (movement::next_word_end(map, head), SelectionGoal::None)
12947            });
12948        })
12949    }
12950
12951    pub fn select_to_next_subword_end(
12952        &mut self,
12953        _: &SelectToNextSubwordEnd,
12954        window: &mut Window,
12955        cx: &mut Context<Self>,
12956    ) {
12957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12958        self.change_selections(Default::default(), window, cx, |s| {
12959            s.move_heads_with(|map, head, _| {
12960                (movement::next_subword_end(map, head), SelectionGoal::None)
12961            });
12962        })
12963    }
12964
12965    pub fn delete_to_next_word_end(
12966        &mut self,
12967        action: &DeleteToNextWordEnd,
12968        window: &mut Window,
12969        cx: &mut Context<Self>,
12970    ) {
12971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12972        self.transact(window, cx, |this, window, cx| {
12973            this.change_selections(Default::default(), window, cx, |s| {
12974                s.move_with(|map, selection| {
12975                    if selection.is_empty() {
12976                        let cursor = if action.ignore_newlines {
12977                            movement::next_word_end(map, selection.head())
12978                        } else {
12979                            movement::next_word_end_or_newline(map, selection.head())
12980                        };
12981                        selection.set_head(cursor, SelectionGoal::None);
12982                    }
12983                });
12984            });
12985            this.insert("", window, cx);
12986        });
12987    }
12988
12989    pub fn delete_to_next_subword_end(
12990        &mut self,
12991        _: &DeleteToNextSubwordEnd,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12996        self.transact(window, cx, |this, window, cx| {
12997            this.change_selections(Default::default(), window, cx, |s| {
12998                s.move_with(|map, selection| {
12999                    if selection.is_empty() {
13000                        let cursor = movement::next_subword_end(map, selection.head());
13001                        selection.set_head(cursor, SelectionGoal::None);
13002                    }
13003                });
13004            });
13005            this.insert("", window, cx);
13006        });
13007    }
13008
13009    pub fn move_to_beginning_of_line(
13010        &mut self,
13011        action: &MoveToBeginningOfLine,
13012        window: &mut Window,
13013        cx: &mut Context<Self>,
13014    ) {
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016        self.change_selections(Default::default(), window, cx, |s| {
13017            s.move_cursors_with(|map, head, _| {
13018                (
13019                    movement::indented_line_beginning(
13020                        map,
13021                        head,
13022                        action.stop_at_soft_wraps,
13023                        action.stop_at_indent,
13024                    ),
13025                    SelectionGoal::None,
13026                )
13027            });
13028        })
13029    }
13030
13031    pub fn select_to_beginning_of_line(
13032        &mut self,
13033        action: &SelectToBeginningOfLine,
13034        window: &mut Window,
13035        cx: &mut Context<Self>,
13036    ) {
13037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13038        self.change_selections(Default::default(), window, cx, |s| {
13039            s.move_heads_with(|map, head, _| {
13040                (
13041                    movement::indented_line_beginning(
13042                        map,
13043                        head,
13044                        action.stop_at_soft_wraps,
13045                        action.stop_at_indent,
13046                    ),
13047                    SelectionGoal::None,
13048                )
13049            });
13050        });
13051    }
13052
13053    pub fn delete_to_beginning_of_line(
13054        &mut self,
13055        action: &DeleteToBeginningOfLine,
13056        window: &mut Window,
13057        cx: &mut Context<Self>,
13058    ) {
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13060        self.transact(window, cx, |this, window, cx| {
13061            this.change_selections(Default::default(), window, cx, |s| {
13062                s.move_with(|_, selection| {
13063                    selection.reversed = true;
13064                });
13065            });
13066
13067            this.select_to_beginning_of_line(
13068                &SelectToBeginningOfLine {
13069                    stop_at_soft_wraps: false,
13070                    stop_at_indent: action.stop_at_indent,
13071                },
13072                window,
13073                cx,
13074            );
13075            this.backspace(&Backspace, window, cx);
13076        });
13077    }
13078
13079    pub fn move_to_end_of_line(
13080        &mut self,
13081        action: &MoveToEndOfLine,
13082        window: &mut Window,
13083        cx: &mut Context<Self>,
13084    ) {
13085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_cursors_with(|map, head, _| {
13088                (
13089                    movement::line_end(map, head, action.stop_at_soft_wraps),
13090                    SelectionGoal::None,
13091                )
13092            });
13093        })
13094    }
13095
13096    pub fn select_to_end_of_line(
13097        &mut self,
13098        action: &SelectToEndOfLine,
13099        window: &mut Window,
13100        cx: &mut Context<Self>,
13101    ) {
13102        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13103        self.change_selections(Default::default(), window, cx, |s| {
13104            s.move_heads_with(|map, head, _| {
13105                (
13106                    movement::line_end(map, head, action.stop_at_soft_wraps),
13107                    SelectionGoal::None,
13108                )
13109            });
13110        })
13111    }
13112
13113    pub fn delete_to_end_of_line(
13114        &mut self,
13115        _: &DeleteToEndOfLine,
13116        window: &mut Window,
13117        cx: &mut Context<Self>,
13118    ) {
13119        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13120        self.transact(window, cx, |this, window, cx| {
13121            this.select_to_end_of_line(
13122                &SelectToEndOfLine {
13123                    stop_at_soft_wraps: false,
13124                },
13125                window,
13126                cx,
13127            );
13128            this.delete(&Delete, window, cx);
13129        });
13130    }
13131
13132    pub fn cut_to_end_of_line(
13133        &mut self,
13134        _: &CutToEndOfLine,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13139        self.transact(window, cx, |this, window, cx| {
13140            this.select_to_end_of_line(
13141                &SelectToEndOfLine {
13142                    stop_at_soft_wraps: false,
13143                },
13144                window,
13145                cx,
13146            );
13147            this.cut(&Cut, window, cx);
13148        });
13149    }
13150
13151    pub fn move_to_start_of_paragraph(
13152        &mut self,
13153        _: &MoveToStartOfParagraph,
13154        window: &mut Window,
13155        cx: &mut Context<Self>,
13156    ) {
13157        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13158            cx.propagate();
13159            return;
13160        }
13161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13162        self.change_selections(Default::default(), window, cx, |s| {
13163            s.move_with(|map, selection| {
13164                selection.collapse_to(
13165                    movement::start_of_paragraph(map, selection.head(), 1),
13166                    SelectionGoal::None,
13167                )
13168            });
13169        })
13170    }
13171
13172    pub fn move_to_end_of_paragraph(
13173        &mut self,
13174        _: &MoveToEndOfParagraph,
13175        window: &mut Window,
13176        cx: &mut Context<Self>,
13177    ) {
13178        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13179            cx.propagate();
13180            return;
13181        }
13182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13183        self.change_selections(Default::default(), window, cx, |s| {
13184            s.move_with(|map, selection| {
13185                selection.collapse_to(
13186                    movement::end_of_paragraph(map, selection.head(), 1),
13187                    SelectionGoal::None,
13188                )
13189            });
13190        })
13191    }
13192
13193    pub fn select_to_start_of_paragraph(
13194        &mut self,
13195        _: &SelectToStartOfParagraph,
13196        window: &mut Window,
13197        cx: &mut Context<Self>,
13198    ) {
13199        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13200            cx.propagate();
13201            return;
13202        }
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204        self.change_selections(Default::default(), window, cx, |s| {
13205            s.move_heads_with(|map, head, _| {
13206                (
13207                    movement::start_of_paragraph(map, head, 1),
13208                    SelectionGoal::None,
13209                )
13210            });
13211        })
13212    }
13213
13214    pub fn select_to_end_of_paragraph(
13215        &mut self,
13216        _: &SelectToEndOfParagraph,
13217        window: &mut Window,
13218        cx: &mut Context<Self>,
13219    ) {
13220        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13221            cx.propagate();
13222            return;
13223        }
13224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13225        self.change_selections(Default::default(), window, cx, |s| {
13226            s.move_heads_with(|map, head, _| {
13227                (
13228                    movement::end_of_paragraph(map, head, 1),
13229                    SelectionGoal::None,
13230                )
13231            });
13232        })
13233    }
13234
13235    pub fn move_to_start_of_excerpt(
13236        &mut self,
13237        _: &MoveToStartOfExcerpt,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13242            cx.propagate();
13243            return;
13244        }
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_with(|map, selection| {
13248                selection.collapse_to(
13249                    movement::start_of_excerpt(
13250                        map,
13251                        selection.head(),
13252                        workspace::searchable::Direction::Prev,
13253                    ),
13254                    SelectionGoal::None,
13255                )
13256            });
13257        })
13258    }
13259
13260    pub fn move_to_start_of_next_excerpt(
13261        &mut self,
13262        _: &MoveToStartOfNextExcerpt,
13263        window: &mut Window,
13264        cx: &mut Context<Self>,
13265    ) {
13266        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13267            cx.propagate();
13268            return;
13269        }
13270
13271        self.change_selections(Default::default(), window, cx, |s| {
13272            s.move_with(|map, selection| {
13273                selection.collapse_to(
13274                    movement::start_of_excerpt(
13275                        map,
13276                        selection.head(),
13277                        workspace::searchable::Direction::Next,
13278                    ),
13279                    SelectionGoal::None,
13280                )
13281            });
13282        })
13283    }
13284
13285    pub fn move_to_end_of_excerpt(
13286        &mut self,
13287        _: &MoveToEndOfExcerpt,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13292            cx.propagate();
13293            return;
13294        }
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296        self.change_selections(Default::default(), window, cx, |s| {
13297            s.move_with(|map, selection| {
13298                selection.collapse_to(
13299                    movement::end_of_excerpt(
13300                        map,
13301                        selection.head(),
13302                        workspace::searchable::Direction::Next,
13303                    ),
13304                    SelectionGoal::None,
13305                )
13306            });
13307        })
13308    }
13309
13310    pub fn move_to_end_of_previous_excerpt(
13311        &mut self,
13312        _: &MoveToEndOfPreviousExcerpt,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13317            cx.propagate();
13318            return;
13319        }
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13321        self.change_selections(Default::default(), window, cx, |s| {
13322            s.move_with(|map, selection| {
13323                selection.collapse_to(
13324                    movement::end_of_excerpt(
13325                        map,
13326                        selection.head(),
13327                        workspace::searchable::Direction::Prev,
13328                    ),
13329                    SelectionGoal::None,
13330                )
13331            });
13332        })
13333    }
13334
13335    pub fn select_to_start_of_excerpt(
13336        &mut self,
13337        _: &SelectToStartOfExcerpt,
13338        window: &mut Window,
13339        cx: &mut Context<Self>,
13340    ) {
13341        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13342            cx.propagate();
13343            return;
13344        }
13345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13346        self.change_selections(Default::default(), window, cx, |s| {
13347            s.move_heads_with(|map, head, _| {
13348                (
13349                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13350                    SelectionGoal::None,
13351                )
13352            });
13353        })
13354    }
13355
13356    pub fn select_to_start_of_next_excerpt(
13357        &mut self,
13358        _: &SelectToStartOfNextExcerpt,
13359        window: &mut Window,
13360        cx: &mut Context<Self>,
13361    ) {
13362        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13363            cx.propagate();
13364            return;
13365        }
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (
13370                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13371                    SelectionGoal::None,
13372                )
13373            });
13374        })
13375    }
13376
13377    pub fn select_to_end_of_excerpt(
13378        &mut self,
13379        _: &SelectToEndOfExcerpt,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13384            cx.propagate();
13385            return;
13386        }
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13388        self.change_selections(Default::default(), window, cx, |s| {
13389            s.move_heads_with(|map, head, _| {
13390                (
13391                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13392                    SelectionGoal::None,
13393                )
13394            });
13395        })
13396    }
13397
13398    pub fn select_to_end_of_previous_excerpt(
13399        &mut self,
13400        _: &SelectToEndOfPreviousExcerpt,
13401        window: &mut Window,
13402        cx: &mut Context<Self>,
13403    ) {
13404        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13405            cx.propagate();
13406            return;
13407        }
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.move_heads_with(|map, head, _| {
13411                (
13412                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn move_to_beginning(
13420        &mut self,
13421        _: &MoveToBeginning,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13426            cx.propagate();
13427            return;
13428        }
13429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13430        self.change_selections(Default::default(), window, cx, |s| {
13431            s.select_ranges(vec![0..0]);
13432        });
13433    }
13434
13435    pub fn select_to_beginning(
13436        &mut self,
13437        _: &SelectToBeginning,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        let mut selection = self.selections.last::<Point>(cx);
13442        selection.set_head(Point::zero(), SelectionGoal::None);
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.select(vec![selection]);
13446        });
13447    }
13448
13449    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13450        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13451            cx.propagate();
13452            return;
13453        }
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        let cursor = self.buffer.read(cx).read(cx).len();
13456        self.change_selections(Default::default(), window, cx, |s| {
13457            s.select_ranges(vec![cursor..cursor])
13458        });
13459    }
13460
13461    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13462        self.nav_history = nav_history;
13463    }
13464
13465    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13466        self.nav_history.as_ref()
13467    }
13468
13469    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13470        self.push_to_nav_history(
13471            self.selections.newest_anchor().head(),
13472            None,
13473            false,
13474            true,
13475            cx,
13476        );
13477    }
13478
13479    fn push_to_nav_history(
13480        &mut self,
13481        cursor_anchor: Anchor,
13482        new_position: Option<Point>,
13483        is_deactivate: bool,
13484        always: bool,
13485        cx: &mut Context<Self>,
13486    ) {
13487        if let Some(nav_history) = self.nav_history.as_mut() {
13488            let buffer = self.buffer.read(cx).read(cx);
13489            let cursor_position = cursor_anchor.to_point(&buffer);
13490            let scroll_state = self.scroll_manager.anchor();
13491            let scroll_top_row = scroll_state.top_row(&buffer);
13492            drop(buffer);
13493
13494            if let Some(new_position) = new_position {
13495                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13496                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13497                    return;
13498                }
13499            }
13500
13501            nav_history.push(
13502                Some(NavigationData {
13503                    cursor_anchor,
13504                    cursor_position,
13505                    scroll_anchor: scroll_state,
13506                    scroll_top_row,
13507                }),
13508                cx,
13509            );
13510            cx.emit(EditorEvent::PushedToNavHistory {
13511                anchor: cursor_anchor,
13512                is_deactivate,
13513            })
13514        }
13515    }
13516
13517    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13519        let buffer = self.buffer.read(cx).snapshot(cx);
13520        let mut selection = self.selections.first::<usize>(cx);
13521        selection.set_head(buffer.len(), SelectionGoal::None);
13522        self.change_selections(Default::default(), window, cx, |s| {
13523            s.select(vec![selection]);
13524        });
13525    }
13526
13527    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13528        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13529        let end = self.buffer.read(cx).read(cx).len();
13530        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13531            s.select_ranges(vec![0..end]);
13532        });
13533    }
13534
13535    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13537        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13538        let mut selections = self.selections.all::<Point>(cx);
13539        let max_point = display_map.buffer_snapshot.max_point();
13540        for selection in &mut selections {
13541            let rows = selection.spanned_rows(true, &display_map);
13542            selection.start = Point::new(rows.start.0, 0);
13543            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13544            selection.reversed = false;
13545        }
13546        self.change_selections(Default::default(), window, cx, |s| {
13547            s.select(selections);
13548        });
13549    }
13550
13551    pub fn split_selection_into_lines(
13552        &mut self,
13553        _: &SplitSelectionIntoLines,
13554        window: &mut Window,
13555        cx: &mut Context<Self>,
13556    ) {
13557        let selections = self
13558            .selections
13559            .all::<Point>(cx)
13560            .into_iter()
13561            .map(|selection| selection.start..selection.end)
13562            .collect::<Vec<_>>();
13563        self.unfold_ranges(&selections, true, true, cx);
13564
13565        let mut new_selection_ranges = Vec::new();
13566        {
13567            let buffer = self.buffer.read(cx).read(cx);
13568            for selection in selections {
13569                for row in selection.start.row..selection.end.row {
13570                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13571                    new_selection_ranges.push(cursor..cursor);
13572                }
13573
13574                let is_multiline_selection = selection.start.row != selection.end.row;
13575                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13576                // so this action feels more ergonomic when paired with other selection operations
13577                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13578                if !should_skip_last {
13579                    new_selection_ranges.push(selection.end..selection.end);
13580                }
13581            }
13582        }
13583        self.change_selections(Default::default(), window, cx, |s| {
13584            s.select_ranges(new_selection_ranges);
13585        });
13586    }
13587
13588    pub fn add_selection_above(
13589        &mut self,
13590        _: &AddSelectionAbove,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        self.add_selection(true, window, cx);
13595    }
13596
13597    pub fn add_selection_below(
13598        &mut self,
13599        _: &AddSelectionBelow,
13600        window: &mut Window,
13601        cx: &mut Context<Self>,
13602    ) {
13603        self.add_selection(false, window, cx);
13604    }
13605
13606    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13608
13609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13610        let all_selections = self.selections.all::<Point>(cx);
13611        let text_layout_details = self.text_layout_details(window);
13612
13613        let (mut columnar_selections, new_selections_to_columnarize) = {
13614            if let Some(state) = self.add_selections_state.as_ref() {
13615                let columnar_selection_ids: HashSet<_> = state
13616                    .groups
13617                    .iter()
13618                    .flat_map(|group| group.stack.iter())
13619                    .copied()
13620                    .collect();
13621
13622                all_selections
13623                    .into_iter()
13624                    .partition(|s| columnar_selection_ids.contains(&s.id))
13625            } else {
13626                (Vec::new(), all_selections)
13627            }
13628        };
13629
13630        let mut state = self
13631            .add_selections_state
13632            .take()
13633            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13634
13635        for selection in new_selections_to_columnarize {
13636            let range = selection.display_range(&display_map).sorted();
13637            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13638            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13639            let positions = start_x.min(end_x)..start_x.max(end_x);
13640            let mut stack = Vec::new();
13641            for row in range.start.row().0..=range.end.row().0 {
13642                if let Some(selection) = self.selections.build_columnar_selection(
13643                    &display_map,
13644                    DisplayRow(row),
13645                    &positions,
13646                    selection.reversed,
13647                    &text_layout_details,
13648                ) {
13649                    stack.push(selection.id);
13650                    columnar_selections.push(selection);
13651                }
13652            }
13653            if !stack.is_empty() {
13654                if above {
13655                    stack.reverse();
13656                }
13657                state.groups.push(AddSelectionsGroup { above, stack });
13658            }
13659        }
13660
13661        let mut final_selections = Vec::new();
13662        let end_row = if above {
13663            DisplayRow(0)
13664        } else {
13665            display_map.max_point().row()
13666        };
13667
13668        let mut last_added_item_per_group = HashMap::default();
13669        for group in state.groups.iter_mut() {
13670            if let Some(last_id) = group.stack.last() {
13671                last_added_item_per_group.insert(*last_id, group);
13672            }
13673        }
13674
13675        for selection in columnar_selections {
13676            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13677                if above == group.above {
13678                    let range = selection.display_range(&display_map).sorted();
13679                    debug_assert_eq!(range.start.row(), range.end.row());
13680                    let mut row = range.start.row();
13681                    let positions =
13682                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13683                            px(start)..px(end)
13684                        } else {
13685                            let start_x =
13686                                display_map.x_for_display_point(range.start, &text_layout_details);
13687                            let end_x =
13688                                display_map.x_for_display_point(range.end, &text_layout_details);
13689                            start_x.min(end_x)..start_x.max(end_x)
13690                        };
13691
13692                    let mut maybe_new_selection = None;
13693                    while row != end_row {
13694                        if above {
13695                            row.0 -= 1;
13696                        } else {
13697                            row.0 += 1;
13698                        }
13699                        if let Some(new_selection) = self.selections.build_columnar_selection(
13700                            &display_map,
13701                            row,
13702                            &positions,
13703                            selection.reversed,
13704                            &text_layout_details,
13705                        ) {
13706                            maybe_new_selection = Some(new_selection);
13707                            break;
13708                        }
13709                    }
13710
13711                    if let Some(new_selection) = maybe_new_selection {
13712                        group.stack.push(new_selection.id);
13713                        if above {
13714                            final_selections.push(new_selection);
13715                            final_selections.push(selection);
13716                        } else {
13717                            final_selections.push(selection);
13718                            final_selections.push(new_selection);
13719                        }
13720                    } else {
13721                        final_selections.push(selection);
13722                    }
13723                } else {
13724                    group.stack.pop();
13725                }
13726            } else {
13727                final_selections.push(selection);
13728            }
13729        }
13730
13731        self.change_selections(Default::default(), window, cx, |s| {
13732            s.select(final_selections);
13733        });
13734
13735        let final_selection_ids: HashSet<_> = self
13736            .selections
13737            .all::<Point>(cx)
13738            .iter()
13739            .map(|s| s.id)
13740            .collect();
13741        state.groups.retain_mut(|group| {
13742            // selections might get merged above so we remove invalid items from stacks
13743            group.stack.retain(|id| final_selection_ids.contains(id));
13744
13745            // single selection in stack can be treated as initial state
13746            group.stack.len() > 1
13747        });
13748
13749        if !state.groups.is_empty() {
13750            self.add_selections_state = Some(state);
13751        }
13752    }
13753
13754    fn select_match_ranges(
13755        &mut self,
13756        range: Range<usize>,
13757        reversed: bool,
13758        replace_newest: bool,
13759        auto_scroll: Option<Autoscroll>,
13760        window: &mut Window,
13761        cx: &mut Context<Editor>,
13762    ) {
13763        self.unfold_ranges(
13764            std::slice::from_ref(&range),
13765            false,
13766            auto_scroll.is_some(),
13767            cx,
13768        );
13769        let effects = if let Some(scroll) = auto_scroll {
13770            SelectionEffects::scroll(scroll)
13771        } else {
13772            SelectionEffects::no_scroll()
13773        };
13774        self.change_selections(effects, window, cx, |s| {
13775            if replace_newest {
13776                s.delete(s.newest_anchor().id);
13777            }
13778            if reversed {
13779                s.insert_range(range.end..range.start);
13780            } else {
13781                s.insert_range(range);
13782            }
13783        });
13784    }
13785
13786    pub fn select_next_match_internal(
13787        &mut self,
13788        display_map: &DisplaySnapshot,
13789        replace_newest: bool,
13790        autoscroll: Option<Autoscroll>,
13791        window: &mut Window,
13792        cx: &mut Context<Self>,
13793    ) -> Result<()> {
13794        let buffer = &display_map.buffer_snapshot;
13795        let mut selections = self.selections.all::<usize>(cx);
13796        if let Some(mut select_next_state) = self.select_next_state.take() {
13797            let query = &select_next_state.query;
13798            if !select_next_state.done {
13799                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13800                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13801                let mut next_selected_range = None;
13802
13803                let bytes_after_last_selection =
13804                    buffer.bytes_in_range(last_selection.end..buffer.len());
13805                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13806                let query_matches = query
13807                    .stream_find_iter(bytes_after_last_selection)
13808                    .map(|result| (last_selection.end, result))
13809                    .chain(
13810                        query
13811                            .stream_find_iter(bytes_before_first_selection)
13812                            .map(|result| (0, result)),
13813                    );
13814
13815                for (start_offset, query_match) in query_matches {
13816                    let query_match = query_match.unwrap(); // can only fail due to I/O
13817                    let offset_range =
13818                        start_offset + query_match.start()..start_offset + query_match.end();
13819
13820                    if !select_next_state.wordwise
13821                        || (!buffer.is_inside_word(offset_range.start, false)
13822                            && !buffer.is_inside_word(offset_range.end, false))
13823                    {
13824                        // TODO: This is n^2, because we might check all the selections
13825                        if !selections
13826                            .iter()
13827                            .any(|selection| selection.range().overlaps(&offset_range))
13828                        {
13829                            next_selected_range = Some(offset_range);
13830                            break;
13831                        }
13832                    }
13833                }
13834
13835                if let Some(next_selected_range) = next_selected_range {
13836                    self.select_match_ranges(
13837                        next_selected_range,
13838                        last_selection.reversed,
13839                        replace_newest,
13840                        autoscroll,
13841                        window,
13842                        cx,
13843                    );
13844                } else {
13845                    select_next_state.done = true;
13846                }
13847            }
13848
13849            self.select_next_state = Some(select_next_state);
13850        } else {
13851            let mut only_carets = true;
13852            let mut same_text_selected = true;
13853            let mut selected_text = None;
13854
13855            let mut selections_iter = selections.iter().peekable();
13856            while let Some(selection) = selections_iter.next() {
13857                if selection.start != selection.end {
13858                    only_carets = false;
13859                }
13860
13861                if same_text_selected {
13862                    if selected_text.is_none() {
13863                        selected_text =
13864                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13865                    }
13866
13867                    if let Some(next_selection) = selections_iter.peek() {
13868                        if next_selection.range().len() == selection.range().len() {
13869                            let next_selected_text = buffer
13870                                .text_for_range(next_selection.range())
13871                                .collect::<String>();
13872                            if Some(next_selected_text) != selected_text {
13873                                same_text_selected = false;
13874                                selected_text = None;
13875                            }
13876                        } else {
13877                            same_text_selected = false;
13878                            selected_text = None;
13879                        }
13880                    }
13881                }
13882            }
13883
13884            if only_carets {
13885                for selection in &mut selections {
13886                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13887                    selection.start = word_range.start;
13888                    selection.end = word_range.end;
13889                    selection.goal = SelectionGoal::None;
13890                    selection.reversed = false;
13891                    self.select_match_ranges(
13892                        selection.start..selection.end,
13893                        selection.reversed,
13894                        replace_newest,
13895                        autoscroll,
13896                        window,
13897                        cx,
13898                    );
13899                }
13900
13901                if selections.len() == 1 {
13902                    let selection = selections
13903                        .last()
13904                        .expect("ensured that there's only one selection");
13905                    let query = buffer
13906                        .text_for_range(selection.start..selection.end)
13907                        .collect::<String>();
13908                    let is_empty = query.is_empty();
13909                    let select_state = SelectNextState {
13910                        query: AhoCorasick::new(&[query])?,
13911                        wordwise: true,
13912                        done: is_empty,
13913                    };
13914                    self.select_next_state = Some(select_state);
13915                } else {
13916                    self.select_next_state = None;
13917                }
13918            } else if let Some(selected_text) = selected_text {
13919                self.select_next_state = Some(SelectNextState {
13920                    query: AhoCorasick::new(&[selected_text])?,
13921                    wordwise: false,
13922                    done: false,
13923                });
13924                self.select_next_match_internal(
13925                    display_map,
13926                    replace_newest,
13927                    autoscroll,
13928                    window,
13929                    cx,
13930                )?;
13931            }
13932        }
13933        Ok(())
13934    }
13935
13936    pub fn select_all_matches(
13937        &mut self,
13938        _action: &SelectAllMatches,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) -> Result<()> {
13942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13943
13944        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13945
13946        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13947        let Some(select_next_state) = self.select_next_state.as_mut() else {
13948            return Ok(());
13949        };
13950        if select_next_state.done {
13951            return Ok(());
13952        }
13953
13954        let mut new_selections = Vec::new();
13955
13956        let reversed = self.selections.oldest::<usize>(cx).reversed;
13957        let buffer = &display_map.buffer_snapshot;
13958        let query_matches = select_next_state
13959            .query
13960            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13961
13962        for query_match in query_matches.into_iter() {
13963            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13964            let offset_range = if reversed {
13965                query_match.end()..query_match.start()
13966            } else {
13967                query_match.start()..query_match.end()
13968            };
13969
13970            if !select_next_state.wordwise
13971                || (!buffer.is_inside_word(offset_range.start, false)
13972                    && !buffer.is_inside_word(offset_range.end, false))
13973            {
13974                new_selections.push(offset_range.start..offset_range.end);
13975            }
13976        }
13977
13978        select_next_state.done = true;
13979
13980        if new_selections.is_empty() {
13981            log::error!("bug: new_selections is empty in select_all_matches");
13982            return Ok(());
13983        }
13984
13985        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13986        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13987            selections.select_ranges(new_selections)
13988        });
13989
13990        Ok(())
13991    }
13992
13993    pub fn select_next(
13994        &mut self,
13995        action: &SelectNext,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) -> Result<()> {
13999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14000        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14001        self.select_next_match_internal(
14002            &display_map,
14003            action.replace_newest,
14004            Some(Autoscroll::newest()),
14005            window,
14006            cx,
14007        )?;
14008        Ok(())
14009    }
14010
14011    pub fn select_previous(
14012        &mut self,
14013        action: &SelectPrevious,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) -> Result<()> {
14017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14018        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14019        let buffer = &display_map.buffer_snapshot;
14020        let mut selections = self.selections.all::<usize>(cx);
14021        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14022            let query = &select_prev_state.query;
14023            if !select_prev_state.done {
14024                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14025                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14026                let mut next_selected_range = None;
14027                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14028                let bytes_before_last_selection =
14029                    buffer.reversed_bytes_in_range(0..last_selection.start);
14030                let bytes_after_first_selection =
14031                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14032                let query_matches = query
14033                    .stream_find_iter(bytes_before_last_selection)
14034                    .map(|result| (last_selection.start, result))
14035                    .chain(
14036                        query
14037                            .stream_find_iter(bytes_after_first_selection)
14038                            .map(|result| (buffer.len(), result)),
14039                    );
14040                for (end_offset, query_match) in query_matches {
14041                    let query_match = query_match.unwrap(); // can only fail due to I/O
14042                    let offset_range =
14043                        end_offset - query_match.end()..end_offset - query_match.start();
14044
14045                    if !select_prev_state.wordwise
14046                        || (!buffer.is_inside_word(offset_range.start, false)
14047                            && !buffer.is_inside_word(offset_range.end, false))
14048                    {
14049                        next_selected_range = Some(offset_range);
14050                        break;
14051                    }
14052                }
14053
14054                if let Some(next_selected_range) = next_selected_range {
14055                    self.select_match_ranges(
14056                        next_selected_range,
14057                        last_selection.reversed,
14058                        action.replace_newest,
14059                        Some(Autoscroll::newest()),
14060                        window,
14061                        cx,
14062                    );
14063                } else {
14064                    select_prev_state.done = true;
14065                }
14066            }
14067
14068            self.select_prev_state = Some(select_prev_state);
14069        } else {
14070            let mut only_carets = true;
14071            let mut same_text_selected = true;
14072            let mut selected_text = None;
14073
14074            let mut selections_iter = selections.iter().peekable();
14075            while let Some(selection) = selections_iter.next() {
14076                if selection.start != selection.end {
14077                    only_carets = false;
14078                }
14079
14080                if same_text_selected {
14081                    if selected_text.is_none() {
14082                        selected_text =
14083                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14084                    }
14085
14086                    if let Some(next_selection) = selections_iter.peek() {
14087                        if next_selection.range().len() == selection.range().len() {
14088                            let next_selected_text = buffer
14089                                .text_for_range(next_selection.range())
14090                                .collect::<String>();
14091                            if Some(next_selected_text) != selected_text {
14092                                same_text_selected = false;
14093                                selected_text = None;
14094                            }
14095                        } else {
14096                            same_text_selected = false;
14097                            selected_text = None;
14098                        }
14099                    }
14100                }
14101            }
14102
14103            if only_carets {
14104                for selection in &mut selections {
14105                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14106                    selection.start = word_range.start;
14107                    selection.end = word_range.end;
14108                    selection.goal = SelectionGoal::None;
14109                    selection.reversed = false;
14110                    self.select_match_ranges(
14111                        selection.start..selection.end,
14112                        selection.reversed,
14113                        action.replace_newest,
14114                        Some(Autoscroll::newest()),
14115                        window,
14116                        cx,
14117                    );
14118                }
14119                if selections.len() == 1 {
14120                    let selection = selections
14121                        .last()
14122                        .expect("ensured that there's only one selection");
14123                    let query = buffer
14124                        .text_for_range(selection.start..selection.end)
14125                        .collect::<String>();
14126                    let is_empty = query.is_empty();
14127                    let select_state = SelectNextState {
14128                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14129                        wordwise: true,
14130                        done: is_empty,
14131                    };
14132                    self.select_prev_state = Some(select_state);
14133                } else {
14134                    self.select_prev_state = None;
14135                }
14136            } else if let Some(selected_text) = selected_text {
14137                self.select_prev_state = Some(SelectNextState {
14138                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14139                    wordwise: false,
14140                    done: false,
14141                });
14142                self.select_previous(action, window, cx)?;
14143            }
14144        }
14145        Ok(())
14146    }
14147
14148    pub fn find_next_match(
14149        &mut self,
14150        _: &FindNextMatch,
14151        window: &mut Window,
14152        cx: &mut Context<Self>,
14153    ) -> Result<()> {
14154        let selections = self.selections.disjoint_anchors();
14155        match selections.first() {
14156            Some(first) if selections.len() >= 2 => {
14157                self.change_selections(Default::default(), window, cx, |s| {
14158                    s.select_ranges([first.range()]);
14159                });
14160            }
14161            _ => self.select_next(
14162                &SelectNext {
14163                    replace_newest: true,
14164                },
14165                window,
14166                cx,
14167            )?,
14168        }
14169        Ok(())
14170    }
14171
14172    pub fn find_previous_match(
14173        &mut self,
14174        _: &FindPreviousMatch,
14175        window: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) -> Result<()> {
14178        let selections = self.selections.disjoint_anchors();
14179        match selections.last() {
14180            Some(last) if selections.len() >= 2 => {
14181                self.change_selections(Default::default(), window, cx, |s| {
14182                    s.select_ranges([last.range()]);
14183                });
14184            }
14185            _ => self.select_previous(
14186                &SelectPrevious {
14187                    replace_newest: true,
14188                },
14189                window,
14190                cx,
14191            )?,
14192        }
14193        Ok(())
14194    }
14195
14196    pub fn toggle_comments(
14197        &mut self,
14198        action: &ToggleComments,
14199        window: &mut Window,
14200        cx: &mut Context<Self>,
14201    ) {
14202        if self.read_only(cx) {
14203            return;
14204        }
14205        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14206        let text_layout_details = &self.text_layout_details(window);
14207        self.transact(window, cx, |this, window, cx| {
14208            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14209            let mut edits = Vec::new();
14210            let mut selection_edit_ranges = Vec::new();
14211            let mut last_toggled_row = None;
14212            let snapshot = this.buffer.read(cx).read(cx);
14213            let empty_str: Arc<str> = Arc::default();
14214            let mut suffixes_inserted = Vec::new();
14215            let ignore_indent = action.ignore_indent;
14216
14217            fn comment_prefix_range(
14218                snapshot: &MultiBufferSnapshot,
14219                row: MultiBufferRow,
14220                comment_prefix: &str,
14221                comment_prefix_whitespace: &str,
14222                ignore_indent: bool,
14223            ) -> Range<Point> {
14224                let indent_size = if ignore_indent {
14225                    0
14226                } else {
14227                    snapshot.indent_size_for_line(row).len
14228                };
14229
14230                let start = Point::new(row.0, indent_size);
14231
14232                let mut line_bytes = snapshot
14233                    .bytes_in_range(start..snapshot.max_point())
14234                    .flatten()
14235                    .copied();
14236
14237                // If this line currently begins with the line comment prefix, then record
14238                // the range containing the prefix.
14239                if line_bytes
14240                    .by_ref()
14241                    .take(comment_prefix.len())
14242                    .eq(comment_prefix.bytes())
14243                {
14244                    // Include any whitespace that matches the comment prefix.
14245                    let matching_whitespace_len = line_bytes
14246                        .zip(comment_prefix_whitespace.bytes())
14247                        .take_while(|(a, b)| a == b)
14248                        .count() as u32;
14249                    let end = Point::new(
14250                        start.row,
14251                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14252                    );
14253                    start..end
14254                } else {
14255                    start..start
14256                }
14257            }
14258
14259            fn comment_suffix_range(
14260                snapshot: &MultiBufferSnapshot,
14261                row: MultiBufferRow,
14262                comment_suffix: &str,
14263                comment_suffix_has_leading_space: bool,
14264            ) -> Range<Point> {
14265                let end = Point::new(row.0, snapshot.line_len(row));
14266                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14267
14268                let mut line_end_bytes = snapshot
14269                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14270                    .flatten()
14271                    .copied();
14272
14273                let leading_space_len = if suffix_start_column > 0
14274                    && line_end_bytes.next() == Some(b' ')
14275                    && comment_suffix_has_leading_space
14276                {
14277                    1
14278                } else {
14279                    0
14280                };
14281
14282                // If this line currently begins with the line comment prefix, then record
14283                // the range containing the prefix.
14284                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14285                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14286                    start..end
14287                } else {
14288                    end..end
14289                }
14290            }
14291
14292            // TODO: Handle selections that cross excerpts
14293            for selection in &mut selections {
14294                let start_column = snapshot
14295                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14296                    .len;
14297                let language = if let Some(language) =
14298                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14299                {
14300                    language
14301                } else {
14302                    continue;
14303                };
14304
14305                selection_edit_ranges.clear();
14306
14307                // If multiple selections contain a given row, avoid processing that
14308                // row more than once.
14309                let mut start_row = MultiBufferRow(selection.start.row);
14310                if last_toggled_row == Some(start_row) {
14311                    start_row = start_row.next_row();
14312                }
14313                let end_row =
14314                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14315                        MultiBufferRow(selection.end.row - 1)
14316                    } else {
14317                        MultiBufferRow(selection.end.row)
14318                    };
14319                last_toggled_row = Some(end_row);
14320
14321                if start_row > end_row {
14322                    continue;
14323                }
14324
14325                // If the language has line comments, toggle those.
14326                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14327
14328                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14329                if ignore_indent {
14330                    full_comment_prefixes = full_comment_prefixes
14331                        .into_iter()
14332                        .map(|s| Arc::from(s.trim_end()))
14333                        .collect();
14334                }
14335
14336                if !full_comment_prefixes.is_empty() {
14337                    let first_prefix = full_comment_prefixes
14338                        .first()
14339                        .expect("prefixes is non-empty");
14340                    let prefix_trimmed_lengths = full_comment_prefixes
14341                        .iter()
14342                        .map(|p| p.trim_end_matches(' ').len())
14343                        .collect::<SmallVec<[usize; 4]>>();
14344
14345                    let mut all_selection_lines_are_comments = true;
14346
14347                    for row in start_row.0..=end_row.0 {
14348                        let row = MultiBufferRow(row);
14349                        if start_row < end_row && snapshot.is_line_blank(row) {
14350                            continue;
14351                        }
14352
14353                        let prefix_range = full_comment_prefixes
14354                            .iter()
14355                            .zip(prefix_trimmed_lengths.iter().copied())
14356                            .map(|(prefix, trimmed_prefix_len)| {
14357                                comment_prefix_range(
14358                                    snapshot.deref(),
14359                                    row,
14360                                    &prefix[..trimmed_prefix_len],
14361                                    &prefix[trimmed_prefix_len..],
14362                                    ignore_indent,
14363                                )
14364                            })
14365                            .max_by_key(|range| range.end.column - range.start.column)
14366                            .expect("prefixes is non-empty");
14367
14368                        if prefix_range.is_empty() {
14369                            all_selection_lines_are_comments = false;
14370                        }
14371
14372                        selection_edit_ranges.push(prefix_range);
14373                    }
14374
14375                    if all_selection_lines_are_comments {
14376                        edits.extend(
14377                            selection_edit_ranges
14378                                .iter()
14379                                .cloned()
14380                                .map(|range| (range, empty_str.clone())),
14381                        );
14382                    } else {
14383                        let min_column = selection_edit_ranges
14384                            .iter()
14385                            .map(|range| range.start.column)
14386                            .min()
14387                            .unwrap_or(0);
14388                        edits.extend(selection_edit_ranges.iter().map(|range| {
14389                            let position = Point::new(range.start.row, min_column);
14390                            (position..position, first_prefix.clone())
14391                        }));
14392                    }
14393                } else if let Some(BlockCommentConfig {
14394                    start: full_comment_prefix,
14395                    end: comment_suffix,
14396                    ..
14397                }) = language.block_comment()
14398                {
14399                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14400                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14401                    let prefix_range = comment_prefix_range(
14402                        snapshot.deref(),
14403                        start_row,
14404                        comment_prefix,
14405                        comment_prefix_whitespace,
14406                        ignore_indent,
14407                    );
14408                    let suffix_range = comment_suffix_range(
14409                        snapshot.deref(),
14410                        end_row,
14411                        comment_suffix.trim_start_matches(' '),
14412                        comment_suffix.starts_with(' '),
14413                    );
14414
14415                    if prefix_range.is_empty() || suffix_range.is_empty() {
14416                        edits.push((
14417                            prefix_range.start..prefix_range.start,
14418                            full_comment_prefix.clone(),
14419                        ));
14420                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14421                        suffixes_inserted.push((end_row, comment_suffix.len()));
14422                    } else {
14423                        edits.push((prefix_range, empty_str.clone()));
14424                        edits.push((suffix_range, empty_str.clone()));
14425                    }
14426                } else {
14427                    continue;
14428                }
14429            }
14430
14431            drop(snapshot);
14432            this.buffer.update(cx, |buffer, cx| {
14433                buffer.edit(edits, None, cx);
14434            });
14435
14436            // Adjust selections so that they end before any comment suffixes that
14437            // were inserted.
14438            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14439            let mut selections = this.selections.all::<Point>(cx);
14440            let snapshot = this.buffer.read(cx).read(cx);
14441            for selection in &mut selections {
14442                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14443                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14444                        Ordering::Less => {
14445                            suffixes_inserted.next();
14446                            continue;
14447                        }
14448                        Ordering::Greater => break,
14449                        Ordering::Equal => {
14450                            if selection.end.column == snapshot.line_len(row) {
14451                                if selection.is_empty() {
14452                                    selection.start.column -= suffix_len as u32;
14453                                }
14454                                selection.end.column -= suffix_len as u32;
14455                            }
14456                            break;
14457                        }
14458                    }
14459                }
14460            }
14461
14462            drop(snapshot);
14463            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14464
14465            let selections = this.selections.all::<Point>(cx);
14466            let selections_on_single_row = selections.windows(2).all(|selections| {
14467                selections[0].start.row == selections[1].start.row
14468                    && selections[0].end.row == selections[1].end.row
14469                    && selections[0].start.row == selections[0].end.row
14470            });
14471            let selections_selecting = selections
14472                .iter()
14473                .any(|selection| selection.start != selection.end);
14474            let advance_downwards = action.advance_downwards
14475                && selections_on_single_row
14476                && !selections_selecting
14477                && !matches!(this.mode, EditorMode::SingleLine { .. });
14478
14479            if advance_downwards {
14480                let snapshot = this.buffer.read(cx).snapshot(cx);
14481
14482                this.change_selections(Default::default(), window, cx, |s| {
14483                    s.move_cursors_with(|display_snapshot, display_point, _| {
14484                        let mut point = display_point.to_point(display_snapshot);
14485                        point.row += 1;
14486                        point = snapshot.clip_point(point, Bias::Left);
14487                        let display_point = point.to_display_point(display_snapshot);
14488                        let goal = SelectionGoal::HorizontalPosition(
14489                            display_snapshot
14490                                .x_for_display_point(display_point, text_layout_details)
14491                                .into(),
14492                        );
14493                        (display_point, goal)
14494                    })
14495                });
14496            }
14497        });
14498    }
14499
14500    pub fn select_enclosing_symbol(
14501        &mut self,
14502        _: &SelectEnclosingSymbol,
14503        window: &mut Window,
14504        cx: &mut Context<Self>,
14505    ) {
14506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14507
14508        let buffer = self.buffer.read(cx).snapshot(cx);
14509        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14510
14511        fn update_selection(
14512            selection: &Selection<usize>,
14513            buffer_snap: &MultiBufferSnapshot,
14514        ) -> Option<Selection<usize>> {
14515            let cursor = selection.head();
14516            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14517            for symbol in symbols.iter().rev() {
14518                let start = symbol.range.start.to_offset(buffer_snap);
14519                let end = symbol.range.end.to_offset(buffer_snap);
14520                let new_range = start..end;
14521                if start < selection.start || end > selection.end {
14522                    return Some(Selection {
14523                        id: selection.id,
14524                        start: new_range.start,
14525                        end: new_range.end,
14526                        goal: SelectionGoal::None,
14527                        reversed: selection.reversed,
14528                    });
14529                }
14530            }
14531            None
14532        }
14533
14534        let mut selected_larger_symbol = false;
14535        let new_selections = old_selections
14536            .iter()
14537            .map(|selection| match update_selection(selection, &buffer) {
14538                Some(new_selection) => {
14539                    if new_selection.range() != selection.range() {
14540                        selected_larger_symbol = true;
14541                    }
14542                    new_selection
14543                }
14544                None => selection.clone(),
14545            })
14546            .collect::<Vec<_>>();
14547
14548        if selected_larger_symbol {
14549            self.change_selections(Default::default(), window, cx, |s| {
14550                s.select(new_selections);
14551            });
14552        }
14553    }
14554
14555    pub fn select_larger_syntax_node(
14556        &mut self,
14557        _: &SelectLargerSyntaxNode,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) {
14561        let Some(visible_row_count) = self.visible_row_count() else {
14562            return;
14563        };
14564        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14565        if old_selections.is_empty() {
14566            return;
14567        }
14568
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570
14571        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14572        let buffer = self.buffer.read(cx).snapshot(cx);
14573
14574        let mut selected_larger_node = false;
14575        let mut new_selections = old_selections
14576            .iter()
14577            .map(|selection| {
14578                let old_range = selection.start..selection.end;
14579
14580                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14581                    // manually select word at selection
14582                    if ["string_content", "inline"].contains(&node.kind()) {
14583                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14584                        // ignore if word is already selected
14585                        if !word_range.is_empty() && old_range != word_range {
14586                            let (last_word_range, _) =
14587                                buffer.surrounding_word(old_range.end, false);
14588                            // only select word if start and end point belongs to same word
14589                            if word_range == last_word_range {
14590                                selected_larger_node = true;
14591                                return Selection {
14592                                    id: selection.id,
14593                                    start: word_range.start,
14594                                    end: word_range.end,
14595                                    goal: SelectionGoal::None,
14596                                    reversed: selection.reversed,
14597                                };
14598                            }
14599                        }
14600                    }
14601                }
14602
14603                let mut new_range = old_range.clone();
14604                while let Some((_node, containing_range)) =
14605                    buffer.syntax_ancestor(new_range.clone())
14606                {
14607                    new_range = match containing_range {
14608                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14609                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14610                    };
14611                    if !display_map.intersects_fold(new_range.start)
14612                        && !display_map.intersects_fold(new_range.end)
14613                    {
14614                        break;
14615                    }
14616                }
14617
14618                selected_larger_node |= new_range != old_range;
14619                Selection {
14620                    id: selection.id,
14621                    start: new_range.start,
14622                    end: new_range.end,
14623                    goal: SelectionGoal::None,
14624                    reversed: selection.reversed,
14625                }
14626            })
14627            .collect::<Vec<_>>();
14628
14629        if !selected_larger_node {
14630            return; // don't put this call in the history
14631        }
14632
14633        // scroll based on transformation done to the last selection created by the user
14634        let (last_old, last_new) = old_selections
14635            .last()
14636            .zip(new_selections.last().cloned())
14637            .expect("old_selections isn't empty");
14638
14639        // revert selection
14640        let is_selection_reversed = {
14641            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14642            new_selections.last_mut().expect("checked above").reversed =
14643                should_newest_selection_be_reversed;
14644            should_newest_selection_be_reversed
14645        };
14646
14647        if selected_larger_node {
14648            self.select_syntax_node_history.disable_clearing = true;
14649            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14650                s.select(new_selections.clone());
14651            });
14652            self.select_syntax_node_history.disable_clearing = false;
14653        }
14654
14655        let start_row = last_new.start.to_display_point(&display_map).row().0;
14656        let end_row = last_new.end.to_display_point(&display_map).row().0;
14657        let selection_height = end_row - start_row + 1;
14658        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14659
14660        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14661        let scroll_behavior = if fits_on_the_screen {
14662            self.request_autoscroll(Autoscroll::fit(), cx);
14663            SelectSyntaxNodeScrollBehavior::FitSelection
14664        } else if is_selection_reversed {
14665            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14666            SelectSyntaxNodeScrollBehavior::CursorTop
14667        } else {
14668            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14669            SelectSyntaxNodeScrollBehavior::CursorBottom
14670        };
14671
14672        self.select_syntax_node_history.push((
14673            old_selections,
14674            scroll_behavior,
14675            is_selection_reversed,
14676        ));
14677    }
14678
14679    pub fn select_smaller_syntax_node(
14680        &mut self,
14681        _: &SelectSmallerSyntaxNode,
14682        window: &mut Window,
14683        cx: &mut Context<Self>,
14684    ) {
14685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14686
14687        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14688            self.select_syntax_node_history.pop()
14689        {
14690            if let Some(selection) = selections.last_mut() {
14691                selection.reversed = is_selection_reversed;
14692            }
14693
14694            self.select_syntax_node_history.disable_clearing = true;
14695            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14696                s.select(selections.to_vec());
14697            });
14698            self.select_syntax_node_history.disable_clearing = false;
14699
14700            match scroll_behavior {
14701                SelectSyntaxNodeScrollBehavior::CursorTop => {
14702                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14703                }
14704                SelectSyntaxNodeScrollBehavior::FitSelection => {
14705                    self.request_autoscroll(Autoscroll::fit(), cx);
14706                }
14707                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14708                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14709                }
14710            }
14711        }
14712    }
14713
14714    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14715        if !EditorSettings::get_global(cx).gutter.runnables {
14716            self.clear_tasks();
14717            return Task::ready(());
14718        }
14719        let project = self.project.as_ref().map(Entity::downgrade);
14720        let task_sources = self.lsp_task_sources(cx);
14721        let multi_buffer = self.buffer.downgrade();
14722        cx.spawn_in(window, async move |editor, cx| {
14723            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14724            let Some(project) = project.and_then(|p| p.upgrade()) else {
14725                return;
14726            };
14727            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14728                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14729            }) else {
14730                return;
14731            };
14732
14733            let hide_runnables = project
14734                .update(cx, |project, cx| {
14735                    // Do not display any test indicators in non-dev server remote projects.
14736                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14737                })
14738                .unwrap_or(true);
14739            if hide_runnables {
14740                return;
14741            }
14742            let new_rows =
14743                cx.background_spawn({
14744                    let snapshot = display_snapshot.clone();
14745                    async move {
14746                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14747                    }
14748                })
14749                    .await;
14750            let Ok(lsp_tasks) =
14751                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14752            else {
14753                return;
14754            };
14755            let lsp_tasks = lsp_tasks.await;
14756
14757            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14758                lsp_tasks
14759                    .into_iter()
14760                    .flat_map(|(kind, tasks)| {
14761                        tasks.into_iter().filter_map(move |(location, task)| {
14762                            Some((kind.clone(), location?, task))
14763                        })
14764                    })
14765                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14766                        let buffer = location.target.buffer;
14767                        let buffer_snapshot = buffer.read(cx).snapshot();
14768                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14769                            |(excerpt_id, snapshot, _)| {
14770                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14771                                    display_snapshot
14772                                        .buffer_snapshot
14773                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14774                                } else {
14775                                    None
14776                                }
14777                            },
14778                        );
14779                        if let Some(offset) = offset {
14780                            let task_buffer_range =
14781                                location.target.range.to_point(&buffer_snapshot);
14782                            let context_buffer_range =
14783                                task_buffer_range.to_offset(&buffer_snapshot);
14784                            let context_range = BufferOffset(context_buffer_range.start)
14785                                ..BufferOffset(context_buffer_range.end);
14786
14787                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14788                                .or_insert_with(|| RunnableTasks {
14789                                    templates: Vec::new(),
14790                                    offset,
14791                                    column: task_buffer_range.start.column,
14792                                    extra_variables: HashMap::default(),
14793                                    context_range,
14794                                })
14795                                .templates
14796                                .push((kind, task.original_task().clone()));
14797                        }
14798
14799                        acc
14800                    })
14801            }) else {
14802                return;
14803            };
14804
14805            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14806                buffer.language_settings(cx).tasks.prefer_lsp
14807            }) else {
14808                return;
14809            };
14810
14811            let rows = Self::runnable_rows(
14812                project,
14813                display_snapshot,
14814                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14815                new_rows,
14816                cx.clone(),
14817            )
14818            .await;
14819            editor
14820                .update(cx, |editor, _| {
14821                    editor.clear_tasks();
14822                    for (key, mut value) in rows {
14823                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14824                            value.templates.extend(lsp_tasks.templates);
14825                        }
14826
14827                        editor.insert_tasks(key, value);
14828                    }
14829                    for (key, value) in lsp_tasks_by_rows {
14830                        editor.insert_tasks(key, value);
14831                    }
14832                })
14833                .ok();
14834        })
14835    }
14836    fn fetch_runnable_ranges(
14837        snapshot: &DisplaySnapshot,
14838        range: Range<Anchor>,
14839    ) -> Vec<language::RunnableRange> {
14840        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14841    }
14842
14843    fn runnable_rows(
14844        project: Entity<Project>,
14845        snapshot: DisplaySnapshot,
14846        prefer_lsp: bool,
14847        runnable_ranges: Vec<RunnableRange>,
14848        cx: AsyncWindowContext,
14849    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14850        cx.spawn(async move |cx| {
14851            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14852            for mut runnable in runnable_ranges {
14853                let Some(tasks) = cx
14854                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14855                    .ok()
14856                else {
14857                    continue;
14858                };
14859                let mut tasks = tasks.await;
14860
14861                if prefer_lsp {
14862                    tasks.retain(|(task_kind, _)| {
14863                        !matches!(task_kind, TaskSourceKind::Language { .. })
14864                    });
14865                }
14866                if tasks.is_empty() {
14867                    continue;
14868                }
14869
14870                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14871                let Some(row) = snapshot
14872                    .buffer_snapshot
14873                    .buffer_line_for_row(MultiBufferRow(point.row))
14874                    .map(|(_, range)| range.start.row)
14875                else {
14876                    continue;
14877                };
14878
14879                let context_range =
14880                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14881                runnable_rows.push((
14882                    (runnable.buffer_id, row),
14883                    RunnableTasks {
14884                        templates: tasks,
14885                        offset: snapshot
14886                            .buffer_snapshot
14887                            .anchor_before(runnable.run_range.start),
14888                        context_range,
14889                        column: point.column,
14890                        extra_variables: runnable.extra_captures,
14891                    },
14892                ));
14893            }
14894            runnable_rows
14895        })
14896    }
14897
14898    fn templates_with_tags(
14899        project: &Entity<Project>,
14900        runnable: &mut Runnable,
14901        cx: &mut App,
14902    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14903        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14904            let (worktree_id, file) = project
14905                .buffer_for_id(runnable.buffer, cx)
14906                .and_then(|buffer| buffer.read(cx).file())
14907                .map(|file| (file.worktree_id(cx), file.clone()))
14908                .unzip();
14909
14910            (
14911                project.task_store().read(cx).task_inventory().cloned(),
14912                worktree_id,
14913                file,
14914            )
14915        });
14916
14917        let tags = mem::take(&mut runnable.tags);
14918        let language = runnable.language.clone();
14919        cx.spawn(async move |cx| {
14920            let mut templates_with_tags = Vec::new();
14921            if let Some(inventory) = inventory {
14922                for RunnableTag(tag) in tags {
14923                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14924                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14925                    }) else {
14926                        return templates_with_tags;
14927                    };
14928                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14929                        move |(_, template)| {
14930                            template.tags.iter().any(|source_tag| source_tag == &tag)
14931                        },
14932                    ));
14933                }
14934            }
14935            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14936
14937            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14938                // Strongest source wins; if we have worktree tag binding, prefer that to
14939                // global and language bindings;
14940                // if we have a global binding, prefer that to language binding.
14941                let first_mismatch = templates_with_tags
14942                    .iter()
14943                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14944                if let Some(index) = first_mismatch {
14945                    templates_with_tags.truncate(index);
14946                }
14947            }
14948
14949            templates_with_tags
14950        })
14951    }
14952
14953    pub fn move_to_enclosing_bracket(
14954        &mut self,
14955        _: &MoveToEnclosingBracket,
14956        window: &mut Window,
14957        cx: &mut Context<Self>,
14958    ) {
14959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14960        self.change_selections(Default::default(), window, cx, |s| {
14961            s.move_offsets_with(|snapshot, selection| {
14962                let Some(enclosing_bracket_ranges) =
14963                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14964                else {
14965                    return;
14966                };
14967
14968                let mut best_length = usize::MAX;
14969                let mut best_inside = false;
14970                let mut best_in_bracket_range = false;
14971                let mut best_destination = None;
14972                for (open, close) in enclosing_bracket_ranges {
14973                    let close = close.to_inclusive();
14974                    let length = close.end() - open.start;
14975                    let inside = selection.start >= open.end && selection.end <= *close.start();
14976                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14977                        || close.contains(&selection.head());
14978
14979                    // If best is next to a bracket and current isn't, skip
14980                    if !in_bracket_range && best_in_bracket_range {
14981                        continue;
14982                    }
14983
14984                    // Prefer smaller lengths unless best is inside and current isn't
14985                    if length > best_length && (best_inside || !inside) {
14986                        continue;
14987                    }
14988
14989                    best_length = length;
14990                    best_inside = inside;
14991                    best_in_bracket_range = in_bracket_range;
14992                    best_destination = Some(
14993                        if close.contains(&selection.start) && close.contains(&selection.end) {
14994                            if inside { open.end } else { open.start }
14995                        } else if inside {
14996                            *close.start()
14997                        } else {
14998                            *close.end()
14999                        },
15000                    );
15001                }
15002
15003                if let Some(destination) = best_destination {
15004                    selection.collapse_to(destination, SelectionGoal::None);
15005                }
15006            })
15007        });
15008    }
15009
15010    pub fn undo_selection(
15011        &mut self,
15012        _: &UndoSelection,
15013        window: &mut Window,
15014        cx: &mut Context<Self>,
15015    ) {
15016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15017        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15018            self.selection_history.mode = SelectionHistoryMode::Undoing;
15019            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15020                this.end_selection(window, cx);
15021                this.change_selections(
15022                    SelectionEffects::scroll(Autoscroll::newest()),
15023                    window,
15024                    cx,
15025                    |s| s.select_anchors(entry.selections.to_vec()),
15026                );
15027            });
15028            self.selection_history.mode = SelectionHistoryMode::Normal;
15029
15030            self.select_next_state = entry.select_next_state;
15031            self.select_prev_state = entry.select_prev_state;
15032            self.add_selections_state = entry.add_selections_state;
15033        }
15034    }
15035
15036    pub fn redo_selection(
15037        &mut self,
15038        _: &RedoSelection,
15039        window: &mut Window,
15040        cx: &mut Context<Self>,
15041    ) {
15042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15043        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15044            self.selection_history.mode = SelectionHistoryMode::Redoing;
15045            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15046                this.end_selection(window, cx);
15047                this.change_selections(
15048                    SelectionEffects::scroll(Autoscroll::newest()),
15049                    window,
15050                    cx,
15051                    |s| s.select_anchors(entry.selections.to_vec()),
15052                );
15053            });
15054            self.selection_history.mode = SelectionHistoryMode::Normal;
15055
15056            self.select_next_state = entry.select_next_state;
15057            self.select_prev_state = entry.select_prev_state;
15058            self.add_selections_state = entry.add_selections_state;
15059        }
15060    }
15061
15062    pub fn expand_excerpts(
15063        &mut self,
15064        action: &ExpandExcerpts,
15065        _: &mut Window,
15066        cx: &mut Context<Self>,
15067    ) {
15068        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15069    }
15070
15071    pub fn expand_excerpts_down(
15072        &mut self,
15073        action: &ExpandExcerptsDown,
15074        _: &mut Window,
15075        cx: &mut Context<Self>,
15076    ) {
15077        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15078    }
15079
15080    pub fn expand_excerpts_up(
15081        &mut self,
15082        action: &ExpandExcerptsUp,
15083        _: &mut Window,
15084        cx: &mut Context<Self>,
15085    ) {
15086        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15087    }
15088
15089    pub fn expand_excerpts_for_direction(
15090        &mut self,
15091        lines: u32,
15092        direction: ExpandExcerptDirection,
15093
15094        cx: &mut Context<Self>,
15095    ) {
15096        let selections = self.selections.disjoint_anchors();
15097
15098        let lines = if lines == 0 {
15099            EditorSettings::get_global(cx).expand_excerpt_lines
15100        } else {
15101            lines
15102        };
15103
15104        self.buffer.update(cx, |buffer, cx| {
15105            let snapshot = buffer.snapshot(cx);
15106            let mut excerpt_ids = selections
15107                .iter()
15108                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15109                .collect::<Vec<_>>();
15110            excerpt_ids.sort();
15111            excerpt_ids.dedup();
15112            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15113        })
15114    }
15115
15116    pub fn expand_excerpt(
15117        &mut self,
15118        excerpt: ExcerptId,
15119        direction: ExpandExcerptDirection,
15120        window: &mut Window,
15121        cx: &mut Context<Self>,
15122    ) {
15123        let current_scroll_position = self.scroll_position(cx);
15124        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15125        let mut should_scroll_up = false;
15126
15127        if direction == ExpandExcerptDirection::Down {
15128            let multi_buffer = self.buffer.read(cx);
15129            let snapshot = multi_buffer.snapshot(cx);
15130            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15131                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15132                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15133                        let buffer_snapshot = buffer.read(cx).snapshot();
15134                        let excerpt_end_row =
15135                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15136                        let last_row = buffer_snapshot.max_point().row;
15137                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15138                        should_scroll_up = lines_below >= lines_to_expand;
15139                    }
15140                }
15141            }
15142        }
15143
15144        self.buffer.update(cx, |buffer, cx| {
15145            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15146        });
15147
15148        if should_scroll_up {
15149            let new_scroll_position =
15150                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15151            self.set_scroll_position(new_scroll_position, window, cx);
15152        }
15153    }
15154
15155    pub fn go_to_singleton_buffer_point(
15156        &mut self,
15157        point: Point,
15158        window: &mut Window,
15159        cx: &mut Context<Self>,
15160    ) {
15161        self.go_to_singleton_buffer_range(point..point, window, cx);
15162    }
15163
15164    pub fn go_to_singleton_buffer_range(
15165        &mut self,
15166        range: Range<Point>,
15167        window: &mut Window,
15168        cx: &mut Context<Self>,
15169    ) {
15170        let multibuffer = self.buffer().read(cx);
15171        let Some(buffer) = multibuffer.as_singleton() else {
15172            return;
15173        };
15174        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15175            return;
15176        };
15177        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15178            return;
15179        };
15180        self.change_selections(
15181            SelectionEffects::default().nav_history(true),
15182            window,
15183            cx,
15184            |s| s.select_anchor_ranges([start..end]),
15185        );
15186    }
15187
15188    pub fn go_to_diagnostic(
15189        &mut self,
15190        action: &GoToDiagnostic,
15191        window: &mut Window,
15192        cx: &mut Context<Self>,
15193    ) {
15194        if !self.diagnostics_enabled() {
15195            return;
15196        }
15197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15198        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15199    }
15200
15201    pub fn go_to_prev_diagnostic(
15202        &mut self,
15203        action: &GoToPreviousDiagnostic,
15204        window: &mut Window,
15205        cx: &mut Context<Self>,
15206    ) {
15207        if !self.diagnostics_enabled() {
15208            return;
15209        }
15210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15211        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15212    }
15213
15214    pub fn go_to_diagnostic_impl(
15215        &mut self,
15216        direction: Direction,
15217        severity: GoToDiagnosticSeverityFilter,
15218        window: &mut Window,
15219        cx: &mut Context<Self>,
15220    ) {
15221        let buffer = self.buffer.read(cx).snapshot(cx);
15222        let selection = self.selections.newest::<usize>(cx);
15223
15224        let mut active_group_id = None;
15225        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15226            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15227                active_group_id = Some(active_group.group_id);
15228            }
15229        }
15230
15231        fn filtered(
15232            snapshot: EditorSnapshot,
15233            severity: GoToDiagnosticSeverityFilter,
15234            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15235        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15236            diagnostics
15237                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15238                .filter(|entry| entry.range.start != entry.range.end)
15239                .filter(|entry| !entry.diagnostic.is_unnecessary)
15240                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15241        }
15242
15243        let snapshot = self.snapshot(window, cx);
15244        let before = filtered(
15245            snapshot.clone(),
15246            severity,
15247            buffer
15248                .diagnostics_in_range(0..selection.start)
15249                .filter(|entry| entry.range.start <= selection.start),
15250        );
15251        let after = filtered(
15252            snapshot,
15253            severity,
15254            buffer
15255                .diagnostics_in_range(selection.start..buffer.len())
15256                .filter(|entry| entry.range.start >= selection.start),
15257        );
15258
15259        let mut found: Option<DiagnosticEntry<usize>> = None;
15260        if direction == Direction::Prev {
15261            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15262            {
15263                for diagnostic in prev_diagnostics.into_iter().rev() {
15264                    if diagnostic.range.start != selection.start
15265                        || active_group_id
15266                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15267                    {
15268                        found = Some(diagnostic);
15269                        break 'outer;
15270                    }
15271                }
15272            }
15273        } else {
15274            for diagnostic in after.chain(before) {
15275                if diagnostic.range.start != selection.start
15276                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15277                {
15278                    found = Some(diagnostic);
15279                    break;
15280                }
15281            }
15282        }
15283        let Some(next_diagnostic) = found else {
15284            return;
15285        };
15286
15287        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15288            return;
15289        };
15290        self.change_selections(Default::default(), window, cx, |s| {
15291            s.select_ranges(vec![
15292                next_diagnostic.range.start..next_diagnostic.range.start,
15293            ])
15294        });
15295        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15296        self.refresh_edit_prediction(false, true, window, cx);
15297    }
15298
15299    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15300        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15301        let snapshot = self.snapshot(window, cx);
15302        let selection = self.selections.newest::<Point>(cx);
15303        self.go_to_hunk_before_or_after_position(
15304            &snapshot,
15305            selection.head(),
15306            Direction::Next,
15307            window,
15308            cx,
15309        );
15310    }
15311
15312    pub fn go_to_hunk_before_or_after_position(
15313        &mut self,
15314        snapshot: &EditorSnapshot,
15315        position: Point,
15316        direction: Direction,
15317        window: &mut Window,
15318        cx: &mut Context<Editor>,
15319    ) {
15320        let row = if direction == Direction::Next {
15321            self.hunk_after_position(snapshot, position)
15322                .map(|hunk| hunk.row_range.start)
15323        } else {
15324            self.hunk_before_position(snapshot, position)
15325        };
15326
15327        if let Some(row) = row {
15328            let destination = Point::new(row.0, 0);
15329            let autoscroll = Autoscroll::center();
15330
15331            self.unfold_ranges(&[destination..destination], false, false, cx);
15332            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15333                s.select_ranges([destination..destination]);
15334            });
15335        }
15336    }
15337
15338    fn hunk_after_position(
15339        &mut self,
15340        snapshot: &EditorSnapshot,
15341        position: Point,
15342    ) -> Option<MultiBufferDiffHunk> {
15343        snapshot
15344            .buffer_snapshot
15345            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15346            .find(|hunk| hunk.row_range.start.0 > position.row)
15347            .or_else(|| {
15348                snapshot
15349                    .buffer_snapshot
15350                    .diff_hunks_in_range(Point::zero()..position)
15351                    .find(|hunk| hunk.row_range.end.0 < position.row)
15352            })
15353    }
15354
15355    fn go_to_prev_hunk(
15356        &mut self,
15357        _: &GoToPreviousHunk,
15358        window: &mut Window,
15359        cx: &mut Context<Self>,
15360    ) {
15361        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15362        let snapshot = self.snapshot(window, cx);
15363        let selection = self.selections.newest::<Point>(cx);
15364        self.go_to_hunk_before_or_after_position(
15365            &snapshot,
15366            selection.head(),
15367            Direction::Prev,
15368            window,
15369            cx,
15370        );
15371    }
15372
15373    fn hunk_before_position(
15374        &mut self,
15375        snapshot: &EditorSnapshot,
15376        position: Point,
15377    ) -> Option<MultiBufferRow> {
15378        snapshot
15379            .buffer_snapshot
15380            .diff_hunk_before(position)
15381            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15382    }
15383
15384    fn go_to_next_change(
15385        &mut self,
15386        _: &GoToNextChange,
15387        window: &mut Window,
15388        cx: &mut Context<Self>,
15389    ) {
15390        if let Some(selections) = self
15391            .change_list
15392            .next_change(1, Direction::Next)
15393            .map(|s| s.to_vec())
15394        {
15395            self.change_selections(Default::default(), window, cx, |s| {
15396                let map = s.display_map();
15397                s.select_display_ranges(selections.iter().map(|a| {
15398                    let point = a.to_display_point(&map);
15399                    point..point
15400                }))
15401            })
15402        }
15403    }
15404
15405    fn go_to_previous_change(
15406        &mut self,
15407        _: &GoToPreviousChange,
15408        window: &mut Window,
15409        cx: &mut Context<Self>,
15410    ) {
15411        if let Some(selections) = self
15412            .change_list
15413            .next_change(1, Direction::Prev)
15414            .map(|s| s.to_vec())
15415        {
15416            self.change_selections(Default::default(), window, cx, |s| {
15417                let map = s.display_map();
15418                s.select_display_ranges(selections.iter().map(|a| {
15419                    let point = a.to_display_point(&map);
15420                    point..point
15421                }))
15422            })
15423        }
15424    }
15425
15426    fn go_to_line<T: 'static>(
15427        &mut self,
15428        position: Anchor,
15429        highlight_color: Option<Hsla>,
15430        window: &mut Window,
15431        cx: &mut Context<Self>,
15432    ) {
15433        let snapshot = self.snapshot(window, cx).display_snapshot;
15434        let position = position.to_point(&snapshot.buffer_snapshot);
15435        let start = snapshot
15436            .buffer_snapshot
15437            .clip_point(Point::new(position.row, 0), Bias::Left);
15438        let end = start + Point::new(1, 0);
15439        let start = snapshot.buffer_snapshot.anchor_before(start);
15440        let end = snapshot.buffer_snapshot.anchor_before(end);
15441
15442        self.highlight_rows::<T>(
15443            start..end,
15444            highlight_color
15445                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15446            Default::default(),
15447            cx,
15448        );
15449
15450        if self.buffer.read(cx).is_singleton() {
15451            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15452        }
15453    }
15454
15455    pub fn go_to_definition(
15456        &mut self,
15457        _: &GoToDefinition,
15458        window: &mut Window,
15459        cx: &mut Context<Self>,
15460    ) -> Task<Result<Navigated>> {
15461        let definition =
15462            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15463        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15464        cx.spawn_in(window, async move |editor, cx| {
15465            if definition.await? == Navigated::Yes {
15466                return Ok(Navigated::Yes);
15467            }
15468            match fallback_strategy {
15469                GoToDefinitionFallback::None => Ok(Navigated::No),
15470                GoToDefinitionFallback::FindAllReferences => {
15471                    match editor.update_in(cx, |editor, window, cx| {
15472                        editor.find_all_references(&FindAllReferences, window, cx)
15473                    })? {
15474                        Some(references) => references.await,
15475                        None => Ok(Navigated::No),
15476                    }
15477                }
15478            }
15479        })
15480    }
15481
15482    pub fn go_to_declaration(
15483        &mut self,
15484        _: &GoToDeclaration,
15485        window: &mut Window,
15486        cx: &mut Context<Self>,
15487    ) -> Task<Result<Navigated>> {
15488        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15489    }
15490
15491    pub fn go_to_declaration_split(
15492        &mut self,
15493        _: &GoToDeclaration,
15494        window: &mut Window,
15495        cx: &mut Context<Self>,
15496    ) -> Task<Result<Navigated>> {
15497        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15498    }
15499
15500    pub fn go_to_implementation(
15501        &mut self,
15502        _: &GoToImplementation,
15503        window: &mut Window,
15504        cx: &mut Context<Self>,
15505    ) -> Task<Result<Navigated>> {
15506        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15507    }
15508
15509    pub fn go_to_implementation_split(
15510        &mut self,
15511        _: &GoToImplementationSplit,
15512        window: &mut Window,
15513        cx: &mut Context<Self>,
15514    ) -> Task<Result<Navigated>> {
15515        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15516    }
15517
15518    pub fn go_to_type_definition(
15519        &mut self,
15520        _: &GoToTypeDefinition,
15521        window: &mut Window,
15522        cx: &mut Context<Self>,
15523    ) -> Task<Result<Navigated>> {
15524        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15525    }
15526
15527    pub fn go_to_definition_split(
15528        &mut self,
15529        _: &GoToDefinitionSplit,
15530        window: &mut Window,
15531        cx: &mut Context<Self>,
15532    ) -> Task<Result<Navigated>> {
15533        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15534    }
15535
15536    pub fn go_to_type_definition_split(
15537        &mut self,
15538        _: &GoToTypeDefinitionSplit,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) -> Task<Result<Navigated>> {
15542        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15543    }
15544
15545    fn go_to_definition_of_kind(
15546        &mut self,
15547        kind: GotoDefinitionKind,
15548        split: bool,
15549        window: &mut Window,
15550        cx: &mut Context<Self>,
15551    ) -> Task<Result<Navigated>> {
15552        let Some(provider) = self.semantics_provider.clone() else {
15553            return Task::ready(Ok(Navigated::No));
15554        };
15555        let head = self.selections.newest::<usize>(cx).head();
15556        let buffer = self.buffer.read(cx);
15557        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15558            text_anchor
15559        } else {
15560            return Task::ready(Ok(Navigated::No));
15561        };
15562
15563        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15564            return Task::ready(Ok(Navigated::No));
15565        };
15566
15567        cx.spawn_in(window, async move |editor, cx| {
15568            let definitions = definitions.await?;
15569            let navigated = editor
15570                .update_in(cx, |editor, window, cx| {
15571                    editor.navigate_to_hover_links(
15572                        Some(kind),
15573                        definitions
15574                            .into_iter()
15575                            .filter(|location| {
15576                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15577                            })
15578                            .map(HoverLink::Text)
15579                            .collect::<Vec<_>>(),
15580                        split,
15581                        window,
15582                        cx,
15583                    )
15584                })?
15585                .await?;
15586            anyhow::Ok(navigated)
15587        })
15588    }
15589
15590    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15591        let selection = self.selections.newest_anchor();
15592        let head = selection.head();
15593        let tail = selection.tail();
15594
15595        let Some((buffer, start_position)) =
15596            self.buffer.read(cx).text_anchor_for_position(head, cx)
15597        else {
15598            return;
15599        };
15600
15601        let end_position = if head != tail {
15602            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15603                return;
15604            };
15605            Some(pos)
15606        } else {
15607            None
15608        };
15609
15610        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15611            let url = if let Some(end_pos) = end_position {
15612                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15613            } else {
15614                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15615            };
15616
15617            if let Some(url) = url {
15618                editor.update(cx, |_, cx| {
15619                    cx.open_url(&url);
15620                })
15621            } else {
15622                Ok(())
15623            }
15624        });
15625
15626        url_finder.detach();
15627    }
15628
15629    pub fn open_selected_filename(
15630        &mut self,
15631        _: &OpenSelectedFilename,
15632        window: &mut Window,
15633        cx: &mut Context<Self>,
15634    ) {
15635        let Some(workspace) = self.workspace() else {
15636            return;
15637        };
15638
15639        let position = self.selections.newest_anchor().head();
15640
15641        let Some((buffer, buffer_position)) =
15642            self.buffer.read(cx).text_anchor_for_position(position, cx)
15643        else {
15644            return;
15645        };
15646
15647        let project = self.project.clone();
15648
15649        cx.spawn_in(window, async move |_, cx| {
15650            let result = find_file(&buffer, project, buffer_position, cx).await;
15651
15652            if let Some((_, path)) = result {
15653                workspace
15654                    .update_in(cx, |workspace, window, cx| {
15655                        workspace.open_resolved_path(path, window, cx)
15656                    })?
15657                    .await?;
15658            }
15659            anyhow::Ok(())
15660        })
15661        .detach();
15662    }
15663
15664    pub(crate) fn navigate_to_hover_links(
15665        &mut self,
15666        kind: Option<GotoDefinitionKind>,
15667        mut definitions: Vec<HoverLink>,
15668        split: bool,
15669        window: &mut Window,
15670        cx: &mut Context<Editor>,
15671    ) -> Task<Result<Navigated>> {
15672        // If there is one definition, just open it directly
15673        if definitions.len() == 1 {
15674            let definition = definitions.pop().unwrap();
15675
15676            enum TargetTaskResult {
15677                Location(Option<Location>),
15678                AlreadyNavigated,
15679            }
15680
15681            let target_task = match definition {
15682                HoverLink::Text(link) => {
15683                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15684                }
15685                HoverLink::InlayHint(lsp_location, server_id) => {
15686                    let computation =
15687                        self.compute_target_location(lsp_location, server_id, window, cx);
15688                    cx.background_spawn(async move {
15689                        let location = computation.await?;
15690                        Ok(TargetTaskResult::Location(location))
15691                    })
15692                }
15693                HoverLink::Url(url) => {
15694                    cx.open_url(&url);
15695                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15696                }
15697                HoverLink::File(path) => {
15698                    if let Some(workspace) = self.workspace() {
15699                        cx.spawn_in(window, async move |_, cx| {
15700                            workspace
15701                                .update_in(cx, |workspace, window, cx| {
15702                                    workspace.open_resolved_path(path, window, cx)
15703                                })?
15704                                .await
15705                                .map(|_| TargetTaskResult::AlreadyNavigated)
15706                        })
15707                    } else {
15708                        Task::ready(Ok(TargetTaskResult::Location(None)))
15709                    }
15710                }
15711            };
15712            cx.spawn_in(window, async move |editor, cx| {
15713                let target = match target_task.await.context("target resolution task")? {
15714                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15715                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15716                    TargetTaskResult::Location(Some(target)) => target,
15717                };
15718
15719                editor.update_in(cx, |editor, window, cx| {
15720                    let Some(workspace) = editor.workspace() else {
15721                        return Navigated::No;
15722                    };
15723                    let pane = workspace.read(cx).active_pane().clone();
15724
15725                    let range = target.range.to_point(target.buffer.read(cx));
15726                    let range = editor.range_for_match(&range);
15727                    let range = collapse_multiline_range(range);
15728
15729                    if !split
15730                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15731                    {
15732                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15733                    } else {
15734                        window.defer(cx, move |window, cx| {
15735                            let target_editor: Entity<Self> =
15736                                workspace.update(cx, |workspace, cx| {
15737                                    let pane = if split {
15738                                        workspace.adjacent_pane(window, cx)
15739                                    } else {
15740                                        workspace.active_pane().clone()
15741                                    };
15742
15743                                    workspace.open_project_item(
15744                                        pane,
15745                                        target.buffer.clone(),
15746                                        true,
15747                                        true,
15748                                        window,
15749                                        cx,
15750                                    )
15751                                });
15752                            target_editor.update(cx, |target_editor, cx| {
15753                                // When selecting a definition in a different buffer, disable the nav history
15754                                // to avoid creating a history entry at the previous cursor location.
15755                                pane.update(cx, |pane, _| pane.disable_history());
15756                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15757                                pane.update(cx, |pane, _| pane.enable_history());
15758                            });
15759                        });
15760                    }
15761                    Navigated::Yes
15762                })
15763            })
15764        } else if !definitions.is_empty() {
15765            cx.spawn_in(window, async move |editor, cx| {
15766                let (title, location_tasks, workspace) = editor
15767                    .update_in(cx, |editor, window, cx| {
15768                        let tab_kind = match kind {
15769                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15770                            _ => "Definitions",
15771                        };
15772                        let title = definitions
15773                            .iter()
15774                            .find_map(|definition| match definition {
15775                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15776                                    let buffer = origin.buffer.read(cx);
15777                                    format!(
15778                                        "{} for {}",
15779                                        tab_kind,
15780                                        buffer
15781                                            .text_for_range(origin.range.clone())
15782                                            .collect::<String>()
15783                                    )
15784                                }),
15785                                HoverLink::InlayHint(_, _) => None,
15786                                HoverLink::Url(_) => None,
15787                                HoverLink::File(_) => None,
15788                            })
15789                            .unwrap_or(tab_kind.to_string());
15790                        let location_tasks = definitions
15791                            .into_iter()
15792                            .map(|definition| match definition {
15793                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15794                                HoverLink::InlayHint(lsp_location, server_id) => editor
15795                                    .compute_target_location(lsp_location, server_id, window, cx),
15796                                HoverLink::Url(_) => Task::ready(Ok(None)),
15797                                HoverLink::File(_) => Task::ready(Ok(None)),
15798                            })
15799                            .collect::<Vec<_>>();
15800                        (title, location_tasks, editor.workspace().clone())
15801                    })
15802                    .context("location tasks preparation")?;
15803
15804                let locations: Vec<Location> = future::join_all(location_tasks)
15805                    .await
15806                    .into_iter()
15807                    .filter_map(|location| location.transpose())
15808                    .collect::<Result<_>>()
15809                    .context("location tasks")?;
15810
15811                if locations.is_empty() {
15812                    return Ok(Navigated::No);
15813                }
15814
15815                let Some(workspace) = workspace else {
15816                    return Ok(Navigated::No);
15817                };
15818
15819                let opened = workspace
15820                    .update_in(cx, |workspace, window, cx| {
15821                        Self::open_locations_in_multibuffer(
15822                            workspace,
15823                            locations,
15824                            title,
15825                            split,
15826                            MultibufferSelectionMode::First,
15827                            window,
15828                            cx,
15829                        )
15830                    })
15831                    .ok();
15832
15833                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15834            })
15835        } else {
15836            Task::ready(Ok(Navigated::No))
15837        }
15838    }
15839
15840    fn compute_target_location(
15841        &self,
15842        lsp_location: lsp::Location,
15843        server_id: LanguageServerId,
15844        window: &mut Window,
15845        cx: &mut Context<Self>,
15846    ) -> Task<anyhow::Result<Option<Location>>> {
15847        let Some(project) = self.project.clone() else {
15848            return Task::ready(Ok(None));
15849        };
15850
15851        cx.spawn_in(window, async move |editor, cx| {
15852            let location_task = editor.update(cx, |_, cx| {
15853                project.update(cx, |project, cx| {
15854                    let language_server_name = project
15855                        .language_server_statuses(cx)
15856                        .find(|(id, _)| server_id == *id)
15857                        .map(|(_, status)| status.name.clone());
15858                    language_server_name.map(|language_server_name| {
15859                        project.open_local_buffer_via_lsp(
15860                            lsp_location.uri.clone(),
15861                            server_id,
15862                            language_server_name,
15863                            cx,
15864                        )
15865                    })
15866                })
15867            })?;
15868            let location = match location_task {
15869                Some(task) => Some({
15870                    let target_buffer_handle = task.await.context("open local buffer")?;
15871                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15872                        let target_start = target_buffer
15873                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15874                        let target_end = target_buffer
15875                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15876                        target_buffer.anchor_after(target_start)
15877                            ..target_buffer.anchor_before(target_end)
15878                    })?;
15879                    Location {
15880                        buffer: target_buffer_handle,
15881                        range,
15882                    }
15883                }),
15884                None => None,
15885            };
15886            Ok(location)
15887        })
15888    }
15889
15890    pub fn find_all_references(
15891        &mut self,
15892        _: &FindAllReferences,
15893        window: &mut Window,
15894        cx: &mut Context<Self>,
15895    ) -> Option<Task<Result<Navigated>>> {
15896        let selection = self.selections.newest::<usize>(cx);
15897        let multi_buffer = self.buffer.read(cx);
15898        let head = selection.head();
15899
15900        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15901        let head_anchor = multi_buffer_snapshot.anchor_at(
15902            head,
15903            if head < selection.tail() {
15904                Bias::Right
15905            } else {
15906                Bias::Left
15907            },
15908        );
15909
15910        match self
15911            .find_all_references_task_sources
15912            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15913        {
15914            Ok(_) => {
15915                log::info!(
15916                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15917                );
15918                return None;
15919            }
15920            Err(i) => {
15921                self.find_all_references_task_sources.insert(i, head_anchor);
15922            }
15923        }
15924
15925        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15926        let workspace = self.workspace()?;
15927        let project = workspace.read(cx).project().clone();
15928        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15929        Some(cx.spawn_in(window, async move |editor, cx| {
15930            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15931                if let Ok(i) = editor
15932                    .find_all_references_task_sources
15933                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15934                {
15935                    editor.find_all_references_task_sources.remove(i);
15936                }
15937            });
15938
15939            let locations = references.await?;
15940            if locations.is_empty() {
15941                return anyhow::Ok(Navigated::No);
15942            }
15943
15944            workspace.update_in(cx, |workspace, window, cx| {
15945                let title = locations
15946                    .first()
15947                    .as_ref()
15948                    .map(|location| {
15949                        let buffer = location.buffer.read(cx);
15950                        format!(
15951                            "References to `{}`",
15952                            buffer
15953                                .text_for_range(location.range.clone())
15954                                .collect::<String>()
15955                        )
15956                    })
15957                    .unwrap();
15958                Self::open_locations_in_multibuffer(
15959                    workspace,
15960                    locations,
15961                    title,
15962                    false,
15963                    MultibufferSelectionMode::First,
15964                    window,
15965                    cx,
15966                );
15967                Navigated::Yes
15968            })
15969        }))
15970    }
15971
15972    /// Opens a multibuffer with the given project locations in it
15973    pub fn open_locations_in_multibuffer(
15974        workspace: &mut Workspace,
15975        mut locations: Vec<Location>,
15976        title: String,
15977        split: bool,
15978        multibuffer_selection_mode: MultibufferSelectionMode,
15979        window: &mut Window,
15980        cx: &mut Context<Workspace>,
15981    ) {
15982        if locations.is_empty() {
15983            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15984            return;
15985        }
15986
15987        // If there are multiple definitions, open them in a multibuffer
15988        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15989        let mut locations = locations.into_iter().peekable();
15990        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15991        let capability = workspace.project().read(cx).capability();
15992
15993        let excerpt_buffer = cx.new(|cx| {
15994            let mut multibuffer = MultiBuffer::new(capability);
15995            while let Some(location) = locations.next() {
15996                let buffer = location.buffer.read(cx);
15997                let mut ranges_for_buffer = Vec::new();
15998                let range = location.range.to_point(buffer);
15999                ranges_for_buffer.push(range.clone());
16000
16001                while let Some(next_location) = locations.peek() {
16002                    if next_location.buffer == location.buffer {
16003                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16004                        locations.next();
16005                    } else {
16006                        break;
16007                    }
16008                }
16009
16010                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16011                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16012                    PathKey::for_buffer(&location.buffer, cx),
16013                    location.buffer.clone(),
16014                    ranges_for_buffer,
16015                    DEFAULT_MULTIBUFFER_CONTEXT,
16016                    cx,
16017                );
16018                ranges.extend(new_ranges)
16019            }
16020
16021            multibuffer.with_title(title)
16022        });
16023
16024        let editor = cx.new(|cx| {
16025            Editor::for_multibuffer(
16026                excerpt_buffer,
16027                Some(workspace.project().clone()),
16028                window,
16029                cx,
16030            )
16031        });
16032        editor.update(cx, |editor, cx| {
16033            match multibuffer_selection_mode {
16034                MultibufferSelectionMode::First => {
16035                    if let Some(first_range) = ranges.first() {
16036                        editor.change_selections(
16037                            SelectionEffects::no_scroll(),
16038                            window,
16039                            cx,
16040                            |selections| {
16041                                selections.clear_disjoint();
16042                                selections
16043                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16044                            },
16045                        );
16046                    }
16047                    editor.highlight_background::<Self>(
16048                        &ranges,
16049                        |theme| theme.colors().editor_highlighted_line_background,
16050                        cx,
16051                    );
16052                }
16053                MultibufferSelectionMode::All => {
16054                    editor.change_selections(
16055                        SelectionEffects::no_scroll(),
16056                        window,
16057                        cx,
16058                        |selections| {
16059                            selections.clear_disjoint();
16060                            selections.select_anchor_ranges(ranges);
16061                        },
16062                    );
16063                }
16064            }
16065            editor.register_buffers_with_language_servers(cx);
16066        });
16067
16068        let item = Box::new(editor);
16069        let item_id = item.item_id();
16070
16071        if split {
16072            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16073        } else {
16074            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16075                let (preview_item_id, preview_item_idx) =
16076                    workspace.active_pane().read_with(cx, |pane, _| {
16077                        (pane.preview_item_id(), pane.preview_item_idx())
16078                    });
16079
16080                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16081
16082                if let Some(preview_item_id) = preview_item_id {
16083                    workspace.active_pane().update(cx, |pane, cx| {
16084                        pane.remove_item(preview_item_id, false, false, window, cx);
16085                    });
16086                }
16087            } else {
16088                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16089            }
16090        }
16091        workspace.active_pane().update(cx, |pane, cx| {
16092            pane.set_preview_item_id(Some(item_id), cx);
16093        });
16094    }
16095
16096    pub fn rename(
16097        &mut self,
16098        _: &Rename,
16099        window: &mut Window,
16100        cx: &mut Context<Self>,
16101    ) -> Option<Task<Result<()>>> {
16102        use language::ToOffset as _;
16103
16104        let provider = self.semantics_provider.clone()?;
16105        let selection = self.selections.newest_anchor().clone();
16106        let (cursor_buffer, cursor_buffer_position) = self
16107            .buffer
16108            .read(cx)
16109            .text_anchor_for_position(selection.head(), cx)?;
16110        let (tail_buffer, cursor_buffer_position_end) = self
16111            .buffer
16112            .read(cx)
16113            .text_anchor_for_position(selection.tail(), cx)?;
16114        if tail_buffer != cursor_buffer {
16115            return None;
16116        }
16117
16118        let snapshot = cursor_buffer.read(cx).snapshot();
16119        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16120        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16121        let prepare_rename = provider
16122            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16123            .unwrap_or_else(|| Task::ready(Ok(None)));
16124        drop(snapshot);
16125
16126        Some(cx.spawn_in(window, async move |this, cx| {
16127            let rename_range = if let Some(range) = prepare_rename.await? {
16128                Some(range)
16129            } else {
16130                this.update(cx, |this, cx| {
16131                    let buffer = this.buffer.read(cx).snapshot(cx);
16132                    let mut buffer_highlights = this
16133                        .document_highlights_for_position(selection.head(), &buffer)
16134                        .filter(|highlight| {
16135                            highlight.start.excerpt_id == selection.head().excerpt_id
16136                                && highlight.end.excerpt_id == selection.head().excerpt_id
16137                        });
16138                    buffer_highlights
16139                        .next()
16140                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16141                })?
16142            };
16143            if let Some(rename_range) = rename_range {
16144                this.update_in(cx, |this, window, cx| {
16145                    let snapshot = cursor_buffer.read(cx).snapshot();
16146                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16147                    let cursor_offset_in_rename_range =
16148                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16149                    let cursor_offset_in_rename_range_end =
16150                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16151
16152                    this.take_rename(false, window, cx);
16153                    let buffer = this.buffer.read(cx).read(cx);
16154                    let cursor_offset = selection.head().to_offset(&buffer);
16155                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16156                    let rename_end = rename_start + rename_buffer_range.len();
16157                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16158                    let mut old_highlight_id = None;
16159                    let old_name: Arc<str> = buffer
16160                        .chunks(rename_start..rename_end, true)
16161                        .map(|chunk| {
16162                            if old_highlight_id.is_none() {
16163                                old_highlight_id = chunk.syntax_highlight_id;
16164                            }
16165                            chunk.text
16166                        })
16167                        .collect::<String>()
16168                        .into();
16169
16170                    drop(buffer);
16171
16172                    // Position the selection in the rename editor so that it matches the current selection.
16173                    this.show_local_selections = false;
16174                    let rename_editor = cx.new(|cx| {
16175                        let mut editor = Editor::single_line(window, cx);
16176                        editor.buffer.update(cx, |buffer, cx| {
16177                            buffer.edit([(0..0, old_name.clone())], None, cx)
16178                        });
16179                        let rename_selection_range = match cursor_offset_in_rename_range
16180                            .cmp(&cursor_offset_in_rename_range_end)
16181                        {
16182                            Ordering::Equal => {
16183                                editor.select_all(&SelectAll, window, cx);
16184                                return editor;
16185                            }
16186                            Ordering::Less => {
16187                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16188                            }
16189                            Ordering::Greater => {
16190                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16191                            }
16192                        };
16193                        if rename_selection_range.end > old_name.len() {
16194                            editor.select_all(&SelectAll, window, cx);
16195                        } else {
16196                            editor.change_selections(Default::default(), window, cx, |s| {
16197                                s.select_ranges([rename_selection_range]);
16198                            });
16199                        }
16200                        editor
16201                    });
16202                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16203                        if e == &EditorEvent::Focused {
16204                            cx.emit(EditorEvent::FocusedIn)
16205                        }
16206                    })
16207                    .detach();
16208
16209                    let write_highlights =
16210                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16211                    let read_highlights =
16212                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16213                    let ranges = write_highlights
16214                        .iter()
16215                        .flat_map(|(_, ranges)| ranges.iter())
16216                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16217                        .cloned()
16218                        .collect();
16219
16220                    this.highlight_text::<Rename>(
16221                        ranges,
16222                        HighlightStyle {
16223                            fade_out: Some(0.6),
16224                            ..Default::default()
16225                        },
16226                        cx,
16227                    );
16228                    let rename_focus_handle = rename_editor.focus_handle(cx);
16229                    window.focus(&rename_focus_handle);
16230                    let block_id = this.insert_blocks(
16231                        [BlockProperties {
16232                            style: BlockStyle::Flex,
16233                            placement: BlockPlacement::Below(range.start),
16234                            height: Some(1),
16235                            render: Arc::new({
16236                                let rename_editor = rename_editor.clone();
16237                                move |cx: &mut BlockContext| {
16238                                    let mut text_style = cx.editor_style.text.clone();
16239                                    if let Some(highlight_style) = old_highlight_id
16240                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16241                                    {
16242                                        text_style = text_style.highlight(highlight_style);
16243                                    }
16244                                    div()
16245                                        .block_mouse_except_scroll()
16246                                        .pl(cx.anchor_x)
16247                                        .child(EditorElement::new(
16248                                            &rename_editor,
16249                                            EditorStyle {
16250                                                background: cx.theme().system().transparent,
16251                                                local_player: cx.editor_style.local_player,
16252                                                text: text_style,
16253                                                scrollbar_width: cx.editor_style.scrollbar_width,
16254                                                syntax: cx.editor_style.syntax.clone(),
16255                                                status: cx.editor_style.status.clone(),
16256                                                inlay_hints_style: HighlightStyle {
16257                                                    font_weight: Some(FontWeight::BOLD),
16258                                                    ..make_inlay_hints_style(cx.app)
16259                                                },
16260                                                edit_prediction_styles: make_suggestion_styles(
16261                                                    cx.app,
16262                                                ),
16263                                                ..EditorStyle::default()
16264                                            },
16265                                        ))
16266                                        .into_any_element()
16267                                }
16268                            }),
16269                            priority: 0,
16270                        }],
16271                        Some(Autoscroll::fit()),
16272                        cx,
16273                    )[0];
16274                    this.pending_rename = Some(RenameState {
16275                        range,
16276                        old_name,
16277                        editor: rename_editor,
16278                        block_id,
16279                    });
16280                })?;
16281            }
16282
16283            Ok(())
16284        }))
16285    }
16286
16287    pub fn confirm_rename(
16288        &mut self,
16289        _: &ConfirmRename,
16290        window: &mut Window,
16291        cx: &mut Context<Self>,
16292    ) -> Option<Task<Result<()>>> {
16293        let rename = self.take_rename(false, window, cx)?;
16294        let workspace = self.workspace()?.downgrade();
16295        let (buffer, start) = self
16296            .buffer
16297            .read(cx)
16298            .text_anchor_for_position(rename.range.start, cx)?;
16299        let (end_buffer, _) = self
16300            .buffer
16301            .read(cx)
16302            .text_anchor_for_position(rename.range.end, cx)?;
16303        if buffer != end_buffer {
16304            return None;
16305        }
16306
16307        let old_name = rename.old_name;
16308        let new_name = rename.editor.read(cx).text(cx);
16309
16310        let rename = self.semantics_provider.as_ref()?.perform_rename(
16311            &buffer,
16312            start,
16313            new_name.clone(),
16314            cx,
16315        )?;
16316
16317        Some(cx.spawn_in(window, async move |editor, cx| {
16318            let project_transaction = rename.await?;
16319            Self::open_project_transaction(
16320                &editor,
16321                workspace,
16322                project_transaction,
16323                format!("Rename: {}{}", old_name, new_name),
16324                cx,
16325            )
16326            .await?;
16327
16328            editor.update(cx, |editor, cx| {
16329                editor.refresh_document_highlights(cx);
16330            })?;
16331            Ok(())
16332        }))
16333    }
16334
16335    fn take_rename(
16336        &mut self,
16337        moving_cursor: bool,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) -> Option<RenameState> {
16341        let rename = self.pending_rename.take()?;
16342        if rename.editor.focus_handle(cx).is_focused(window) {
16343            window.focus(&self.focus_handle);
16344        }
16345
16346        self.remove_blocks(
16347            [rename.block_id].into_iter().collect(),
16348            Some(Autoscroll::fit()),
16349            cx,
16350        );
16351        self.clear_highlights::<Rename>(cx);
16352        self.show_local_selections = true;
16353
16354        if moving_cursor {
16355            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16356                editor.selections.newest::<usize>(cx).head()
16357            });
16358
16359            // Update the selection to match the position of the selection inside
16360            // the rename editor.
16361            let snapshot = self.buffer.read(cx).read(cx);
16362            let rename_range = rename.range.to_offset(&snapshot);
16363            let cursor_in_editor = snapshot
16364                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16365                .min(rename_range.end);
16366            drop(snapshot);
16367
16368            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16369                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16370            });
16371        } else {
16372            self.refresh_document_highlights(cx);
16373        }
16374
16375        Some(rename)
16376    }
16377
16378    pub fn pending_rename(&self) -> Option<&RenameState> {
16379        self.pending_rename.as_ref()
16380    }
16381
16382    fn format(
16383        &mut self,
16384        _: &Format,
16385        window: &mut Window,
16386        cx: &mut Context<Self>,
16387    ) -> Option<Task<Result<()>>> {
16388        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16389
16390        let project = match &self.project {
16391            Some(project) => project.clone(),
16392            None => return None,
16393        };
16394
16395        Some(self.perform_format(
16396            project,
16397            FormatTrigger::Manual,
16398            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16399            window,
16400            cx,
16401        ))
16402    }
16403
16404    fn format_selections(
16405        &mut self,
16406        _: &FormatSelections,
16407        window: &mut Window,
16408        cx: &mut Context<Self>,
16409    ) -> Option<Task<Result<()>>> {
16410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16411
16412        let project = match &self.project {
16413            Some(project) => project.clone(),
16414            None => return None,
16415        };
16416
16417        let ranges = self
16418            .selections
16419            .all_adjusted(cx)
16420            .into_iter()
16421            .map(|selection| selection.range())
16422            .collect_vec();
16423
16424        Some(self.perform_format(
16425            project,
16426            FormatTrigger::Manual,
16427            FormatTarget::Ranges(ranges),
16428            window,
16429            cx,
16430        ))
16431    }
16432
16433    fn perform_format(
16434        &mut self,
16435        project: Entity<Project>,
16436        trigger: FormatTrigger,
16437        target: FormatTarget,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) -> Task<Result<()>> {
16441        let buffer = self.buffer.clone();
16442        let (buffers, target) = match target {
16443            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16444            FormatTarget::Ranges(selection_ranges) => {
16445                let multi_buffer = buffer.read(cx);
16446                let snapshot = multi_buffer.read(cx);
16447                let mut buffers = HashSet::default();
16448                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16449                    BTreeMap::new();
16450                for selection_range in selection_ranges {
16451                    for (buffer, buffer_range, _) in
16452                        snapshot.range_to_buffer_ranges(selection_range)
16453                    {
16454                        let buffer_id = buffer.remote_id();
16455                        let start = buffer.anchor_before(buffer_range.start);
16456                        let end = buffer.anchor_after(buffer_range.end);
16457                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16458                        buffer_id_to_ranges
16459                            .entry(buffer_id)
16460                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16461                            .or_insert_with(|| vec![start..end]);
16462                    }
16463                }
16464                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16465            }
16466        };
16467
16468        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16469        let selections_prev = transaction_id_prev
16470            .and_then(|transaction_id_prev| {
16471                // default to selections as they were after the last edit, if we have them,
16472                // instead of how they are now.
16473                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16474                // will take you back to where you made the last edit, instead of staying where you scrolled
16475                self.selection_history
16476                    .transaction(transaction_id_prev)
16477                    .map(|t| t.0.clone())
16478            })
16479            .unwrap_or_else(|| {
16480                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16481                self.selections.disjoint_anchors()
16482            });
16483
16484        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16485        let format = project.update(cx, |project, cx| {
16486            project.format(buffers, target, true, trigger, cx)
16487        });
16488
16489        cx.spawn_in(window, async move |editor, cx| {
16490            let transaction = futures::select_biased! {
16491                transaction = format.log_err().fuse() => transaction,
16492                () = timeout => {
16493                    log::warn!("timed out waiting for formatting");
16494                    None
16495                }
16496            };
16497
16498            buffer
16499                .update(cx, |buffer, cx| {
16500                    if let Some(transaction) = transaction {
16501                        if !buffer.is_singleton() {
16502                            buffer.push_transaction(&transaction.0, cx);
16503                        }
16504                    }
16505                    cx.notify();
16506                })
16507                .ok();
16508
16509            if let Some(transaction_id_now) =
16510                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16511            {
16512                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16513                if has_new_transaction {
16514                    _ = editor.update(cx, |editor, _| {
16515                        editor
16516                            .selection_history
16517                            .insert_transaction(transaction_id_now, selections_prev);
16518                    });
16519                }
16520            }
16521
16522            Ok(())
16523        })
16524    }
16525
16526    fn organize_imports(
16527        &mut self,
16528        _: &OrganizeImports,
16529        window: &mut Window,
16530        cx: &mut Context<Self>,
16531    ) -> Option<Task<Result<()>>> {
16532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16533        let project = match &self.project {
16534            Some(project) => project.clone(),
16535            None => return None,
16536        };
16537        Some(self.perform_code_action_kind(
16538            project,
16539            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16540            window,
16541            cx,
16542        ))
16543    }
16544
16545    fn perform_code_action_kind(
16546        &mut self,
16547        project: Entity<Project>,
16548        kind: CodeActionKind,
16549        window: &mut Window,
16550        cx: &mut Context<Self>,
16551    ) -> Task<Result<()>> {
16552        let buffer = self.buffer.clone();
16553        let buffers = buffer.read(cx).all_buffers();
16554        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16555        let apply_action = project.update(cx, |project, cx| {
16556            project.apply_code_action_kind(buffers, kind, true, cx)
16557        });
16558        cx.spawn_in(window, async move |_, cx| {
16559            let transaction = futures::select_biased! {
16560                () = timeout => {
16561                    log::warn!("timed out waiting for executing code action");
16562                    None
16563                }
16564                transaction = apply_action.log_err().fuse() => transaction,
16565            };
16566            buffer
16567                .update(cx, |buffer, cx| {
16568                    // check if we need this
16569                    if let Some(transaction) = transaction {
16570                        if !buffer.is_singleton() {
16571                            buffer.push_transaction(&transaction.0, cx);
16572                        }
16573                    }
16574                    cx.notify();
16575                })
16576                .ok();
16577            Ok(())
16578        })
16579    }
16580
16581    pub fn restart_language_server(
16582        &mut self,
16583        _: &RestartLanguageServer,
16584        _: &mut Window,
16585        cx: &mut Context<Self>,
16586    ) {
16587        if let Some(project) = self.project.clone() {
16588            self.buffer.update(cx, |multi_buffer, cx| {
16589                project.update(cx, |project, cx| {
16590                    project.restart_language_servers_for_buffers(
16591                        multi_buffer.all_buffers().into_iter().collect(),
16592                        HashSet::default(),
16593                        cx,
16594                    );
16595                });
16596            })
16597        }
16598    }
16599
16600    pub fn stop_language_server(
16601        &mut self,
16602        _: &StopLanguageServer,
16603        _: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) {
16606        if let Some(project) = self.project.clone() {
16607            self.buffer.update(cx, |multi_buffer, cx| {
16608                project.update(cx, |project, cx| {
16609                    project.stop_language_servers_for_buffers(
16610                        multi_buffer.all_buffers().into_iter().collect(),
16611                        HashSet::default(),
16612                        cx,
16613                    );
16614                    cx.emit(project::Event::RefreshInlayHints);
16615                });
16616            });
16617        }
16618    }
16619
16620    fn cancel_language_server_work(
16621        workspace: &mut Workspace,
16622        _: &actions::CancelLanguageServerWork,
16623        _: &mut Window,
16624        cx: &mut Context<Workspace>,
16625    ) {
16626        let project = workspace.project();
16627        let buffers = workspace
16628            .active_item(cx)
16629            .and_then(|item| item.act_as::<Editor>(cx))
16630            .map_or(HashSet::default(), |editor| {
16631                editor.read(cx).buffer.read(cx).all_buffers()
16632            });
16633        project.update(cx, |project, cx| {
16634            project.cancel_language_server_work_for_buffers(buffers, cx);
16635        });
16636    }
16637
16638    fn show_character_palette(
16639        &mut self,
16640        _: &ShowCharacterPalette,
16641        window: &mut Window,
16642        _: &mut Context<Self>,
16643    ) {
16644        window.show_character_palette();
16645    }
16646
16647    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16648        if !self.diagnostics_enabled() {
16649            return;
16650        }
16651
16652        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16653            let buffer = self.buffer.read(cx).snapshot(cx);
16654            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16655            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16656            let is_valid = buffer
16657                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16658                .any(|entry| {
16659                    entry.diagnostic.is_primary
16660                        && !entry.range.is_empty()
16661                        && entry.range.start == primary_range_start
16662                        && entry.diagnostic.message == active_diagnostics.active_message
16663                });
16664
16665            if !is_valid {
16666                self.dismiss_diagnostics(cx);
16667            }
16668        }
16669    }
16670
16671    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16672        match &self.active_diagnostics {
16673            ActiveDiagnostic::Group(group) => Some(group),
16674            _ => None,
16675        }
16676    }
16677
16678    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16679        if !self.diagnostics_enabled() {
16680            return;
16681        }
16682        self.dismiss_diagnostics(cx);
16683        self.active_diagnostics = ActiveDiagnostic::All;
16684    }
16685
16686    fn activate_diagnostics(
16687        &mut self,
16688        buffer_id: BufferId,
16689        diagnostic: DiagnosticEntry<usize>,
16690        window: &mut Window,
16691        cx: &mut Context<Self>,
16692    ) {
16693        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16694            return;
16695        }
16696        self.dismiss_diagnostics(cx);
16697        let snapshot = self.snapshot(window, cx);
16698        let buffer = self.buffer.read(cx).snapshot(cx);
16699        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16700            return;
16701        };
16702
16703        let diagnostic_group = buffer
16704            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16705            .collect::<Vec<_>>();
16706
16707        let blocks =
16708            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16709
16710        let blocks = self.display_map.update(cx, |display_map, cx| {
16711            display_map.insert_blocks(blocks, cx).into_iter().collect()
16712        });
16713        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16714            active_range: buffer.anchor_before(diagnostic.range.start)
16715                ..buffer.anchor_after(diagnostic.range.end),
16716            active_message: diagnostic.diagnostic.message.clone(),
16717            group_id: diagnostic.diagnostic.group_id,
16718            blocks,
16719        });
16720        cx.notify();
16721    }
16722
16723    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16724        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16725            return;
16726        };
16727
16728        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16729        if let ActiveDiagnostic::Group(group) = prev {
16730            self.display_map.update(cx, |display_map, cx| {
16731                display_map.remove_blocks(group.blocks, cx);
16732            });
16733            cx.notify();
16734        }
16735    }
16736
16737    /// Disable inline diagnostics rendering for this editor.
16738    pub fn disable_inline_diagnostics(&mut self) {
16739        self.inline_diagnostics_enabled = false;
16740        self.inline_diagnostics_update = Task::ready(());
16741        self.inline_diagnostics.clear();
16742    }
16743
16744    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16745        self.diagnostics_enabled = false;
16746        self.dismiss_diagnostics(cx);
16747        self.inline_diagnostics_update = Task::ready(());
16748        self.inline_diagnostics.clear();
16749    }
16750
16751    pub fn diagnostics_enabled(&self) -> bool {
16752        self.diagnostics_enabled && self.mode.is_full()
16753    }
16754
16755    pub fn inline_diagnostics_enabled(&self) -> bool {
16756        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16757    }
16758
16759    pub fn show_inline_diagnostics(&self) -> bool {
16760        self.show_inline_diagnostics
16761    }
16762
16763    pub fn toggle_inline_diagnostics(
16764        &mut self,
16765        _: &ToggleInlineDiagnostics,
16766        window: &mut Window,
16767        cx: &mut Context<Editor>,
16768    ) {
16769        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16770        self.refresh_inline_diagnostics(false, window, cx);
16771    }
16772
16773    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16774        self.diagnostics_max_severity = severity;
16775        self.display_map.update(cx, |display_map, _| {
16776            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16777        });
16778    }
16779
16780    pub fn toggle_diagnostics(
16781        &mut self,
16782        _: &ToggleDiagnostics,
16783        window: &mut Window,
16784        cx: &mut Context<Editor>,
16785    ) {
16786        if !self.diagnostics_enabled() {
16787            return;
16788        }
16789
16790        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16791            EditorSettings::get_global(cx)
16792                .diagnostics_max_severity
16793                .filter(|severity| severity != &DiagnosticSeverity::Off)
16794                .unwrap_or(DiagnosticSeverity::Hint)
16795        } else {
16796            DiagnosticSeverity::Off
16797        };
16798        self.set_max_diagnostics_severity(new_severity, cx);
16799        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16800            self.active_diagnostics = ActiveDiagnostic::None;
16801            self.inline_diagnostics_update = Task::ready(());
16802            self.inline_diagnostics.clear();
16803        } else {
16804            self.refresh_inline_diagnostics(false, window, cx);
16805        }
16806
16807        cx.notify();
16808    }
16809
16810    pub fn toggle_minimap(
16811        &mut self,
16812        _: &ToggleMinimap,
16813        window: &mut Window,
16814        cx: &mut Context<Editor>,
16815    ) {
16816        if self.supports_minimap(cx) {
16817            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16818        }
16819    }
16820
16821    fn refresh_inline_diagnostics(
16822        &mut self,
16823        debounce: bool,
16824        window: &mut Window,
16825        cx: &mut Context<Self>,
16826    ) {
16827        let max_severity = ProjectSettings::get_global(cx)
16828            .diagnostics
16829            .inline
16830            .max_severity
16831            .unwrap_or(self.diagnostics_max_severity);
16832
16833        if !self.inline_diagnostics_enabled()
16834            || !self.show_inline_diagnostics
16835            || max_severity == DiagnosticSeverity::Off
16836        {
16837            self.inline_diagnostics_update = Task::ready(());
16838            self.inline_diagnostics.clear();
16839            return;
16840        }
16841
16842        let debounce_ms = ProjectSettings::get_global(cx)
16843            .diagnostics
16844            .inline
16845            .update_debounce_ms;
16846        let debounce = if debounce && debounce_ms > 0 {
16847            Some(Duration::from_millis(debounce_ms))
16848        } else {
16849            None
16850        };
16851        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16852            if let Some(debounce) = debounce {
16853                cx.background_executor().timer(debounce).await;
16854            }
16855            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16856                editor
16857                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16858                    .ok()
16859            }) else {
16860                return;
16861            };
16862
16863            let new_inline_diagnostics = cx
16864                .background_spawn(async move {
16865                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16866                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16867                        let message = diagnostic_entry
16868                            .diagnostic
16869                            .message
16870                            .split_once('\n')
16871                            .map(|(line, _)| line)
16872                            .map(SharedString::new)
16873                            .unwrap_or_else(|| {
16874                                SharedString::from(diagnostic_entry.diagnostic.message)
16875                            });
16876                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16877                        let (Ok(i) | Err(i)) = inline_diagnostics
16878                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16879                        inline_diagnostics.insert(
16880                            i,
16881                            (
16882                                start_anchor,
16883                                InlineDiagnostic {
16884                                    message,
16885                                    group_id: diagnostic_entry.diagnostic.group_id,
16886                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16887                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16888                                    severity: diagnostic_entry.diagnostic.severity,
16889                                },
16890                            ),
16891                        );
16892                    }
16893                    inline_diagnostics
16894                })
16895                .await;
16896
16897            editor
16898                .update(cx, |editor, cx| {
16899                    editor.inline_diagnostics = new_inline_diagnostics;
16900                    cx.notify();
16901                })
16902                .ok();
16903        });
16904    }
16905
16906    fn pull_diagnostics(
16907        &mut self,
16908        buffer_id: Option<BufferId>,
16909        window: &Window,
16910        cx: &mut Context<Self>,
16911    ) -> Option<()> {
16912        if !self.mode().is_full() {
16913            return None;
16914        }
16915        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16916            .diagnostics
16917            .lsp_pull_diagnostics;
16918        if !pull_diagnostics_settings.enabled {
16919            return None;
16920        }
16921        let project = self.project.as_ref()?.downgrade();
16922        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16923        let mut buffers = self.buffer.read(cx).all_buffers();
16924        if let Some(buffer_id) = buffer_id {
16925            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16926        }
16927
16928        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16929            cx.background_executor().timer(debounce).await;
16930
16931            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16932                buffers
16933                    .into_iter()
16934                    .filter_map(|buffer| {
16935                        project
16936                            .update(cx, |project, cx| {
16937                                project.lsp_store().update(cx, |lsp_store, cx| {
16938                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16939                                })
16940                            })
16941                            .ok()
16942                    })
16943                    .collect::<FuturesUnordered<_>>()
16944            }) else {
16945                return;
16946            };
16947
16948            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16949                match pull_task {
16950                    Ok(()) => {
16951                        if editor
16952                            .update_in(cx, |editor, window, cx| {
16953                                editor.update_diagnostics_state(window, cx);
16954                            })
16955                            .is_err()
16956                        {
16957                            return;
16958                        }
16959                    }
16960                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16961                }
16962            }
16963        });
16964
16965        Some(())
16966    }
16967
16968    pub fn set_selections_from_remote(
16969        &mut self,
16970        selections: Vec<Selection<Anchor>>,
16971        pending_selection: Option<Selection<Anchor>>,
16972        window: &mut Window,
16973        cx: &mut Context<Self>,
16974    ) {
16975        let old_cursor_position = self.selections.newest_anchor().head();
16976        self.selections.change_with(cx, |s| {
16977            s.select_anchors(selections);
16978            if let Some(pending_selection) = pending_selection {
16979                s.set_pending(pending_selection, SelectMode::Character);
16980            } else {
16981                s.clear_pending();
16982            }
16983        });
16984        self.selections_did_change(
16985            false,
16986            &old_cursor_position,
16987            SelectionEffects::default(),
16988            window,
16989            cx,
16990        );
16991    }
16992
16993    pub fn transact(
16994        &mut self,
16995        window: &mut Window,
16996        cx: &mut Context<Self>,
16997        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16998    ) -> Option<TransactionId> {
16999        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17000            this.start_transaction_at(Instant::now(), window, cx);
17001            update(this, window, cx);
17002            this.end_transaction_at(Instant::now(), cx)
17003        })
17004    }
17005
17006    pub fn start_transaction_at(
17007        &mut self,
17008        now: Instant,
17009        window: &mut Window,
17010        cx: &mut Context<Self>,
17011    ) -> Option<TransactionId> {
17012        self.end_selection(window, cx);
17013        if let Some(tx_id) = self
17014            .buffer
17015            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17016        {
17017            self.selection_history
17018                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17019            cx.emit(EditorEvent::TransactionBegun {
17020                transaction_id: tx_id,
17021            });
17022            Some(tx_id)
17023        } else {
17024            None
17025        }
17026    }
17027
17028    pub fn end_transaction_at(
17029        &mut self,
17030        now: Instant,
17031        cx: &mut Context<Self>,
17032    ) -> Option<TransactionId> {
17033        if let Some(transaction_id) = self
17034            .buffer
17035            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17036        {
17037            if let Some((_, end_selections)) =
17038                self.selection_history.transaction_mut(transaction_id)
17039            {
17040                *end_selections = Some(self.selections.disjoint_anchors());
17041            } else {
17042                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17043            }
17044
17045            cx.emit(EditorEvent::Edited { transaction_id });
17046            Some(transaction_id)
17047        } else {
17048            None
17049        }
17050    }
17051
17052    pub fn modify_transaction_selection_history(
17053        &mut self,
17054        transaction_id: TransactionId,
17055        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17056    ) -> bool {
17057        self.selection_history
17058            .transaction_mut(transaction_id)
17059            .map(modify)
17060            .is_some()
17061    }
17062
17063    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17064        if self.selection_mark_mode {
17065            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17066                s.move_with(|_, sel| {
17067                    sel.collapse_to(sel.head(), SelectionGoal::None);
17068                });
17069            })
17070        }
17071        self.selection_mark_mode = true;
17072        cx.notify();
17073    }
17074
17075    pub fn swap_selection_ends(
17076        &mut self,
17077        _: &actions::SwapSelectionEnds,
17078        window: &mut Window,
17079        cx: &mut Context<Self>,
17080    ) {
17081        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17082            s.move_with(|_, sel| {
17083                if sel.start != sel.end {
17084                    sel.reversed = !sel.reversed
17085                }
17086            });
17087        });
17088        self.request_autoscroll(Autoscroll::newest(), cx);
17089        cx.notify();
17090    }
17091
17092    pub fn toggle_focus(
17093        workspace: &mut Workspace,
17094        _: &actions::ToggleFocus,
17095        window: &mut Window,
17096        cx: &mut Context<Workspace>,
17097    ) {
17098        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17099            return;
17100        };
17101        workspace.activate_item(&item, true, true, window, cx);
17102    }
17103
17104    pub fn toggle_fold(
17105        &mut self,
17106        _: &actions::ToggleFold,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) {
17110        if self.is_singleton(cx) {
17111            let selection = self.selections.newest::<Point>(cx);
17112
17113            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17114            let range = if selection.is_empty() {
17115                let point = selection.head().to_display_point(&display_map);
17116                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17117                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17118                    .to_point(&display_map);
17119                start..end
17120            } else {
17121                selection.range()
17122            };
17123            if display_map.folds_in_range(range).next().is_some() {
17124                self.unfold_lines(&Default::default(), window, cx)
17125            } else {
17126                self.fold(&Default::default(), window, cx)
17127            }
17128        } else {
17129            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17130            let buffer_ids: HashSet<_> = self
17131                .selections
17132                .disjoint_anchor_ranges()
17133                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17134                .collect();
17135
17136            let should_unfold = buffer_ids
17137                .iter()
17138                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17139
17140            for buffer_id in buffer_ids {
17141                if should_unfold {
17142                    self.unfold_buffer(buffer_id, cx);
17143                } else {
17144                    self.fold_buffer(buffer_id, cx);
17145                }
17146            }
17147        }
17148    }
17149
17150    pub fn toggle_fold_recursive(
17151        &mut self,
17152        _: &actions::ToggleFoldRecursive,
17153        window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        let selection = self.selections.newest::<Point>(cx);
17157
17158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17159        let range = if selection.is_empty() {
17160            let point = selection.head().to_display_point(&display_map);
17161            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17162            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17163                .to_point(&display_map);
17164            start..end
17165        } else {
17166            selection.range()
17167        };
17168        if display_map.folds_in_range(range).next().is_some() {
17169            self.unfold_recursive(&Default::default(), window, cx)
17170        } else {
17171            self.fold_recursive(&Default::default(), window, cx)
17172        }
17173    }
17174
17175    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17176        if self.is_singleton(cx) {
17177            let mut to_fold = Vec::new();
17178            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17179            let selections = self.selections.all_adjusted(cx);
17180
17181            for selection in selections {
17182                let range = selection.range().sorted();
17183                let buffer_start_row = range.start.row;
17184
17185                if range.start.row != range.end.row {
17186                    let mut found = false;
17187                    let mut row = range.start.row;
17188                    while row <= range.end.row {
17189                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17190                        {
17191                            found = true;
17192                            row = crease.range().end.row + 1;
17193                            to_fold.push(crease);
17194                        } else {
17195                            row += 1
17196                        }
17197                    }
17198                    if found {
17199                        continue;
17200                    }
17201                }
17202
17203                for row in (0..=range.start.row).rev() {
17204                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17205                        if crease.range().end.row >= buffer_start_row {
17206                            to_fold.push(crease);
17207                            if row <= range.start.row {
17208                                break;
17209                            }
17210                        }
17211                    }
17212                }
17213            }
17214
17215            self.fold_creases(to_fold, true, window, cx);
17216        } else {
17217            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17218            let buffer_ids = self
17219                .selections
17220                .disjoint_anchor_ranges()
17221                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17222                .collect::<HashSet<_>>();
17223            for buffer_id in buffer_ids {
17224                self.fold_buffer(buffer_id, cx);
17225            }
17226        }
17227    }
17228
17229    pub fn toggle_fold_all(
17230        &mut self,
17231        _: &actions::ToggleFoldAll,
17232        window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        if self.buffer.read(cx).is_singleton() {
17236            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17237            let has_folds = display_map
17238                .folds_in_range(0..display_map.buffer_snapshot.len())
17239                .next()
17240                .is_some();
17241
17242            if has_folds {
17243                self.unfold_all(&actions::UnfoldAll, window, cx);
17244            } else {
17245                self.fold_all(&actions::FoldAll, window, cx);
17246            }
17247        } else {
17248            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17249            let should_unfold = buffer_ids
17250                .iter()
17251                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17252
17253            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17254                editor
17255                    .update_in(cx, |editor, _, cx| {
17256                        for buffer_id in buffer_ids {
17257                            if should_unfold {
17258                                editor.unfold_buffer(buffer_id, cx);
17259                            } else {
17260                                editor.fold_buffer(buffer_id, cx);
17261                            }
17262                        }
17263                    })
17264                    .ok();
17265            });
17266        }
17267    }
17268
17269    fn fold_at_level(
17270        &mut self,
17271        fold_at: &FoldAtLevel,
17272        window: &mut Window,
17273        cx: &mut Context<Self>,
17274    ) {
17275        if !self.buffer.read(cx).is_singleton() {
17276            return;
17277        }
17278
17279        let fold_at_level = fold_at.0;
17280        let snapshot = self.buffer.read(cx).snapshot(cx);
17281        let mut to_fold = Vec::new();
17282        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17283
17284        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17285            while start_row < end_row {
17286                match self
17287                    .snapshot(window, cx)
17288                    .crease_for_buffer_row(MultiBufferRow(start_row))
17289                {
17290                    Some(crease) => {
17291                        let nested_start_row = crease.range().start.row + 1;
17292                        let nested_end_row = crease.range().end.row;
17293
17294                        if current_level < fold_at_level {
17295                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17296                        } else if current_level == fold_at_level {
17297                            to_fold.push(crease);
17298                        }
17299
17300                        start_row = nested_end_row + 1;
17301                    }
17302                    None => start_row += 1,
17303                }
17304            }
17305        }
17306
17307        self.fold_creases(to_fold, true, window, cx);
17308    }
17309
17310    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17311        if self.buffer.read(cx).is_singleton() {
17312            let mut fold_ranges = Vec::new();
17313            let snapshot = self.buffer.read(cx).snapshot(cx);
17314
17315            for row in 0..snapshot.max_row().0 {
17316                if let Some(foldable_range) = self
17317                    .snapshot(window, cx)
17318                    .crease_for_buffer_row(MultiBufferRow(row))
17319                {
17320                    fold_ranges.push(foldable_range);
17321                }
17322            }
17323
17324            self.fold_creases(fold_ranges, true, window, cx);
17325        } else {
17326            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17327                editor
17328                    .update_in(cx, |editor, _, cx| {
17329                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17330                            editor.fold_buffer(buffer_id, cx);
17331                        }
17332                    })
17333                    .ok();
17334            });
17335        }
17336    }
17337
17338    pub fn fold_function_bodies(
17339        &mut self,
17340        _: &actions::FoldFunctionBodies,
17341        window: &mut Window,
17342        cx: &mut Context<Self>,
17343    ) {
17344        let snapshot = self.buffer.read(cx).snapshot(cx);
17345
17346        let ranges = snapshot
17347            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17348            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17349            .collect::<Vec<_>>();
17350
17351        let creases = ranges
17352            .into_iter()
17353            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17354            .collect();
17355
17356        self.fold_creases(creases, true, window, cx);
17357    }
17358
17359    pub fn fold_recursive(
17360        &mut self,
17361        _: &actions::FoldRecursive,
17362        window: &mut Window,
17363        cx: &mut Context<Self>,
17364    ) {
17365        let mut to_fold = Vec::new();
17366        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17367        let selections = self.selections.all_adjusted(cx);
17368
17369        for selection in selections {
17370            let range = selection.range().sorted();
17371            let buffer_start_row = range.start.row;
17372
17373            if range.start.row != range.end.row {
17374                let mut found = false;
17375                for row in range.start.row..=range.end.row {
17376                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17377                        found = true;
17378                        to_fold.push(crease);
17379                    }
17380                }
17381                if found {
17382                    continue;
17383                }
17384            }
17385
17386            for row in (0..=range.start.row).rev() {
17387                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17388                    if crease.range().end.row >= buffer_start_row {
17389                        to_fold.push(crease);
17390                    } else {
17391                        break;
17392                    }
17393                }
17394            }
17395        }
17396
17397        self.fold_creases(to_fold, true, window, cx);
17398    }
17399
17400    pub fn fold_at(
17401        &mut self,
17402        buffer_row: MultiBufferRow,
17403        window: &mut Window,
17404        cx: &mut Context<Self>,
17405    ) {
17406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17407
17408        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17409            let autoscroll = self
17410                .selections
17411                .all::<Point>(cx)
17412                .iter()
17413                .any(|selection| crease.range().overlaps(&selection.range()));
17414
17415            self.fold_creases(vec![crease], autoscroll, window, cx);
17416        }
17417    }
17418
17419    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17420        if self.is_singleton(cx) {
17421            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17422            let buffer = &display_map.buffer_snapshot;
17423            let selections = self.selections.all::<Point>(cx);
17424            let ranges = selections
17425                .iter()
17426                .map(|s| {
17427                    let range = s.display_range(&display_map).sorted();
17428                    let mut start = range.start.to_point(&display_map);
17429                    let mut end = range.end.to_point(&display_map);
17430                    start.column = 0;
17431                    end.column = buffer.line_len(MultiBufferRow(end.row));
17432                    start..end
17433                })
17434                .collect::<Vec<_>>();
17435
17436            self.unfold_ranges(&ranges, true, true, cx);
17437        } else {
17438            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17439            let buffer_ids = self
17440                .selections
17441                .disjoint_anchor_ranges()
17442                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17443                .collect::<HashSet<_>>();
17444            for buffer_id in buffer_ids {
17445                self.unfold_buffer(buffer_id, cx);
17446            }
17447        }
17448    }
17449
17450    pub fn unfold_recursive(
17451        &mut self,
17452        _: &UnfoldRecursive,
17453        _window: &mut Window,
17454        cx: &mut Context<Self>,
17455    ) {
17456        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17457        let selections = self.selections.all::<Point>(cx);
17458        let ranges = selections
17459            .iter()
17460            .map(|s| {
17461                let mut range = s.display_range(&display_map).sorted();
17462                *range.start.column_mut() = 0;
17463                *range.end.column_mut() = display_map.line_len(range.end.row());
17464                let start = range.start.to_point(&display_map);
17465                let end = range.end.to_point(&display_map);
17466                start..end
17467            })
17468            .collect::<Vec<_>>();
17469
17470        self.unfold_ranges(&ranges, true, true, cx);
17471    }
17472
17473    pub fn unfold_at(
17474        &mut self,
17475        buffer_row: MultiBufferRow,
17476        _window: &mut Window,
17477        cx: &mut Context<Self>,
17478    ) {
17479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17480
17481        let intersection_range = Point::new(buffer_row.0, 0)
17482            ..Point::new(
17483                buffer_row.0,
17484                display_map.buffer_snapshot.line_len(buffer_row),
17485            );
17486
17487        let autoscroll = self
17488            .selections
17489            .all::<Point>(cx)
17490            .iter()
17491            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17492
17493        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17494    }
17495
17496    pub fn unfold_all(
17497        &mut self,
17498        _: &actions::UnfoldAll,
17499        _window: &mut Window,
17500        cx: &mut Context<Self>,
17501    ) {
17502        if self.buffer.read(cx).is_singleton() {
17503            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17504            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17505        } else {
17506            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17507                editor
17508                    .update(cx, |editor, cx| {
17509                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17510                            editor.unfold_buffer(buffer_id, cx);
17511                        }
17512                    })
17513                    .ok();
17514            });
17515        }
17516    }
17517
17518    pub fn fold_selected_ranges(
17519        &mut self,
17520        _: &FoldSelectedRanges,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) {
17524        let selections = self.selections.all_adjusted(cx);
17525        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17526        let ranges = selections
17527            .into_iter()
17528            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17529            .collect::<Vec<_>>();
17530        self.fold_creases(ranges, true, window, cx);
17531    }
17532
17533    pub fn fold_ranges<T: ToOffset + Clone>(
17534        &mut self,
17535        ranges: Vec<Range<T>>,
17536        auto_scroll: bool,
17537        window: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) {
17540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17541        let ranges = ranges
17542            .into_iter()
17543            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17544            .collect::<Vec<_>>();
17545        self.fold_creases(ranges, auto_scroll, window, cx);
17546    }
17547
17548    pub fn fold_creases<T: ToOffset + Clone>(
17549        &mut self,
17550        creases: Vec<Crease<T>>,
17551        auto_scroll: bool,
17552        _window: &mut Window,
17553        cx: &mut Context<Self>,
17554    ) {
17555        if creases.is_empty() {
17556            return;
17557        }
17558
17559        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17560
17561        if auto_scroll {
17562            self.request_autoscroll(Autoscroll::fit(), cx);
17563        }
17564
17565        cx.notify();
17566
17567        self.scrollbar_marker_state.dirty = true;
17568        self.folds_did_change(cx);
17569    }
17570
17571    /// Removes any folds whose ranges intersect any of the given ranges.
17572    pub fn unfold_ranges<T: ToOffset + Clone>(
17573        &mut self,
17574        ranges: &[Range<T>],
17575        inclusive: bool,
17576        auto_scroll: bool,
17577        cx: &mut Context<Self>,
17578    ) {
17579        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17580            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17581        });
17582        self.folds_did_change(cx);
17583    }
17584
17585    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17586        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17587            return;
17588        }
17589        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17590        self.display_map.update(cx, |display_map, cx| {
17591            display_map.fold_buffers([buffer_id], cx)
17592        });
17593        cx.emit(EditorEvent::BufferFoldToggled {
17594            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17595            folded: true,
17596        });
17597        cx.notify();
17598    }
17599
17600    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17601        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17602            return;
17603        }
17604        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17605        self.display_map.update(cx, |display_map, cx| {
17606            display_map.unfold_buffers([buffer_id], cx);
17607        });
17608        cx.emit(EditorEvent::BufferFoldToggled {
17609            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17610            folded: false,
17611        });
17612        cx.notify();
17613    }
17614
17615    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17616        self.display_map.read(cx).is_buffer_folded(buffer)
17617    }
17618
17619    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17620        self.display_map.read(cx).folded_buffers()
17621    }
17622
17623    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17624        self.display_map.update(cx, |display_map, cx| {
17625            display_map.disable_header_for_buffer(buffer_id, cx);
17626        });
17627        cx.notify();
17628    }
17629
17630    /// Removes any folds with the given ranges.
17631    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17632        &mut self,
17633        ranges: &[Range<T>],
17634        type_id: TypeId,
17635        auto_scroll: bool,
17636        cx: &mut Context<Self>,
17637    ) {
17638        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17639            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17640        });
17641        self.folds_did_change(cx);
17642    }
17643
17644    fn remove_folds_with<T: ToOffset + Clone>(
17645        &mut self,
17646        ranges: &[Range<T>],
17647        auto_scroll: bool,
17648        cx: &mut Context<Self>,
17649        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17650    ) {
17651        if ranges.is_empty() {
17652            return;
17653        }
17654
17655        let mut buffers_affected = HashSet::default();
17656        let multi_buffer = self.buffer().read(cx);
17657        for range in ranges {
17658            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17659                buffers_affected.insert(buffer.read(cx).remote_id());
17660            };
17661        }
17662
17663        self.display_map.update(cx, update);
17664
17665        if auto_scroll {
17666            self.request_autoscroll(Autoscroll::fit(), cx);
17667        }
17668
17669        cx.notify();
17670        self.scrollbar_marker_state.dirty = true;
17671        self.active_indent_guides_state.dirty = true;
17672    }
17673
17674    pub fn update_renderer_widths(
17675        &mut self,
17676        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17677        cx: &mut Context<Self>,
17678    ) -> bool {
17679        self.display_map
17680            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17681    }
17682
17683    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17684        self.display_map.read(cx).fold_placeholder.clone()
17685    }
17686
17687    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17688        self.buffer.update(cx, |buffer, cx| {
17689            buffer.set_all_diff_hunks_expanded(cx);
17690        });
17691    }
17692
17693    pub fn expand_all_diff_hunks(
17694        &mut self,
17695        _: &ExpandAllDiffHunks,
17696        _window: &mut Window,
17697        cx: &mut Context<Self>,
17698    ) {
17699        self.buffer.update(cx, |buffer, cx| {
17700            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17701        });
17702    }
17703
17704    pub fn toggle_selected_diff_hunks(
17705        &mut self,
17706        _: &ToggleSelectedDiffHunks,
17707        _window: &mut Window,
17708        cx: &mut Context<Self>,
17709    ) {
17710        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17711        self.toggle_diff_hunks_in_ranges(ranges, cx);
17712    }
17713
17714    pub fn diff_hunks_in_ranges<'a>(
17715        &'a self,
17716        ranges: &'a [Range<Anchor>],
17717        buffer: &'a MultiBufferSnapshot,
17718    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17719        ranges.iter().flat_map(move |range| {
17720            let end_excerpt_id = range.end.excerpt_id;
17721            let range = range.to_point(buffer);
17722            let mut peek_end = range.end;
17723            if range.end.row < buffer.max_row().0 {
17724                peek_end = Point::new(range.end.row + 1, 0);
17725            }
17726            buffer
17727                .diff_hunks_in_range(range.start..peek_end)
17728                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17729        })
17730    }
17731
17732    pub fn has_stageable_diff_hunks_in_ranges(
17733        &self,
17734        ranges: &[Range<Anchor>],
17735        snapshot: &MultiBufferSnapshot,
17736    ) -> bool {
17737        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17738        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17739    }
17740
17741    pub fn toggle_staged_selected_diff_hunks(
17742        &mut self,
17743        _: &::git::ToggleStaged,
17744        _: &mut Window,
17745        cx: &mut Context<Self>,
17746    ) {
17747        let snapshot = self.buffer.read(cx).snapshot(cx);
17748        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17749        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17750        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17751    }
17752
17753    pub fn set_render_diff_hunk_controls(
17754        &mut self,
17755        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17756        cx: &mut Context<Self>,
17757    ) {
17758        self.render_diff_hunk_controls = render_diff_hunk_controls;
17759        cx.notify();
17760    }
17761
17762    pub fn stage_and_next(
17763        &mut self,
17764        _: &::git::StageAndNext,
17765        window: &mut Window,
17766        cx: &mut Context<Self>,
17767    ) {
17768        self.do_stage_or_unstage_and_next(true, window, cx);
17769    }
17770
17771    pub fn unstage_and_next(
17772        &mut self,
17773        _: &::git::UnstageAndNext,
17774        window: &mut Window,
17775        cx: &mut Context<Self>,
17776    ) {
17777        self.do_stage_or_unstage_and_next(false, window, cx);
17778    }
17779
17780    pub fn stage_or_unstage_diff_hunks(
17781        &mut self,
17782        stage: bool,
17783        ranges: Vec<Range<Anchor>>,
17784        cx: &mut Context<Self>,
17785    ) {
17786        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17787        cx.spawn(async move |this, cx| {
17788            task.await?;
17789            this.update(cx, |this, cx| {
17790                let snapshot = this.buffer.read(cx).snapshot(cx);
17791                let chunk_by = this
17792                    .diff_hunks_in_ranges(&ranges, &snapshot)
17793                    .chunk_by(|hunk| hunk.buffer_id);
17794                for (buffer_id, hunks) in &chunk_by {
17795                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17796                }
17797            })
17798        })
17799        .detach_and_log_err(cx);
17800    }
17801
17802    fn save_buffers_for_ranges_if_needed(
17803        &mut self,
17804        ranges: &[Range<Anchor>],
17805        cx: &mut Context<Editor>,
17806    ) -> Task<Result<()>> {
17807        let multibuffer = self.buffer.read(cx);
17808        let snapshot = multibuffer.read(cx);
17809        let buffer_ids: HashSet<_> = ranges
17810            .iter()
17811            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17812            .collect();
17813        drop(snapshot);
17814
17815        let mut buffers = HashSet::default();
17816        for buffer_id in buffer_ids {
17817            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17818                let buffer = buffer_entity.read(cx);
17819                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17820                {
17821                    buffers.insert(buffer_entity);
17822                }
17823            }
17824        }
17825
17826        if let Some(project) = &self.project {
17827            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17828        } else {
17829            Task::ready(Ok(()))
17830        }
17831    }
17832
17833    fn do_stage_or_unstage_and_next(
17834        &mut self,
17835        stage: bool,
17836        window: &mut Window,
17837        cx: &mut Context<Self>,
17838    ) {
17839        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17840
17841        if ranges.iter().any(|range| range.start != range.end) {
17842            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17843            return;
17844        }
17845
17846        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17847        let snapshot = self.snapshot(window, cx);
17848        let position = self.selections.newest::<Point>(cx).head();
17849        let mut row = snapshot
17850            .buffer_snapshot
17851            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17852            .find(|hunk| hunk.row_range.start.0 > position.row)
17853            .map(|hunk| hunk.row_range.start);
17854
17855        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17856        // Outside of the project diff editor, wrap around to the beginning.
17857        if !all_diff_hunks_expanded {
17858            row = row.or_else(|| {
17859                snapshot
17860                    .buffer_snapshot
17861                    .diff_hunks_in_range(Point::zero()..position)
17862                    .find(|hunk| hunk.row_range.end.0 < position.row)
17863                    .map(|hunk| hunk.row_range.start)
17864            });
17865        }
17866
17867        if let Some(row) = row {
17868            let destination = Point::new(row.0, 0);
17869            let autoscroll = Autoscroll::center();
17870
17871            self.unfold_ranges(&[destination..destination], false, false, cx);
17872            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17873                s.select_ranges([destination..destination]);
17874            });
17875        }
17876    }
17877
17878    fn do_stage_or_unstage(
17879        &self,
17880        stage: bool,
17881        buffer_id: BufferId,
17882        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17883        cx: &mut App,
17884    ) -> Option<()> {
17885        let project = self.project.as_ref()?;
17886        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17887        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17888        let buffer_snapshot = buffer.read(cx).snapshot();
17889        let file_exists = buffer_snapshot
17890            .file()
17891            .is_some_and(|file| file.disk_state().exists());
17892        diff.update(cx, |diff, cx| {
17893            diff.stage_or_unstage_hunks(
17894                stage,
17895                &hunks
17896                    .map(|hunk| buffer_diff::DiffHunk {
17897                        buffer_range: hunk.buffer_range,
17898                        diff_base_byte_range: hunk.diff_base_byte_range,
17899                        secondary_status: hunk.secondary_status,
17900                        range: Point::zero()..Point::zero(), // unused
17901                    })
17902                    .collect::<Vec<_>>(),
17903                &buffer_snapshot,
17904                file_exists,
17905                cx,
17906            )
17907        });
17908        None
17909    }
17910
17911    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17912        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17913        self.buffer
17914            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17915    }
17916
17917    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17918        self.buffer.update(cx, |buffer, cx| {
17919            let ranges = vec![Anchor::min()..Anchor::max()];
17920            if !buffer.all_diff_hunks_expanded()
17921                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17922            {
17923                buffer.collapse_diff_hunks(ranges, cx);
17924                true
17925            } else {
17926                false
17927            }
17928        })
17929    }
17930
17931    fn toggle_diff_hunks_in_ranges(
17932        &mut self,
17933        ranges: Vec<Range<Anchor>>,
17934        cx: &mut Context<Editor>,
17935    ) {
17936        self.buffer.update(cx, |buffer, cx| {
17937            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17938            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17939        })
17940    }
17941
17942    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17943        self.buffer.update(cx, |buffer, cx| {
17944            let snapshot = buffer.snapshot(cx);
17945            let excerpt_id = range.end.excerpt_id;
17946            let point_range = range.to_point(&snapshot);
17947            let expand = !buffer.single_hunk_is_expanded(range, cx);
17948            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17949        })
17950    }
17951
17952    pub(crate) fn apply_all_diff_hunks(
17953        &mut self,
17954        _: &ApplyAllDiffHunks,
17955        window: &mut Window,
17956        cx: &mut Context<Self>,
17957    ) {
17958        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17959
17960        let buffers = self.buffer.read(cx).all_buffers();
17961        for branch_buffer in buffers {
17962            branch_buffer.update(cx, |branch_buffer, cx| {
17963                branch_buffer.merge_into_base(Vec::new(), cx);
17964            });
17965        }
17966
17967        if let Some(project) = self.project.clone() {
17968            self.save(
17969                SaveOptions {
17970                    format: true,
17971                    autosave: false,
17972                },
17973                project,
17974                window,
17975                cx,
17976            )
17977            .detach_and_log_err(cx);
17978        }
17979    }
17980
17981    pub(crate) fn apply_selected_diff_hunks(
17982        &mut self,
17983        _: &ApplyDiffHunk,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17988        let snapshot = self.snapshot(window, cx);
17989        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17990        let mut ranges_by_buffer = HashMap::default();
17991        self.transact(window, cx, |editor, _window, cx| {
17992            for hunk in hunks {
17993                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17994                    ranges_by_buffer
17995                        .entry(buffer.clone())
17996                        .or_insert_with(Vec::new)
17997                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17998                }
17999            }
18000
18001            for (buffer, ranges) in ranges_by_buffer {
18002                buffer.update(cx, |buffer, cx| {
18003                    buffer.merge_into_base(ranges, cx);
18004                });
18005            }
18006        });
18007
18008        if let Some(project) = self.project.clone() {
18009            self.save(
18010                SaveOptions {
18011                    format: true,
18012                    autosave: false,
18013                },
18014                project,
18015                window,
18016                cx,
18017            )
18018            .detach_and_log_err(cx);
18019        }
18020    }
18021
18022    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18023        if hovered != self.gutter_hovered {
18024            self.gutter_hovered = hovered;
18025            cx.notify();
18026        }
18027    }
18028
18029    pub fn insert_blocks(
18030        &mut self,
18031        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18032        autoscroll: Option<Autoscroll>,
18033        cx: &mut Context<Self>,
18034    ) -> Vec<CustomBlockId> {
18035        let blocks = self
18036            .display_map
18037            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18038        if let Some(autoscroll) = autoscroll {
18039            self.request_autoscroll(autoscroll, cx);
18040        }
18041        cx.notify();
18042        blocks
18043    }
18044
18045    pub fn resize_blocks(
18046        &mut self,
18047        heights: HashMap<CustomBlockId, u32>,
18048        autoscroll: Option<Autoscroll>,
18049        cx: &mut Context<Self>,
18050    ) {
18051        self.display_map
18052            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18053        if let Some(autoscroll) = autoscroll {
18054            self.request_autoscroll(autoscroll, cx);
18055        }
18056        cx.notify();
18057    }
18058
18059    pub fn replace_blocks(
18060        &mut self,
18061        renderers: HashMap<CustomBlockId, RenderBlock>,
18062        autoscroll: Option<Autoscroll>,
18063        cx: &mut Context<Self>,
18064    ) {
18065        self.display_map
18066            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18067        if let Some(autoscroll) = autoscroll {
18068            self.request_autoscroll(autoscroll, cx);
18069        }
18070        cx.notify();
18071    }
18072
18073    pub fn remove_blocks(
18074        &mut self,
18075        block_ids: HashSet<CustomBlockId>,
18076        autoscroll: Option<Autoscroll>,
18077        cx: &mut Context<Self>,
18078    ) {
18079        self.display_map.update(cx, |display_map, cx| {
18080            display_map.remove_blocks(block_ids, cx)
18081        });
18082        if let Some(autoscroll) = autoscroll {
18083            self.request_autoscroll(autoscroll, cx);
18084        }
18085        cx.notify();
18086    }
18087
18088    pub fn row_for_block(
18089        &self,
18090        block_id: CustomBlockId,
18091        cx: &mut Context<Self>,
18092    ) -> Option<DisplayRow> {
18093        self.display_map
18094            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18095    }
18096
18097    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18098        self.focused_block = Some(focused_block);
18099    }
18100
18101    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18102        self.focused_block.take()
18103    }
18104
18105    pub fn insert_creases(
18106        &mut self,
18107        creases: impl IntoIterator<Item = Crease<Anchor>>,
18108        cx: &mut Context<Self>,
18109    ) -> Vec<CreaseId> {
18110        self.display_map
18111            .update(cx, |map, cx| map.insert_creases(creases, cx))
18112    }
18113
18114    pub fn remove_creases(
18115        &mut self,
18116        ids: impl IntoIterator<Item = CreaseId>,
18117        cx: &mut Context<Self>,
18118    ) -> Vec<(CreaseId, Range<Anchor>)> {
18119        self.display_map
18120            .update(cx, |map, cx| map.remove_creases(ids, cx))
18121    }
18122
18123    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18124        self.display_map
18125            .update(cx, |map, cx| map.snapshot(cx))
18126            .longest_row()
18127    }
18128
18129    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18130        self.display_map
18131            .update(cx, |map, cx| map.snapshot(cx))
18132            .max_point()
18133    }
18134
18135    pub fn text(&self, cx: &App) -> String {
18136        self.buffer.read(cx).read(cx).text()
18137    }
18138
18139    pub fn is_empty(&self, cx: &App) -> bool {
18140        self.buffer.read(cx).read(cx).is_empty()
18141    }
18142
18143    pub fn text_option(&self, cx: &App) -> Option<String> {
18144        let text = self.text(cx);
18145        let text = text.trim();
18146
18147        if text.is_empty() {
18148            return None;
18149        }
18150
18151        Some(text.to_string())
18152    }
18153
18154    pub fn set_text(
18155        &mut self,
18156        text: impl Into<Arc<str>>,
18157        window: &mut Window,
18158        cx: &mut Context<Self>,
18159    ) {
18160        self.transact(window, cx, |this, _, cx| {
18161            this.buffer
18162                .read(cx)
18163                .as_singleton()
18164                .expect("you can only call set_text on editors for singleton buffers")
18165                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18166        });
18167    }
18168
18169    pub fn display_text(&self, cx: &mut App) -> String {
18170        self.display_map
18171            .update(cx, |map, cx| map.snapshot(cx))
18172            .text()
18173    }
18174
18175    fn create_minimap(
18176        &self,
18177        minimap_settings: MinimapSettings,
18178        window: &mut Window,
18179        cx: &mut Context<Self>,
18180    ) -> Option<Entity<Self>> {
18181        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18182            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18183    }
18184
18185    fn initialize_new_minimap(
18186        &self,
18187        minimap_settings: MinimapSettings,
18188        window: &mut Window,
18189        cx: &mut Context<Self>,
18190    ) -> Entity<Self> {
18191        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18192
18193        let mut minimap = Editor::new_internal(
18194            EditorMode::Minimap {
18195                parent: cx.weak_entity(),
18196            },
18197            self.buffer.clone(),
18198            None,
18199            Some(self.display_map.clone()),
18200            window,
18201            cx,
18202        );
18203        minimap.scroll_manager.clone_state(&self.scroll_manager);
18204        minimap.set_text_style_refinement(TextStyleRefinement {
18205            font_size: Some(MINIMAP_FONT_SIZE),
18206            font_weight: Some(MINIMAP_FONT_WEIGHT),
18207            ..Default::default()
18208        });
18209        minimap.update_minimap_configuration(minimap_settings, cx);
18210        cx.new(|_| minimap)
18211    }
18212
18213    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18214        let current_line_highlight = minimap_settings
18215            .current_line_highlight
18216            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18217        self.set_current_line_highlight(Some(current_line_highlight));
18218    }
18219
18220    pub fn minimap(&self) -> Option<&Entity<Self>> {
18221        self.minimap
18222            .as_ref()
18223            .filter(|_| self.minimap_visibility.visible())
18224    }
18225
18226    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18227        let mut wrap_guides = smallvec![];
18228
18229        if self.show_wrap_guides == Some(false) {
18230            return wrap_guides;
18231        }
18232
18233        let settings = self.buffer.read(cx).language_settings(cx);
18234        if settings.show_wrap_guides {
18235            match self.soft_wrap_mode(cx) {
18236                SoftWrap::Column(soft_wrap) => {
18237                    wrap_guides.push((soft_wrap as usize, true));
18238                }
18239                SoftWrap::Bounded(soft_wrap) => {
18240                    wrap_guides.push((soft_wrap as usize, true));
18241                }
18242                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18243            }
18244            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18245        }
18246
18247        wrap_guides
18248    }
18249
18250    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18251        let settings = self.buffer.read(cx).language_settings(cx);
18252        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18253        match mode {
18254            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18255                SoftWrap::None
18256            }
18257            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18258            language_settings::SoftWrap::PreferredLineLength => {
18259                SoftWrap::Column(settings.preferred_line_length)
18260            }
18261            language_settings::SoftWrap::Bounded => {
18262                SoftWrap::Bounded(settings.preferred_line_length)
18263            }
18264        }
18265    }
18266
18267    pub fn set_soft_wrap_mode(
18268        &mut self,
18269        mode: language_settings::SoftWrap,
18270
18271        cx: &mut Context<Self>,
18272    ) {
18273        self.soft_wrap_mode_override = Some(mode);
18274        cx.notify();
18275    }
18276
18277    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18278        self.hard_wrap = hard_wrap;
18279        cx.notify();
18280    }
18281
18282    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18283        self.text_style_refinement = Some(style);
18284    }
18285
18286    /// called by the Element so we know what style we were most recently rendered with.
18287    pub(crate) fn set_style(
18288        &mut self,
18289        style: EditorStyle,
18290        window: &mut Window,
18291        cx: &mut Context<Self>,
18292    ) {
18293        // We intentionally do not inform the display map about the minimap style
18294        // so that wrapping is not recalculated and stays consistent for the editor
18295        // and its linked minimap.
18296        if !self.mode.is_minimap() {
18297            let rem_size = window.rem_size();
18298            self.display_map.update(cx, |map, cx| {
18299                map.set_font(
18300                    style.text.font(),
18301                    style.text.font_size.to_pixels(rem_size),
18302                    cx,
18303                )
18304            });
18305        }
18306        self.style = Some(style);
18307    }
18308
18309    pub fn style(&self) -> Option<&EditorStyle> {
18310        self.style.as_ref()
18311    }
18312
18313    // Called by the element. This method is not designed to be called outside of the editor
18314    // element's layout code because it does not notify when rewrapping is computed synchronously.
18315    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18316        self.display_map
18317            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18318    }
18319
18320    pub fn set_soft_wrap(&mut self) {
18321        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18322    }
18323
18324    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18325        if self.soft_wrap_mode_override.is_some() {
18326            self.soft_wrap_mode_override.take();
18327        } else {
18328            let soft_wrap = match self.soft_wrap_mode(cx) {
18329                SoftWrap::GitDiff => return,
18330                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18331                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18332                    language_settings::SoftWrap::None
18333                }
18334            };
18335            self.soft_wrap_mode_override = Some(soft_wrap);
18336        }
18337        cx.notify();
18338    }
18339
18340    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18341        let Some(workspace) = self.workspace() else {
18342            return;
18343        };
18344        let fs = workspace.read(cx).app_state().fs.clone();
18345        let current_show = TabBarSettings::get_global(cx).show;
18346        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18347            setting.show = Some(!current_show);
18348        });
18349    }
18350
18351    pub fn toggle_indent_guides(
18352        &mut self,
18353        _: &ToggleIndentGuides,
18354        _: &mut Window,
18355        cx: &mut Context<Self>,
18356    ) {
18357        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18358            self.buffer
18359                .read(cx)
18360                .language_settings(cx)
18361                .indent_guides
18362                .enabled
18363        });
18364        self.show_indent_guides = Some(!currently_enabled);
18365        cx.notify();
18366    }
18367
18368    fn should_show_indent_guides(&self) -> Option<bool> {
18369        self.show_indent_guides
18370    }
18371
18372    pub fn toggle_line_numbers(
18373        &mut self,
18374        _: &ToggleLineNumbers,
18375        _: &mut Window,
18376        cx: &mut Context<Self>,
18377    ) {
18378        let mut editor_settings = EditorSettings::get_global(cx).clone();
18379        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18380        EditorSettings::override_global(editor_settings, cx);
18381    }
18382
18383    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18384        if let Some(show_line_numbers) = self.show_line_numbers {
18385            return show_line_numbers;
18386        }
18387        EditorSettings::get_global(cx).gutter.line_numbers
18388    }
18389
18390    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18391        self.use_relative_line_numbers
18392            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18393    }
18394
18395    pub fn toggle_relative_line_numbers(
18396        &mut self,
18397        _: &ToggleRelativeLineNumbers,
18398        _: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        let is_relative = self.should_use_relative_line_numbers(cx);
18402        self.set_relative_line_number(Some(!is_relative), cx)
18403    }
18404
18405    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18406        self.use_relative_line_numbers = is_relative;
18407        cx.notify();
18408    }
18409
18410    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18411        self.show_gutter = show_gutter;
18412        cx.notify();
18413    }
18414
18415    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18416        self.show_scrollbars = ScrollbarAxes {
18417            horizontal: show,
18418            vertical: show,
18419        };
18420        cx.notify();
18421    }
18422
18423    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18424        self.show_scrollbars.vertical = show;
18425        cx.notify();
18426    }
18427
18428    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18429        self.show_scrollbars.horizontal = show;
18430        cx.notify();
18431    }
18432
18433    pub fn set_minimap_visibility(
18434        &mut self,
18435        minimap_visibility: MinimapVisibility,
18436        window: &mut Window,
18437        cx: &mut Context<Self>,
18438    ) {
18439        if self.minimap_visibility != minimap_visibility {
18440            if minimap_visibility.visible() && self.minimap.is_none() {
18441                let minimap_settings = EditorSettings::get_global(cx).minimap;
18442                self.minimap =
18443                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18444            }
18445            self.minimap_visibility = minimap_visibility;
18446            cx.notify();
18447        }
18448    }
18449
18450    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18451        self.set_show_scrollbars(false, cx);
18452        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18453    }
18454
18455    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18456        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18457    }
18458
18459    /// Normally the text in full mode and auto height editors is padded on the
18460    /// left side by roughly half a character width for improved hit testing.
18461    ///
18462    /// Use this method to disable this for cases where this is not wanted (e.g.
18463    /// if you want to align the editor text with some other text above or below)
18464    /// or if you want to add this padding to single-line editors.
18465    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18466        self.offset_content = offset_content;
18467        cx.notify();
18468    }
18469
18470    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18471        self.show_line_numbers = Some(show_line_numbers);
18472        cx.notify();
18473    }
18474
18475    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18476        self.disable_expand_excerpt_buttons = true;
18477        cx.notify();
18478    }
18479
18480    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18481        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18482        cx.notify();
18483    }
18484
18485    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18486        self.show_code_actions = Some(show_code_actions);
18487        cx.notify();
18488    }
18489
18490    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18491        self.show_runnables = Some(show_runnables);
18492        cx.notify();
18493    }
18494
18495    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18496        self.show_breakpoints = Some(show_breakpoints);
18497        cx.notify();
18498    }
18499
18500    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18501        if self.display_map.read(cx).masked != masked {
18502            self.display_map.update(cx, |map, _| map.masked = masked);
18503        }
18504        cx.notify()
18505    }
18506
18507    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18508        self.show_wrap_guides = Some(show_wrap_guides);
18509        cx.notify();
18510    }
18511
18512    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18513        self.show_indent_guides = Some(show_indent_guides);
18514        cx.notify();
18515    }
18516
18517    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18518        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18519            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18520                if let Some(dir) = file.abs_path(cx).parent() {
18521                    return Some(dir.to_owned());
18522                }
18523            }
18524
18525            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18526                return Some(project_path.path.to_path_buf());
18527            }
18528        }
18529
18530        None
18531    }
18532
18533    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18534        self.active_excerpt(cx)?
18535            .1
18536            .read(cx)
18537            .file()
18538            .and_then(|f| f.as_local())
18539    }
18540
18541    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18542        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18543            let buffer = buffer.read(cx);
18544            if let Some(project_path) = buffer.project_path(cx) {
18545                let project = self.project.as_ref()?.read(cx);
18546                project.absolute_path(&project_path, cx)
18547            } else {
18548                buffer
18549                    .file()
18550                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18551            }
18552        })
18553    }
18554
18555    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18556        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18557            let project_path = buffer.read(cx).project_path(cx)?;
18558            let project = self.project.as_ref()?.read(cx);
18559            let entry = project.entry_for_path(&project_path, cx)?;
18560            let path = entry.path.to_path_buf();
18561            Some(path)
18562        })
18563    }
18564
18565    pub fn reveal_in_finder(
18566        &mut self,
18567        _: &RevealInFileManager,
18568        _window: &mut Window,
18569        cx: &mut Context<Self>,
18570    ) {
18571        if let Some(target) = self.target_file(cx) {
18572            cx.reveal_path(&target.abs_path(cx));
18573        }
18574    }
18575
18576    pub fn copy_path(
18577        &mut self,
18578        _: &zed_actions::workspace::CopyPath,
18579        _window: &mut Window,
18580        cx: &mut Context<Self>,
18581    ) {
18582        if let Some(path) = self.target_file_abs_path(cx) {
18583            if let Some(path) = path.to_str() {
18584                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18585            }
18586        }
18587    }
18588
18589    pub fn copy_relative_path(
18590        &mut self,
18591        _: &zed_actions::workspace::CopyRelativePath,
18592        _window: &mut Window,
18593        cx: &mut Context<Self>,
18594    ) {
18595        if let Some(path) = self.target_file_path(cx) {
18596            if let Some(path) = path.to_str() {
18597                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18598            }
18599        }
18600    }
18601
18602    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18603        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18604            buffer.read(cx).project_path(cx)
18605        } else {
18606            None
18607        }
18608    }
18609
18610    // Returns true if the editor handled a go-to-line request
18611    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18612        maybe!({
18613            let breakpoint_store = self.breakpoint_store.as_ref()?;
18614
18615            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18616            else {
18617                self.clear_row_highlights::<ActiveDebugLine>();
18618                return None;
18619            };
18620
18621            let position = active_stack_frame.position;
18622            let buffer_id = position.buffer_id?;
18623            let snapshot = self
18624                .project
18625                .as_ref()?
18626                .read(cx)
18627                .buffer_for_id(buffer_id, cx)?
18628                .read(cx)
18629                .snapshot();
18630
18631            let mut handled = false;
18632            for (id, ExcerptRange { context, .. }) in
18633                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18634            {
18635                if context.start.cmp(&position, &snapshot).is_ge()
18636                    || context.end.cmp(&position, &snapshot).is_lt()
18637                {
18638                    continue;
18639                }
18640                let snapshot = self.buffer.read(cx).snapshot(cx);
18641                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18642
18643                handled = true;
18644                self.clear_row_highlights::<ActiveDebugLine>();
18645
18646                self.go_to_line::<ActiveDebugLine>(
18647                    multibuffer_anchor,
18648                    Some(cx.theme().colors().editor_debugger_active_line_background),
18649                    window,
18650                    cx,
18651                );
18652
18653                cx.notify();
18654            }
18655
18656            handled.then_some(())
18657        })
18658        .is_some()
18659    }
18660
18661    pub fn copy_file_name_without_extension(
18662        &mut self,
18663        _: &CopyFileNameWithoutExtension,
18664        _: &mut Window,
18665        cx: &mut Context<Self>,
18666    ) {
18667        if let Some(file) = self.target_file(cx) {
18668            if let Some(file_stem) = file.path().file_stem() {
18669                if let Some(name) = file_stem.to_str() {
18670                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18671                }
18672            }
18673        }
18674    }
18675
18676    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18677        if let Some(file) = self.target_file(cx) {
18678            if let Some(file_name) = file.path().file_name() {
18679                if let Some(name) = file_name.to_str() {
18680                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18681                }
18682            }
18683        }
18684    }
18685
18686    pub fn toggle_git_blame(
18687        &mut self,
18688        _: &::git::Blame,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18693
18694        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18695            self.start_git_blame(true, window, cx);
18696        }
18697
18698        cx.notify();
18699    }
18700
18701    pub fn toggle_git_blame_inline(
18702        &mut self,
18703        _: &ToggleGitBlameInline,
18704        window: &mut Window,
18705        cx: &mut Context<Self>,
18706    ) {
18707        self.toggle_git_blame_inline_internal(true, window, cx);
18708        cx.notify();
18709    }
18710
18711    pub fn open_git_blame_commit(
18712        &mut self,
18713        _: &OpenGitBlameCommit,
18714        window: &mut Window,
18715        cx: &mut Context<Self>,
18716    ) {
18717        self.open_git_blame_commit_internal(window, cx);
18718    }
18719
18720    fn open_git_blame_commit_internal(
18721        &mut self,
18722        window: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) -> Option<()> {
18725        let blame = self.blame.as_ref()?;
18726        let snapshot = self.snapshot(window, cx);
18727        let cursor = self.selections.newest::<Point>(cx).head();
18728        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18729        let blame_entry = blame
18730            .update(cx, |blame, cx| {
18731                blame
18732                    .blame_for_rows(
18733                        &[RowInfo {
18734                            buffer_id: Some(buffer.remote_id()),
18735                            buffer_row: Some(point.row),
18736                            ..Default::default()
18737                        }],
18738                        cx,
18739                    )
18740                    .next()
18741            })
18742            .flatten()?;
18743        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18744        let repo = blame.read(cx).repository(cx)?;
18745        let workspace = self.workspace()?.downgrade();
18746        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18747        None
18748    }
18749
18750    pub fn git_blame_inline_enabled(&self) -> bool {
18751        self.git_blame_inline_enabled
18752    }
18753
18754    pub fn toggle_selection_menu(
18755        &mut self,
18756        _: &ToggleSelectionMenu,
18757        _: &mut Window,
18758        cx: &mut Context<Self>,
18759    ) {
18760        self.show_selection_menu = self
18761            .show_selection_menu
18762            .map(|show_selections_menu| !show_selections_menu)
18763            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18764
18765        cx.notify();
18766    }
18767
18768    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18769        self.show_selection_menu
18770            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18771    }
18772
18773    fn start_git_blame(
18774        &mut self,
18775        user_triggered: bool,
18776        window: &mut Window,
18777        cx: &mut Context<Self>,
18778    ) {
18779        if let Some(project) = self.project.as_ref() {
18780            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18781                return;
18782            };
18783
18784            if buffer.read(cx).file().is_none() {
18785                return;
18786            }
18787
18788            let focused = self.focus_handle(cx).contains_focused(window, cx);
18789
18790            let project = project.clone();
18791            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18792            self.blame_subscription =
18793                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18794            self.blame = Some(blame);
18795        }
18796    }
18797
18798    fn toggle_git_blame_inline_internal(
18799        &mut self,
18800        user_triggered: bool,
18801        window: &mut Window,
18802        cx: &mut Context<Self>,
18803    ) {
18804        if self.git_blame_inline_enabled {
18805            self.git_blame_inline_enabled = false;
18806            self.show_git_blame_inline = false;
18807            self.show_git_blame_inline_delay_task.take();
18808        } else {
18809            self.git_blame_inline_enabled = true;
18810            self.start_git_blame_inline(user_triggered, window, cx);
18811        }
18812
18813        cx.notify();
18814    }
18815
18816    fn start_git_blame_inline(
18817        &mut self,
18818        user_triggered: bool,
18819        window: &mut Window,
18820        cx: &mut Context<Self>,
18821    ) {
18822        self.start_git_blame(user_triggered, window, cx);
18823
18824        if ProjectSettings::get_global(cx)
18825            .git
18826            .inline_blame_delay()
18827            .is_some()
18828        {
18829            self.start_inline_blame_timer(window, cx);
18830        } else {
18831            self.show_git_blame_inline = true
18832        }
18833    }
18834
18835    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18836        self.blame.as_ref()
18837    }
18838
18839    pub fn show_git_blame_gutter(&self) -> bool {
18840        self.show_git_blame_gutter
18841    }
18842
18843    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18844        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18845    }
18846
18847    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18848        self.show_git_blame_inline
18849            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18850            && !self.newest_selection_head_on_empty_line(cx)
18851            && self.has_blame_entries(cx)
18852    }
18853
18854    fn has_blame_entries(&self, cx: &App) -> bool {
18855        self.blame()
18856            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18857    }
18858
18859    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18860        let cursor_anchor = self.selections.newest_anchor().head();
18861
18862        let snapshot = self.buffer.read(cx).snapshot(cx);
18863        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18864
18865        snapshot.line_len(buffer_row) == 0
18866    }
18867
18868    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18869        let buffer_and_selection = maybe!({
18870            let selection = self.selections.newest::<Point>(cx);
18871            let selection_range = selection.range();
18872
18873            let multi_buffer = self.buffer().read(cx);
18874            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18875            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18876
18877            let (buffer, range, _) = if selection.reversed {
18878                buffer_ranges.first()
18879            } else {
18880                buffer_ranges.last()
18881            }?;
18882
18883            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18884                ..text::ToPoint::to_point(&range.end, &buffer).row;
18885            Some((
18886                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18887                selection,
18888            ))
18889        });
18890
18891        let Some((buffer, selection)) = buffer_and_selection else {
18892            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18893        };
18894
18895        let Some(project) = self.project.as_ref() else {
18896            return Task::ready(Err(anyhow!("editor does not have project")));
18897        };
18898
18899        project.update(cx, |project, cx| {
18900            project.get_permalink_to_line(&buffer, selection, cx)
18901        })
18902    }
18903
18904    pub fn copy_permalink_to_line(
18905        &mut self,
18906        _: &CopyPermalinkToLine,
18907        window: &mut Window,
18908        cx: &mut Context<Self>,
18909    ) {
18910        let permalink_task = self.get_permalink_to_line(cx);
18911        let workspace = self.workspace();
18912
18913        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18914            Ok(permalink) => {
18915                cx.update(|_, cx| {
18916                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18917                })
18918                .ok();
18919            }
18920            Err(err) => {
18921                let message = format!("Failed to copy permalink: {err}");
18922
18923                anyhow::Result::<()>::Err(err).log_err();
18924
18925                if let Some(workspace) = workspace {
18926                    workspace
18927                        .update_in(cx, |workspace, _, cx| {
18928                            struct CopyPermalinkToLine;
18929
18930                            workspace.show_toast(
18931                                Toast::new(
18932                                    NotificationId::unique::<CopyPermalinkToLine>(),
18933                                    message,
18934                                ),
18935                                cx,
18936                            )
18937                        })
18938                        .ok();
18939                }
18940            }
18941        })
18942        .detach();
18943    }
18944
18945    pub fn copy_file_location(
18946        &mut self,
18947        _: &CopyFileLocation,
18948        _: &mut Window,
18949        cx: &mut Context<Self>,
18950    ) {
18951        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18952        if let Some(file) = self.target_file(cx) {
18953            if let Some(path) = file.path().to_str() {
18954                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18955            }
18956        }
18957    }
18958
18959    pub fn open_permalink_to_line(
18960        &mut self,
18961        _: &OpenPermalinkToLine,
18962        window: &mut Window,
18963        cx: &mut Context<Self>,
18964    ) {
18965        let permalink_task = self.get_permalink_to_line(cx);
18966        let workspace = self.workspace();
18967
18968        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18969            Ok(permalink) => {
18970                cx.update(|_, cx| {
18971                    cx.open_url(permalink.as_ref());
18972                })
18973                .ok();
18974            }
18975            Err(err) => {
18976                let message = format!("Failed to open permalink: {err}");
18977
18978                anyhow::Result::<()>::Err(err).log_err();
18979
18980                if let Some(workspace) = workspace {
18981                    workspace
18982                        .update(cx, |workspace, cx| {
18983                            struct OpenPermalinkToLine;
18984
18985                            workspace.show_toast(
18986                                Toast::new(
18987                                    NotificationId::unique::<OpenPermalinkToLine>(),
18988                                    message,
18989                                ),
18990                                cx,
18991                            )
18992                        })
18993                        .ok();
18994                }
18995            }
18996        })
18997        .detach();
18998    }
18999
19000    pub fn insert_uuid_v4(
19001        &mut self,
19002        _: &InsertUuidV4,
19003        window: &mut Window,
19004        cx: &mut Context<Self>,
19005    ) {
19006        self.insert_uuid(UuidVersion::V4, window, cx);
19007    }
19008
19009    pub fn insert_uuid_v7(
19010        &mut self,
19011        _: &InsertUuidV7,
19012        window: &mut Window,
19013        cx: &mut Context<Self>,
19014    ) {
19015        self.insert_uuid(UuidVersion::V7, window, cx);
19016    }
19017
19018    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19020        self.transact(window, cx, |this, window, cx| {
19021            let edits = this
19022                .selections
19023                .all::<Point>(cx)
19024                .into_iter()
19025                .map(|selection| {
19026                    let uuid = match version {
19027                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19028                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19029                    };
19030
19031                    (selection.range(), uuid.to_string())
19032                });
19033            this.edit(edits, cx);
19034            this.refresh_edit_prediction(true, false, window, cx);
19035        });
19036    }
19037
19038    pub fn open_selections_in_multibuffer(
19039        &mut self,
19040        _: &OpenSelectionsInMultibuffer,
19041        window: &mut Window,
19042        cx: &mut Context<Self>,
19043    ) {
19044        let multibuffer = self.buffer.read(cx);
19045
19046        let Some(buffer) = multibuffer.as_singleton() else {
19047            return;
19048        };
19049
19050        let Some(workspace) = self.workspace() else {
19051            return;
19052        };
19053
19054        let title = multibuffer.title(cx).to_string();
19055
19056        let locations = self
19057            .selections
19058            .all_anchors(cx)
19059            .into_iter()
19060            .map(|selection| Location {
19061                buffer: buffer.clone(),
19062                range: selection.start.text_anchor..selection.end.text_anchor,
19063            })
19064            .collect::<Vec<_>>();
19065
19066        cx.spawn_in(window, async move |_, cx| {
19067            workspace.update_in(cx, |workspace, window, cx| {
19068                Self::open_locations_in_multibuffer(
19069                    workspace,
19070                    locations,
19071                    format!("Selections for '{title}'"),
19072                    false,
19073                    MultibufferSelectionMode::All,
19074                    window,
19075                    cx,
19076                );
19077            })
19078        })
19079        .detach();
19080    }
19081
19082    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19083    /// last highlight added will be used.
19084    ///
19085    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19086    pub fn highlight_rows<T: 'static>(
19087        &mut self,
19088        range: Range<Anchor>,
19089        color: Hsla,
19090        options: RowHighlightOptions,
19091        cx: &mut Context<Self>,
19092    ) {
19093        let snapshot = self.buffer().read(cx).snapshot(cx);
19094        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19095        let ix = row_highlights.binary_search_by(|highlight| {
19096            Ordering::Equal
19097                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19098                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19099        });
19100
19101        if let Err(mut ix) = ix {
19102            let index = post_inc(&mut self.highlight_order);
19103
19104            // If this range intersects with the preceding highlight, then merge it with
19105            // the preceding highlight. Otherwise insert a new highlight.
19106            let mut merged = false;
19107            if ix > 0 {
19108                let prev_highlight = &mut row_highlights[ix - 1];
19109                if prev_highlight
19110                    .range
19111                    .end
19112                    .cmp(&range.start, &snapshot)
19113                    .is_ge()
19114                {
19115                    ix -= 1;
19116                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19117                        prev_highlight.range.end = range.end;
19118                    }
19119                    merged = true;
19120                    prev_highlight.index = index;
19121                    prev_highlight.color = color;
19122                    prev_highlight.options = options;
19123                }
19124            }
19125
19126            if !merged {
19127                row_highlights.insert(
19128                    ix,
19129                    RowHighlight {
19130                        range: range.clone(),
19131                        index,
19132                        color,
19133                        options,
19134                        type_id: TypeId::of::<T>(),
19135                    },
19136                );
19137            }
19138
19139            // If any of the following highlights intersect with this one, merge them.
19140            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19141                let highlight = &row_highlights[ix];
19142                if next_highlight
19143                    .range
19144                    .start
19145                    .cmp(&highlight.range.end, &snapshot)
19146                    .is_le()
19147                {
19148                    if next_highlight
19149                        .range
19150                        .end
19151                        .cmp(&highlight.range.end, &snapshot)
19152                        .is_gt()
19153                    {
19154                        row_highlights[ix].range.end = next_highlight.range.end;
19155                    }
19156                    row_highlights.remove(ix + 1);
19157                } else {
19158                    break;
19159                }
19160            }
19161        }
19162    }
19163
19164    /// Remove any highlighted row ranges of the given type that intersect the
19165    /// given ranges.
19166    pub fn remove_highlighted_rows<T: 'static>(
19167        &mut self,
19168        ranges_to_remove: Vec<Range<Anchor>>,
19169        cx: &mut Context<Self>,
19170    ) {
19171        let snapshot = self.buffer().read(cx).snapshot(cx);
19172        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19173        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19174        row_highlights.retain(|highlight| {
19175            while let Some(range_to_remove) = ranges_to_remove.peek() {
19176                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19177                    Ordering::Less | Ordering::Equal => {
19178                        ranges_to_remove.next();
19179                    }
19180                    Ordering::Greater => {
19181                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19182                            Ordering::Less | Ordering::Equal => {
19183                                return false;
19184                            }
19185                            Ordering::Greater => break,
19186                        }
19187                    }
19188                }
19189            }
19190
19191            true
19192        })
19193    }
19194
19195    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19196    pub fn clear_row_highlights<T: 'static>(&mut self) {
19197        self.highlighted_rows.remove(&TypeId::of::<T>());
19198    }
19199
19200    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19201    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19202        self.highlighted_rows
19203            .get(&TypeId::of::<T>())
19204            .map_or(&[] as &[_], |vec| vec.as_slice())
19205            .iter()
19206            .map(|highlight| (highlight.range.clone(), highlight.color))
19207    }
19208
19209    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19210    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19211    /// Allows to ignore certain kinds of highlights.
19212    pub fn highlighted_display_rows(
19213        &self,
19214        window: &mut Window,
19215        cx: &mut App,
19216    ) -> BTreeMap<DisplayRow, LineHighlight> {
19217        let snapshot = self.snapshot(window, cx);
19218        let mut used_highlight_orders = HashMap::default();
19219        self.highlighted_rows
19220            .iter()
19221            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19222            .fold(
19223                BTreeMap::<DisplayRow, LineHighlight>::new(),
19224                |mut unique_rows, highlight| {
19225                    let start = highlight.range.start.to_display_point(&snapshot);
19226                    let end = highlight.range.end.to_display_point(&snapshot);
19227                    let start_row = start.row().0;
19228                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19229                        && end.column() == 0
19230                    {
19231                        end.row().0.saturating_sub(1)
19232                    } else {
19233                        end.row().0
19234                    };
19235                    for row in start_row..=end_row {
19236                        let used_index =
19237                            used_highlight_orders.entry(row).or_insert(highlight.index);
19238                        if highlight.index >= *used_index {
19239                            *used_index = highlight.index;
19240                            unique_rows.insert(
19241                                DisplayRow(row),
19242                                LineHighlight {
19243                                    include_gutter: highlight.options.include_gutter,
19244                                    border: None,
19245                                    background: highlight.color.into(),
19246                                    type_id: Some(highlight.type_id),
19247                                },
19248                            );
19249                        }
19250                    }
19251                    unique_rows
19252                },
19253            )
19254    }
19255
19256    pub fn highlighted_display_row_for_autoscroll(
19257        &self,
19258        snapshot: &DisplaySnapshot,
19259    ) -> Option<DisplayRow> {
19260        self.highlighted_rows
19261            .values()
19262            .flat_map(|highlighted_rows| highlighted_rows.iter())
19263            .filter_map(|highlight| {
19264                if highlight.options.autoscroll {
19265                    Some(highlight.range.start.to_display_point(snapshot).row())
19266                } else {
19267                    None
19268                }
19269            })
19270            .min()
19271    }
19272
19273    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19274        self.highlight_background::<SearchWithinRange>(
19275            ranges,
19276            |colors| colors.colors().editor_document_highlight_read_background,
19277            cx,
19278        )
19279    }
19280
19281    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19282        self.breadcrumb_header = Some(new_header);
19283    }
19284
19285    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19286        self.clear_background_highlights::<SearchWithinRange>(cx);
19287    }
19288
19289    pub fn highlight_background<T: 'static>(
19290        &mut self,
19291        ranges: &[Range<Anchor>],
19292        color_fetcher: fn(&Theme) -> Hsla,
19293        cx: &mut Context<Self>,
19294    ) {
19295        self.background_highlights.insert(
19296            HighlightKey::Type(TypeId::of::<T>()),
19297            (color_fetcher, Arc::from(ranges)),
19298        );
19299        self.scrollbar_marker_state.dirty = true;
19300        cx.notify();
19301    }
19302
19303    pub fn highlight_background_key<T: 'static>(
19304        &mut self,
19305        key: usize,
19306        ranges: &[Range<Anchor>],
19307        color_fetcher: fn(&Theme) -> Hsla,
19308        cx: &mut Context<Self>,
19309    ) {
19310        self.background_highlights.insert(
19311            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19312            (color_fetcher, Arc::from(ranges)),
19313        );
19314        self.scrollbar_marker_state.dirty = true;
19315        cx.notify();
19316    }
19317
19318    pub fn clear_background_highlights<T: 'static>(
19319        &mut self,
19320        cx: &mut Context<Self>,
19321    ) -> Option<BackgroundHighlight> {
19322        let text_highlights = self
19323            .background_highlights
19324            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19325        if !text_highlights.1.is_empty() {
19326            self.scrollbar_marker_state.dirty = true;
19327            cx.notify();
19328        }
19329        Some(text_highlights)
19330    }
19331
19332    pub fn highlight_gutter<T: 'static>(
19333        &mut self,
19334        ranges: impl Into<Vec<Range<Anchor>>>,
19335        color_fetcher: fn(&App) -> Hsla,
19336        cx: &mut Context<Self>,
19337    ) {
19338        self.gutter_highlights
19339            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19340        cx.notify();
19341    }
19342
19343    pub fn clear_gutter_highlights<T: 'static>(
19344        &mut self,
19345        cx: &mut Context<Self>,
19346    ) -> Option<GutterHighlight> {
19347        cx.notify();
19348        self.gutter_highlights.remove(&TypeId::of::<T>())
19349    }
19350
19351    pub fn insert_gutter_highlight<T: 'static>(
19352        &mut self,
19353        range: Range<Anchor>,
19354        color_fetcher: fn(&App) -> Hsla,
19355        cx: &mut Context<Self>,
19356    ) {
19357        let snapshot = self.buffer().read(cx).snapshot(cx);
19358        let mut highlights = self
19359            .gutter_highlights
19360            .remove(&TypeId::of::<T>())
19361            .map(|(_, highlights)| highlights)
19362            .unwrap_or_default();
19363        let ix = highlights.binary_search_by(|highlight| {
19364            Ordering::Equal
19365                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19366                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19367        });
19368        if let Err(ix) = ix {
19369            highlights.insert(ix, range);
19370        }
19371        self.gutter_highlights
19372            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19373    }
19374
19375    pub fn remove_gutter_highlights<T: 'static>(
19376        &mut self,
19377        ranges_to_remove: Vec<Range<Anchor>>,
19378        cx: &mut Context<Self>,
19379    ) {
19380        let snapshot = self.buffer().read(cx).snapshot(cx);
19381        let Some((color_fetcher, mut gutter_highlights)) =
19382            self.gutter_highlights.remove(&TypeId::of::<T>())
19383        else {
19384            return;
19385        };
19386        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19387        gutter_highlights.retain(|highlight| {
19388            while let Some(range_to_remove) = ranges_to_remove.peek() {
19389                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19390                    Ordering::Less | Ordering::Equal => {
19391                        ranges_to_remove.next();
19392                    }
19393                    Ordering::Greater => {
19394                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19395                            Ordering::Less | Ordering::Equal => {
19396                                return false;
19397                            }
19398                            Ordering::Greater => break,
19399                        }
19400                    }
19401                }
19402            }
19403
19404            true
19405        });
19406        self.gutter_highlights
19407            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19408    }
19409
19410    #[cfg(feature = "test-support")]
19411    pub fn all_text_highlights(
19412        &self,
19413        window: &mut Window,
19414        cx: &mut Context<Self>,
19415    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19416        let snapshot = self.snapshot(window, cx);
19417        self.display_map.update(cx, |display_map, _| {
19418            display_map
19419                .all_text_highlights()
19420                .map(|highlight| {
19421                    let (style, ranges) = highlight.as_ref();
19422                    (
19423                        *style,
19424                        ranges
19425                            .iter()
19426                            .map(|range| range.clone().to_display_points(&snapshot))
19427                            .collect(),
19428                    )
19429                })
19430                .collect()
19431        })
19432    }
19433
19434    #[cfg(feature = "test-support")]
19435    pub fn all_text_background_highlights(
19436        &self,
19437        window: &mut Window,
19438        cx: &mut Context<Self>,
19439    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19440        let snapshot = self.snapshot(window, cx);
19441        let buffer = &snapshot.buffer_snapshot;
19442        let start = buffer.anchor_before(0);
19443        let end = buffer.anchor_after(buffer.len());
19444        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19445    }
19446
19447    #[cfg(feature = "test-support")]
19448    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19449        let snapshot = self.buffer().read(cx).snapshot(cx);
19450
19451        let highlights = self
19452            .background_highlights
19453            .get(&HighlightKey::Type(TypeId::of::<
19454                items::BufferSearchHighlights,
19455            >()));
19456
19457        if let Some((_color, ranges)) = highlights {
19458            ranges
19459                .iter()
19460                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19461                .collect_vec()
19462        } else {
19463            vec![]
19464        }
19465    }
19466
19467    fn document_highlights_for_position<'a>(
19468        &'a self,
19469        position: Anchor,
19470        buffer: &'a MultiBufferSnapshot,
19471    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19472        let read_highlights = self
19473            .background_highlights
19474            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19475            .map(|h| &h.1);
19476        let write_highlights = self
19477            .background_highlights
19478            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19479            .map(|h| &h.1);
19480        let left_position = position.bias_left(buffer);
19481        let right_position = position.bias_right(buffer);
19482        read_highlights
19483            .into_iter()
19484            .chain(write_highlights)
19485            .flat_map(move |ranges| {
19486                let start_ix = match ranges.binary_search_by(|probe| {
19487                    let cmp = probe.end.cmp(&left_position, buffer);
19488                    if cmp.is_ge() {
19489                        Ordering::Greater
19490                    } else {
19491                        Ordering::Less
19492                    }
19493                }) {
19494                    Ok(i) | Err(i) => i,
19495                };
19496
19497                ranges[start_ix..]
19498                    .iter()
19499                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19500            })
19501    }
19502
19503    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19504        self.background_highlights
19505            .get(&HighlightKey::Type(TypeId::of::<T>()))
19506            .map_or(false, |(_, highlights)| !highlights.is_empty())
19507    }
19508
19509    pub fn background_highlights_in_range(
19510        &self,
19511        search_range: Range<Anchor>,
19512        display_snapshot: &DisplaySnapshot,
19513        theme: &Theme,
19514    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19515        let mut results = Vec::new();
19516        for (color_fetcher, ranges) in self.background_highlights.values() {
19517            let color = color_fetcher(theme);
19518            let start_ix = match ranges.binary_search_by(|probe| {
19519                let cmp = probe
19520                    .end
19521                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19522                if cmp.is_gt() {
19523                    Ordering::Greater
19524                } else {
19525                    Ordering::Less
19526                }
19527            }) {
19528                Ok(i) | Err(i) => i,
19529            };
19530            for range in &ranges[start_ix..] {
19531                if range
19532                    .start
19533                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19534                    .is_ge()
19535                {
19536                    break;
19537                }
19538
19539                let start = range.start.to_display_point(display_snapshot);
19540                let end = range.end.to_display_point(display_snapshot);
19541                results.push((start..end, color))
19542            }
19543        }
19544        results
19545    }
19546
19547    pub fn background_highlight_row_ranges<T: 'static>(
19548        &self,
19549        search_range: Range<Anchor>,
19550        display_snapshot: &DisplaySnapshot,
19551        count: usize,
19552    ) -> Vec<RangeInclusive<DisplayPoint>> {
19553        let mut results = Vec::new();
19554        let Some((_, ranges)) = self
19555            .background_highlights
19556            .get(&HighlightKey::Type(TypeId::of::<T>()))
19557        else {
19558            return vec![];
19559        };
19560
19561        let start_ix = match ranges.binary_search_by(|probe| {
19562            let cmp = probe
19563                .end
19564                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19565            if cmp.is_gt() {
19566                Ordering::Greater
19567            } else {
19568                Ordering::Less
19569            }
19570        }) {
19571            Ok(i) | Err(i) => i,
19572        };
19573        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19574            if let (Some(start_display), Some(end_display)) = (start, end) {
19575                results.push(
19576                    start_display.to_display_point(display_snapshot)
19577                        ..=end_display.to_display_point(display_snapshot),
19578                );
19579            }
19580        };
19581        let mut start_row: Option<Point> = None;
19582        let mut end_row: Option<Point> = None;
19583        if ranges.len() > count {
19584            return Vec::new();
19585        }
19586        for range in &ranges[start_ix..] {
19587            if range
19588                .start
19589                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19590                .is_ge()
19591            {
19592                break;
19593            }
19594            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19595            if let Some(current_row) = &end_row {
19596                if end.row == current_row.row {
19597                    continue;
19598                }
19599            }
19600            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19601            if start_row.is_none() {
19602                assert_eq!(end_row, None);
19603                start_row = Some(start);
19604                end_row = Some(end);
19605                continue;
19606            }
19607            if let Some(current_end) = end_row.as_mut() {
19608                if start.row > current_end.row + 1 {
19609                    push_region(start_row, end_row);
19610                    start_row = Some(start);
19611                    end_row = Some(end);
19612                } else {
19613                    // Merge two hunks.
19614                    *current_end = end;
19615                }
19616            } else {
19617                unreachable!();
19618            }
19619        }
19620        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19621        push_region(start_row, end_row);
19622        results
19623    }
19624
19625    pub fn gutter_highlights_in_range(
19626        &self,
19627        search_range: Range<Anchor>,
19628        display_snapshot: &DisplaySnapshot,
19629        cx: &App,
19630    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19631        let mut results = Vec::new();
19632        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19633            let color = color_fetcher(cx);
19634            let start_ix = match ranges.binary_search_by(|probe| {
19635                let cmp = probe
19636                    .end
19637                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19638                if cmp.is_gt() {
19639                    Ordering::Greater
19640                } else {
19641                    Ordering::Less
19642                }
19643            }) {
19644                Ok(i) | Err(i) => i,
19645            };
19646            for range in &ranges[start_ix..] {
19647                if range
19648                    .start
19649                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19650                    .is_ge()
19651                {
19652                    break;
19653                }
19654
19655                let start = range.start.to_display_point(display_snapshot);
19656                let end = range.end.to_display_point(display_snapshot);
19657                results.push((start..end, color))
19658            }
19659        }
19660        results
19661    }
19662
19663    /// Get the text ranges corresponding to the redaction query
19664    pub fn redacted_ranges(
19665        &self,
19666        search_range: Range<Anchor>,
19667        display_snapshot: &DisplaySnapshot,
19668        cx: &App,
19669    ) -> Vec<Range<DisplayPoint>> {
19670        display_snapshot
19671            .buffer_snapshot
19672            .redacted_ranges(search_range, |file| {
19673                if let Some(file) = file {
19674                    file.is_private()
19675                        && EditorSettings::get(
19676                            Some(SettingsLocation {
19677                                worktree_id: file.worktree_id(cx),
19678                                path: file.path().as_ref(),
19679                            }),
19680                            cx,
19681                        )
19682                        .redact_private_values
19683                } else {
19684                    false
19685                }
19686            })
19687            .map(|range| {
19688                range.start.to_display_point(display_snapshot)
19689                    ..range.end.to_display_point(display_snapshot)
19690            })
19691            .collect()
19692    }
19693
19694    pub fn highlight_text_key<T: 'static>(
19695        &mut self,
19696        key: usize,
19697        ranges: Vec<Range<Anchor>>,
19698        style: HighlightStyle,
19699        cx: &mut Context<Self>,
19700    ) {
19701        self.display_map.update(cx, |map, _| {
19702            map.highlight_text(
19703                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19704                ranges,
19705                style,
19706            );
19707        });
19708        cx.notify();
19709    }
19710
19711    pub fn highlight_text<T: 'static>(
19712        &mut self,
19713        ranges: Vec<Range<Anchor>>,
19714        style: HighlightStyle,
19715        cx: &mut Context<Self>,
19716    ) {
19717        self.display_map.update(cx, |map, _| {
19718            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19719        });
19720        cx.notify();
19721    }
19722
19723    pub(crate) fn highlight_inlays<T: 'static>(
19724        &mut self,
19725        highlights: Vec<InlayHighlight>,
19726        style: HighlightStyle,
19727        cx: &mut Context<Self>,
19728    ) {
19729        self.display_map.update(cx, |map, _| {
19730            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19731        });
19732        cx.notify();
19733    }
19734
19735    pub fn text_highlights<'a, T: 'static>(
19736        &'a self,
19737        cx: &'a App,
19738    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19739        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19740    }
19741
19742    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19743        let cleared = self
19744            .display_map
19745            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19746        if cleared {
19747            cx.notify();
19748        }
19749    }
19750
19751    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19752        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19753            && self.focus_handle.is_focused(window)
19754    }
19755
19756    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19757        self.show_cursor_when_unfocused = is_enabled;
19758        cx.notify();
19759    }
19760
19761    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19762        cx.notify();
19763    }
19764
19765    fn on_debug_session_event(
19766        &mut self,
19767        _session: Entity<Session>,
19768        event: &SessionEvent,
19769        cx: &mut Context<Self>,
19770    ) {
19771        match event {
19772            SessionEvent::InvalidateInlineValue => {
19773                self.refresh_inline_values(cx);
19774            }
19775            _ => {}
19776        }
19777    }
19778
19779    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19780        let Some(project) = self.project.clone() else {
19781            return;
19782        };
19783
19784        if !self.inline_value_cache.enabled {
19785            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19786            self.splice_inlays(&inlays, Vec::new(), cx);
19787            return;
19788        }
19789
19790        let current_execution_position = self
19791            .highlighted_rows
19792            .get(&TypeId::of::<ActiveDebugLine>())
19793            .and_then(|lines| lines.last().map(|line| line.range.end));
19794
19795        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19796            let inline_values = editor
19797                .update(cx, |editor, cx| {
19798                    let Some(current_execution_position) = current_execution_position else {
19799                        return Some(Task::ready(Ok(Vec::new())));
19800                    };
19801
19802                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19803                        let snapshot = buffer.snapshot(cx);
19804
19805                        let excerpt = snapshot.excerpt_containing(
19806                            current_execution_position..current_execution_position,
19807                        )?;
19808
19809                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19810                    })?;
19811
19812                    let range =
19813                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19814
19815                    project.inline_values(buffer, range, cx)
19816                })
19817                .ok()
19818                .flatten()?
19819                .await
19820                .context("refreshing debugger inlays")
19821                .log_err()?;
19822
19823            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19824
19825            for (buffer_id, inline_value) in inline_values
19826                .into_iter()
19827                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19828            {
19829                buffer_inline_values
19830                    .entry(buffer_id)
19831                    .or_default()
19832                    .push(inline_value);
19833            }
19834
19835            editor
19836                .update(cx, |editor, cx| {
19837                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19838                    let mut new_inlays = Vec::default();
19839
19840                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19841                        let buffer_id = buffer_snapshot.remote_id();
19842                        buffer_inline_values
19843                            .get(&buffer_id)
19844                            .into_iter()
19845                            .flatten()
19846                            .for_each(|hint| {
19847                                let inlay = Inlay::debugger(
19848                                    post_inc(&mut editor.next_inlay_id),
19849                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19850                                    hint.text(),
19851                                );
19852                                if !inlay.text.chars().contains(&'\n') {
19853                                    new_inlays.push(inlay);
19854                                }
19855                            });
19856                    }
19857
19858                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19859                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19860
19861                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19862                })
19863                .ok()?;
19864            Some(())
19865        });
19866    }
19867
19868    fn on_buffer_event(
19869        &mut self,
19870        multibuffer: &Entity<MultiBuffer>,
19871        event: &multi_buffer::Event,
19872        window: &mut Window,
19873        cx: &mut Context<Self>,
19874    ) {
19875        match event {
19876            multi_buffer::Event::Edited {
19877                singleton_buffer_edited,
19878                edited_buffer,
19879            } => {
19880                self.scrollbar_marker_state.dirty = true;
19881                self.active_indent_guides_state.dirty = true;
19882                self.refresh_active_diagnostics(cx);
19883                self.refresh_code_actions(window, cx);
19884                self.refresh_selected_text_highlights(true, window, cx);
19885                self.refresh_single_line_folds(window, cx);
19886                refresh_matching_bracket_highlights(self, window, cx);
19887                if self.has_active_edit_prediction() {
19888                    self.update_visible_edit_prediction(window, cx);
19889                }
19890                if let Some(project) = self.project.as_ref() {
19891                    if let Some(edited_buffer) = edited_buffer {
19892                        project.update(cx, |project, cx| {
19893                            self.registered_buffers
19894                                .entry(edited_buffer.read(cx).remote_id())
19895                                .or_insert_with(|| {
19896                                    project
19897                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19898                                });
19899                        });
19900                    }
19901                }
19902                cx.emit(EditorEvent::BufferEdited);
19903                cx.emit(SearchEvent::MatchesInvalidated);
19904
19905                if let Some(buffer) = edited_buffer {
19906                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19907                }
19908
19909                if *singleton_buffer_edited {
19910                    if let Some(buffer) = edited_buffer {
19911                        if buffer.read(cx).file().is_none() {
19912                            cx.emit(EditorEvent::TitleChanged);
19913                        }
19914                    }
19915                    if let Some(project) = &self.project {
19916                        #[allow(clippy::mutable_key_type)]
19917                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19918                            multibuffer
19919                                .all_buffers()
19920                                .into_iter()
19921                                .filter_map(|buffer| {
19922                                    buffer.update(cx, |buffer, cx| {
19923                                        let language = buffer.language()?;
19924                                        let should_discard = project.update(cx, |project, cx| {
19925                                            project.is_local()
19926                                                && !project.has_language_servers_for(buffer, cx)
19927                                        });
19928                                        should_discard.not().then_some(language.clone())
19929                                    })
19930                                })
19931                                .collect::<HashSet<_>>()
19932                        });
19933                        if !languages_affected.is_empty() {
19934                            self.refresh_inlay_hints(
19935                                InlayHintRefreshReason::BufferEdited(languages_affected),
19936                                cx,
19937                            );
19938                        }
19939                    }
19940                }
19941
19942                let Some(project) = &self.project else { return };
19943                let (telemetry, is_via_ssh) = {
19944                    let project = project.read(cx);
19945                    let telemetry = project.client().telemetry().clone();
19946                    let is_via_ssh = project.is_via_ssh();
19947                    (telemetry, is_via_ssh)
19948                };
19949                refresh_linked_ranges(self, window, cx);
19950                telemetry.log_edit_event("editor", is_via_ssh);
19951            }
19952            multi_buffer::Event::ExcerptsAdded {
19953                buffer,
19954                predecessor,
19955                excerpts,
19956            } => {
19957                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19958                let buffer_id = buffer.read(cx).remote_id();
19959                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19960                    if let Some(project) = &self.project {
19961                        update_uncommitted_diff_for_buffer(
19962                            cx.entity(),
19963                            project,
19964                            [buffer.clone()],
19965                            self.buffer.clone(),
19966                            cx,
19967                        )
19968                        .detach();
19969                    }
19970                }
19971                self.update_lsp_data(false, Some(buffer_id), window, cx);
19972                cx.emit(EditorEvent::ExcerptsAdded {
19973                    buffer: buffer.clone(),
19974                    predecessor: *predecessor,
19975                    excerpts: excerpts.clone(),
19976                });
19977                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19978            }
19979            multi_buffer::Event::ExcerptsRemoved {
19980                ids,
19981                removed_buffer_ids,
19982            } => {
19983                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19984                let buffer = self.buffer.read(cx);
19985                self.registered_buffers
19986                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19987                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19988                cx.emit(EditorEvent::ExcerptsRemoved {
19989                    ids: ids.clone(),
19990                    removed_buffer_ids: removed_buffer_ids.clone(),
19991                });
19992            }
19993            multi_buffer::Event::ExcerptsEdited {
19994                excerpt_ids,
19995                buffer_ids,
19996            } => {
19997                self.display_map.update(cx, |map, cx| {
19998                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19999                });
20000                cx.emit(EditorEvent::ExcerptsEdited {
20001                    ids: excerpt_ids.clone(),
20002                });
20003            }
20004            multi_buffer::Event::ExcerptsExpanded { ids } => {
20005                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20006                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20007            }
20008            multi_buffer::Event::Reparsed(buffer_id) => {
20009                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20010                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20011
20012                cx.emit(EditorEvent::Reparsed(*buffer_id));
20013            }
20014            multi_buffer::Event::DiffHunksToggled => {
20015                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20016            }
20017            multi_buffer::Event::LanguageChanged(buffer_id) => {
20018                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20019                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20020                cx.emit(EditorEvent::Reparsed(*buffer_id));
20021                cx.notify();
20022            }
20023            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20024            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20025            multi_buffer::Event::FileHandleChanged
20026            | multi_buffer::Event::Reloaded
20027            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20028            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20029            multi_buffer::Event::DiagnosticsUpdated => {
20030                self.update_diagnostics_state(window, cx);
20031            }
20032            _ => {}
20033        };
20034    }
20035
20036    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20037        if !self.diagnostics_enabled() {
20038            return;
20039        }
20040        self.refresh_active_diagnostics(cx);
20041        self.refresh_inline_diagnostics(true, window, cx);
20042        self.scrollbar_marker_state.dirty = true;
20043        cx.notify();
20044    }
20045
20046    pub fn start_temporary_diff_override(&mut self) {
20047        self.load_diff_task.take();
20048        self.temporary_diff_override = true;
20049    }
20050
20051    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20052        self.temporary_diff_override = false;
20053        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20054        self.buffer.update(cx, |buffer, cx| {
20055            buffer.set_all_diff_hunks_collapsed(cx);
20056        });
20057
20058        if let Some(project) = self.project.clone() {
20059            self.load_diff_task = Some(
20060                update_uncommitted_diff_for_buffer(
20061                    cx.entity(),
20062                    &project,
20063                    self.buffer.read(cx).all_buffers(),
20064                    self.buffer.clone(),
20065                    cx,
20066                )
20067                .shared(),
20068            );
20069        }
20070    }
20071
20072    fn on_display_map_changed(
20073        &mut self,
20074        _: Entity<DisplayMap>,
20075        _: &mut Window,
20076        cx: &mut Context<Self>,
20077    ) {
20078        cx.notify();
20079    }
20080
20081    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20082        if self.diagnostics_enabled() {
20083            let new_severity = EditorSettings::get_global(cx)
20084                .diagnostics_max_severity
20085                .unwrap_or(DiagnosticSeverity::Hint);
20086            self.set_max_diagnostics_severity(new_severity, cx);
20087        }
20088        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20089        self.update_edit_prediction_settings(cx);
20090        self.refresh_edit_prediction(true, false, window, cx);
20091        self.refresh_inline_values(cx);
20092        self.refresh_inlay_hints(
20093            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20094                self.selections.newest_anchor().head(),
20095                &self.buffer.read(cx).snapshot(cx),
20096                cx,
20097            )),
20098            cx,
20099        );
20100
20101        let old_cursor_shape = self.cursor_shape;
20102
20103        {
20104            let editor_settings = EditorSettings::get_global(cx);
20105            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20106            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20107            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20108            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20109        }
20110
20111        if old_cursor_shape != self.cursor_shape {
20112            cx.emit(EditorEvent::CursorShapeChanged);
20113        }
20114
20115        let project_settings = ProjectSettings::get_global(cx);
20116        self.serialize_dirty_buffers =
20117            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20118
20119        if self.mode.is_full() {
20120            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20121            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20122            if self.show_inline_diagnostics != show_inline_diagnostics {
20123                self.show_inline_diagnostics = show_inline_diagnostics;
20124                self.refresh_inline_diagnostics(false, window, cx);
20125            }
20126
20127            if self.git_blame_inline_enabled != inline_blame_enabled {
20128                self.toggle_git_blame_inline_internal(false, window, cx);
20129            }
20130
20131            let minimap_settings = EditorSettings::get_global(cx).minimap;
20132            if self.minimap_visibility != MinimapVisibility::Disabled {
20133                if self.minimap_visibility.settings_visibility()
20134                    != minimap_settings.minimap_enabled()
20135                {
20136                    self.set_minimap_visibility(
20137                        MinimapVisibility::for_mode(self.mode(), cx),
20138                        window,
20139                        cx,
20140                    );
20141                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20142                    minimap_entity.update(cx, |minimap_editor, cx| {
20143                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20144                    })
20145                }
20146            }
20147        }
20148
20149        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20150            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20151        }) {
20152            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20153                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20154            }
20155            self.refresh_colors(false, None, window, cx);
20156        }
20157
20158        cx.notify();
20159    }
20160
20161    pub fn set_searchable(&mut self, searchable: bool) {
20162        self.searchable = searchable;
20163    }
20164
20165    pub fn searchable(&self) -> bool {
20166        self.searchable
20167    }
20168
20169    fn open_proposed_changes_editor(
20170        &mut self,
20171        _: &OpenProposedChangesEditor,
20172        window: &mut Window,
20173        cx: &mut Context<Self>,
20174    ) {
20175        let Some(workspace) = self.workspace() else {
20176            cx.propagate();
20177            return;
20178        };
20179
20180        let selections = self.selections.all::<usize>(cx);
20181        let multi_buffer = self.buffer.read(cx);
20182        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20183        let mut new_selections_by_buffer = HashMap::default();
20184        for selection in selections {
20185            for (buffer, range, _) in
20186                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20187            {
20188                let mut range = range.to_point(buffer);
20189                range.start.column = 0;
20190                range.end.column = buffer.line_len(range.end.row);
20191                new_selections_by_buffer
20192                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20193                    .or_insert(Vec::new())
20194                    .push(range)
20195            }
20196        }
20197
20198        let proposed_changes_buffers = new_selections_by_buffer
20199            .into_iter()
20200            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20201            .collect::<Vec<_>>();
20202        let proposed_changes_editor = cx.new(|cx| {
20203            ProposedChangesEditor::new(
20204                "Proposed changes",
20205                proposed_changes_buffers,
20206                self.project.clone(),
20207                window,
20208                cx,
20209            )
20210        });
20211
20212        window.defer(cx, move |window, cx| {
20213            workspace.update(cx, |workspace, cx| {
20214                workspace.active_pane().update(cx, |pane, cx| {
20215                    pane.add_item(
20216                        Box::new(proposed_changes_editor),
20217                        true,
20218                        true,
20219                        None,
20220                        window,
20221                        cx,
20222                    );
20223                });
20224            });
20225        });
20226    }
20227
20228    pub fn open_excerpts_in_split(
20229        &mut self,
20230        _: &OpenExcerptsSplit,
20231        window: &mut Window,
20232        cx: &mut Context<Self>,
20233    ) {
20234        self.open_excerpts_common(None, true, window, cx)
20235    }
20236
20237    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20238        self.open_excerpts_common(None, false, window, cx)
20239    }
20240
20241    fn open_excerpts_common(
20242        &mut self,
20243        jump_data: Option<JumpData>,
20244        split: bool,
20245        window: &mut Window,
20246        cx: &mut Context<Self>,
20247    ) {
20248        let Some(workspace) = self.workspace() else {
20249            cx.propagate();
20250            return;
20251        };
20252
20253        if self.buffer.read(cx).is_singleton() {
20254            cx.propagate();
20255            return;
20256        }
20257
20258        let mut new_selections_by_buffer = HashMap::default();
20259        match &jump_data {
20260            Some(JumpData::MultiBufferPoint {
20261                excerpt_id,
20262                position,
20263                anchor,
20264                line_offset_from_top,
20265            }) => {
20266                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20267                if let Some(buffer) = multi_buffer_snapshot
20268                    .buffer_id_for_excerpt(*excerpt_id)
20269                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20270                {
20271                    let buffer_snapshot = buffer.read(cx).snapshot();
20272                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20273                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20274                    } else {
20275                        buffer_snapshot.clip_point(*position, Bias::Left)
20276                    };
20277                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20278                    new_selections_by_buffer.insert(
20279                        buffer,
20280                        (
20281                            vec![jump_to_offset..jump_to_offset],
20282                            Some(*line_offset_from_top),
20283                        ),
20284                    );
20285                }
20286            }
20287            Some(JumpData::MultiBufferRow {
20288                row,
20289                line_offset_from_top,
20290            }) => {
20291                let point = MultiBufferPoint::new(row.0, 0);
20292                if let Some((buffer, buffer_point, _)) =
20293                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20294                {
20295                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20296                    new_selections_by_buffer
20297                        .entry(buffer)
20298                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20299                        .0
20300                        .push(buffer_offset..buffer_offset)
20301                }
20302            }
20303            None => {
20304                let selections = self.selections.all::<usize>(cx);
20305                let multi_buffer = self.buffer.read(cx);
20306                for selection in selections {
20307                    for (snapshot, range, _, anchor) in multi_buffer
20308                        .snapshot(cx)
20309                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20310                    {
20311                        if let Some(anchor) = anchor {
20312                            // selection is in a deleted hunk
20313                            let Some(buffer_id) = anchor.buffer_id else {
20314                                continue;
20315                            };
20316                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20317                                continue;
20318                            };
20319                            let offset = text::ToOffset::to_offset(
20320                                &anchor.text_anchor,
20321                                &buffer_handle.read(cx).snapshot(),
20322                            );
20323                            let range = offset..offset;
20324                            new_selections_by_buffer
20325                                .entry(buffer_handle)
20326                                .or_insert((Vec::new(), None))
20327                                .0
20328                                .push(range)
20329                        } else {
20330                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20331                            else {
20332                                continue;
20333                            };
20334                            new_selections_by_buffer
20335                                .entry(buffer_handle)
20336                                .or_insert((Vec::new(), None))
20337                                .0
20338                                .push(range)
20339                        }
20340                    }
20341                }
20342            }
20343        }
20344
20345        new_selections_by_buffer
20346            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20347
20348        if new_selections_by_buffer.is_empty() {
20349            return;
20350        }
20351
20352        // We defer the pane interaction because we ourselves are a workspace item
20353        // and activating a new item causes the pane to call a method on us reentrantly,
20354        // which panics if we're on the stack.
20355        window.defer(cx, move |window, cx| {
20356            workspace.update(cx, |workspace, cx| {
20357                let pane = if split {
20358                    workspace.adjacent_pane(window, cx)
20359                } else {
20360                    workspace.active_pane().clone()
20361                };
20362
20363                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20364                    let editor = buffer
20365                        .read(cx)
20366                        .file()
20367                        .is_none()
20368                        .then(|| {
20369                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20370                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20371                            // Instead, we try to activate the existing editor in the pane first.
20372                            let (editor, pane_item_index) =
20373                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20374                                    let editor = item.downcast::<Editor>()?;
20375                                    let singleton_buffer =
20376                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20377                                    if singleton_buffer == buffer {
20378                                        Some((editor, i))
20379                                    } else {
20380                                        None
20381                                    }
20382                                })?;
20383                            pane.update(cx, |pane, cx| {
20384                                pane.activate_item(pane_item_index, true, true, window, cx)
20385                            });
20386                            Some(editor)
20387                        })
20388                        .flatten()
20389                        .unwrap_or_else(|| {
20390                            workspace.open_project_item::<Self>(
20391                                pane.clone(),
20392                                buffer,
20393                                true,
20394                                true,
20395                                window,
20396                                cx,
20397                            )
20398                        });
20399
20400                    editor.update(cx, |editor, cx| {
20401                        let autoscroll = match scroll_offset {
20402                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20403                            None => Autoscroll::newest(),
20404                        };
20405                        let nav_history = editor.nav_history.take();
20406                        editor.change_selections(
20407                            SelectionEffects::scroll(autoscroll),
20408                            window,
20409                            cx,
20410                            |s| {
20411                                s.select_ranges(ranges);
20412                            },
20413                        );
20414                        editor.nav_history = nav_history;
20415                    });
20416                }
20417            })
20418        });
20419    }
20420
20421    // For now, don't allow opening excerpts in buffers that aren't backed by
20422    // regular project files.
20423    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20424        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20425    }
20426
20427    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20428        let snapshot = self.buffer.read(cx).read(cx);
20429        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20430        Some(
20431            ranges
20432                .iter()
20433                .map(move |range| {
20434                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20435                })
20436                .collect(),
20437        )
20438    }
20439
20440    fn selection_replacement_ranges(
20441        &self,
20442        range: Range<OffsetUtf16>,
20443        cx: &mut App,
20444    ) -> Vec<Range<OffsetUtf16>> {
20445        let selections = self.selections.all::<OffsetUtf16>(cx);
20446        let newest_selection = selections
20447            .iter()
20448            .max_by_key(|selection| selection.id)
20449            .unwrap();
20450        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20451        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20452        let snapshot = self.buffer.read(cx).read(cx);
20453        selections
20454            .into_iter()
20455            .map(|mut selection| {
20456                selection.start.0 =
20457                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20458                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20459                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20460                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20461            })
20462            .collect()
20463    }
20464
20465    fn report_editor_event(
20466        &self,
20467        event_type: &'static str,
20468        file_extension: Option<String>,
20469        cx: &App,
20470    ) {
20471        if cfg!(any(test, feature = "test-support")) {
20472            return;
20473        }
20474
20475        let Some(project) = &self.project else { return };
20476
20477        // If None, we are in a file without an extension
20478        let file = self
20479            .buffer
20480            .read(cx)
20481            .as_singleton()
20482            .and_then(|b| b.read(cx).file());
20483        let file_extension = file_extension.or(file
20484            .as_ref()
20485            .and_then(|file| Path::new(file.file_name(cx)).extension())
20486            .and_then(|e| e.to_str())
20487            .map(|a| a.to_string()));
20488
20489        let vim_mode = vim_enabled(cx);
20490
20491        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20492        let copilot_enabled = edit_predictions_provider
20493            == language::language_settings::EditPredictionProvider::Copilot;
20494        let copilot_enabled_for_language = self
20495            .buffer
20496            .read(cx)
20497            .language_settings(cx)
20498            .show_edit_predictions;
20499
20500        let project = project.read(cx);
20501        telemetry::event!(
20502            event_type,
20503            file_extension,
20504            vim_mode,
20505            copilot_enabled,
20506            copilot_enabled_for_language,
20507            edit_predictions_provider,
20508            is_via_ssh = project.is_via_ssh(),
20509        );
20510    }
20511
20512    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20513    /// with each line being an array of {text, highlight} objects.
20514    fn copy_highlight_json(
20515        &mut self,
20516        _: &CopyHighlightJson,
20517        window: &mut Window,
20518        cx: &mut Context<Self>,
20519    ) {
20520        #[derive(Serialize)]
20521        struct Chunk<'a> {
20522            text: String,
20523            highlight: Option<&'a str>,
20524        }
20525
20526        let snapshot = self.buffer.read(cx).snapshot(cx);
20527        let range = self
20528            .selected_text_range(false, window, cx)
20529            .and_then(|selection| {
20530                if selection.range.is_empty() {
20531                    None
20532                } else {
20533                    Some(selection.range)
20534                }
20535            })
20536            .unwrap_or_else(|| 0..snapshot.len());
20537
20538        let chunks = snapshot.chunks(range, true);
20539        let mut lines = Vec::new();
20540        let mut line: VecDeque<Chunk> = VecDeque::new();
20541
20542        let Some(style) = self.style.as_ref() else {
20543            return;
20544        };
20545
20546        for chunk in chunks {
20547            let highlight = chunk
20548                .syntax_highlight_id
20549                .and_then(|id| id.name(&style.syntax));
20550            let mut chunk_lines = chunk.text.split('\n').peekable();
20551            while let Some(text) = chunk_lines.next() {
20552                let mut merged_with_last_token = false;
20553                if let Some(last_token) = line.back_mut() {
20554                    if last_token.highlight == highlight {
20555                        last_token.text.push_str(text);
20556                        merged_with_last_token = true;
20557                    }
20558                }
20559
20560                if !merged_with_last_token {
20561                    line.push_back(Chunk {
20562                        text: text.into(),
20563                        highlight,
20564                    });
20565                }
20566
20567                if chunk_lines.peek().is_some() {
20568                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20569                        line.pop_front();
20570                    }
20571                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20572                        line.pop_back();
20573                    }
20574
20575                    lines.push(mem::take(&mut line));
20576                }
20577            }
20578        }
20579
20580        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20581            return;
20582        };
20583        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20584    }
20585
20586    pub fn open_context_menu(
20587        &mut self,
20588        _: &OpenContextMenu,
20589        window: &mut Window,
20590        cx: &mut Context<Self>,
20591    ) {
20592        self.request_autoscroll(Autoscroll::newest(), cx);
20593        let position = self.selections.newest_display(cx).start;
20594        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20595    }
20596
20597    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20598        &self.inlay_hint_cache
20599    }
20600
20601    pub fn replay_insert_event(
20602        &mut self,
20603        text: &str,
20604        relative_utf16_range: Option<Range<isize>>,
20605        window: &mut Window,
20606        cx: &mut Context<Self>,
20607    ) {
20608        if !self.input_enabled {
20609            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20610            return;
20611        }
20612        if let Some(relative_utf16_range) = relative_utf16_range {
20613            let selections = self.selections.all::<OffsetUtf16>(cx);
20614            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20615                let new_ranges = selections.into_iter().map(|range| {
20616                    let start = OffsetUtf16(
20617                        range
20618                            .head()
20619                            .0
20620                            .saturating_add_signed(relative_utf16_range.start),
20621                    );
20622                    let end = OffsetUtf16(
20623                        range
20624                            .head()
20625                            .0
20626                            .saturating_add_signed(relative_utf16_range.end),
20627                    );
20628                    start..end
20629                });
20630                s.select_ranges(new_ranges);
20631            });
20632        }
20633
20634        self.handle_input(text, window, cx);
20635    }
20636
20637    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20638        let Some(provider) = self.semantics_provider.as_ref() else {
20639            return false;
20640        };
20641
20642        let mut supports = false;
20643        self.buffer().update(cx, |this, cx| {
20644            this.for_each_buffer(|buffer| {
20645                supports |= provider.supports_inlay_hints(buffer, cx);
20646            });
20647        });
20648
20649        supports
20650    }
20651
20652    pub fn is_focused(&self, window: &Window) -> bool {
20653        self.focus_handle.is_focused(window)
20654    }
20655
20656    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20657        cx.emit(EditorEvent::Focused);
20658
20659        if let Some(descendant) = self
20660            .last_focused_descendant
20661            .take()
20662            .and_then(|descendant| descendant.upgrade())
20663        {
20664            window.focus(&descendant);
20665        } else {
20666            if let Some(blame) = self.blame.as_ref() {
20667                blame.update(cx, GitBlame::focus)
20668            }
20669
20670            self.blink_manager.update(cx, BlinkManager::enable);
20671            self.show_cursor_names(window, cx);
20672            self.buffer.update(cx, |buffer, cx| {
20673                buffer.finalize_last_transaction(cx);
20674                if self.leader_id.is_none() {
20675                    buffer.set_active_selections(
20676                        &self.selections.disjoint_anchors(),
20677                        self.selections.line_mode,
20678                        self.cursor_shape,
20679                        cx,
20680                    );
20681                }
20682            });
20683        }
20684    }
20685
20686    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20687        cx.emit(EditorEvent::FocusedIn)
20688    }
20689
20690    fn handle_focus_out(
20691        &mut self,
20692        event: FocusOutEvent,
20693        _window: &mut Window,
20694        cx: &mut Context<Self>,
20695    ) {
20696        if event.blurred != self.focus_handle {
20697            self.last_focused_descendant = Some(event.blurred);
20698        }
20699        self.selection_drag_state = SelectionDragState::None;
20700        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20701    }
20702
20703    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20704        self.blink_manager.update(cx, BlinkManager::disable);
20705        self.buffer
20706            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20707
20708        if let Some(blame) = self.blame.as_ref() {
20709            blame.update(cx, GitBlame::blur)
20710        }
20711        if !self.hover_state.focused(window, cx) {
20712            hide_hover(self, cx);
20713        }
20714        if !self
20715            .context_menu
20716            .borrow()
20717            .as_ref()
20718            .is_some_and(|context_menu| context_menu.focused(window, cx))
20719        {
20720            self.hide_context_menu(window, cx);
20721        }
20722        self.discard_edit_prediction(false, cx);
20723        cx.emit(EditorEvent::Blurred);
20724        cx.notify();
20725    }
20726
20727    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20728        let mut pending: String = window
20729            .pending_input_keystrokes()
20730            .into_iter()
20731            .flatten()
20732            .filter_map(|keystroke| {
20733                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20734                    keystroke.key_char.clone()
20735                } else {
20736                    None
20737                }
20738            })
20739            .collect();
20740
20741        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20742            pending = "".to_string();
20743        }
20744
20745        let existing_pending = self
20746            .text_highlights::<PendingInput>(cx)
20747            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20748        if existing_pending.is_none() && pending.is_empty() {
20749            return;
20750        }
20751        let transaction =
20752            self.transact(window, cx, |this, window, cx| {
20753                let selections = this.selections.all::<usize>(cx);
20754                let edits = selections
20755                    .iter()
20756                    .map(|selection| (selection.end..selection.end, pending.clone()));
20757                this.edit(edits, cx);
20758                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20759                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20760                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20761                    }));
20762                });
20763                if let Some(existing_ranges) = existing_pending {
20764                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20765                    this.edit(edits, cx);
20766                }
20767            });
20768
20769        let snapshot = self.snapshot(window, cx);
20770        let ranges = self
20771            .selections
20772            .all::<usize>(cx)
20773            .into_iter()
20774            .map(|selection| {
20775                snapshot.buffer_snapshot.anchor_after(selection.end)
20776                    ..snapshot
20777                        .buffer_snapshot
20778                        .anchor_before(selection.end + pending.len())
20779            })
20780            .collect();
20781
20782        if pending.is_empty() {
20783            self.clear_highlights::<PendingInput>(cx);
20784        } else {
20785            self.highlight_text::<PendingInput>(
20786                ranges,
20787                HighlightStyle {
20788                    underline: Some(UnderlineStyle {
20789                        thickness: px(1.),
20790                        color: None,
20791                        wavy: false,
20792                    }),
20793                    ..Default::default()
20794                },
20795                cx,
20796            );
20797        }
20798
20799        self.ime_transaction = self.ime_transaction.or(transaction);
20800        if let Some(transaction) = self.ime_transaction {
20801            self.buffer.update(cx, |buffer, cx| {
20802                buffer.group_until_transaction(transaction, cx);
20803            });
20804        }
20805
20806        if self.text_highlights::<PendingInput>(cx).is_none() {
20807            self.ime_transaction.take();
20808        }
20809    }
20810
20811    pub fn register_action_renderer(
20812        &mut self,
20813        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20814    ) -> Subscription {
20815        let id = self.next_editor_action_id.post_inc();
20816        self.editor_actions
20817            .borrow_mut()
20818            .insert(id, Box::new(listener));
20819
20820        let editor_actions = self.editor_actions.clone();
20821        Subscription::new(move || {
20822            editor_actions.borrow_mut().remove(&id);
20823        })
20824    }
20825
20826    pub fn register_action<A: Action>(
20827        &mut self,
20828        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20829    ) -> Subscription {
20830        let id = self.next_editor_action_id.post_inc();
20831        let listener = Arc::new(listener);
20832        self.editor_actions.borrow_mut().insert(
20833            id,
20834            Box::new(move |_, window, _| {
20835                let listener = listener.clone();
20836                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20837                    let action = action.downcast_ref().unwrap();
20838                    if phase == DispatchPhase::Bubble {
20839                        listener(action, window, cx)
20840                    }
20841                })
20842            }),
20843        );
20844
20845        let editor_actions = self.editor_actions.clone();
20846        Subscription::new(move || {
20847            editor_actions.borrow_mut().remove(&id);
20848        })
20849    }
20850
20851    pub fn file_header_size(&self) -> u32 {
20852        FILE_HEADER_HEIGHT
20853    }
20854
20855    pub fn restore(
20856        &mut self,
20857        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20858        window: &mut Window,
20859        cx: &mut Context<Self>,
20860    ) {
20861        let workspace = self.workspace();
20862        let project = self.project.as_ref();
20863        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20864            let mut tasks = Vec::new();
20865            for (buffer_id, changes) in revert_changes {
20866                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20867                    buffer.update(cx, |buffer, cx| {
20868                        buffer.edit(
20869                            changes
20870                                .into_iter()
20871                                .map(|(range, text)| (range, text.to_string())),
20872                            None,
20873                            cx,
20874                        );
20875                    });
20876
20877                    if let Some(project) =
20878                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20879                    {
20880                        project.update(cx, |project, cx| {
20881                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20882                        })
20883                    }
20884                }
20885            }
20886            tasks
20887        });
20888        cx.spawn_in(window, async move |_, cx| {
20889            for (buffer, task) in save_tasks {
20890                let result = task.await;
20891                if result.is_err() {
20892                    let Some(path) = buffer
20893                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20894                        .ok()
20895                    else {
20896                        continue;
20897                    };
20898                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20899                        let Some(task) = cx
20900                            .update_window_entity(&workspace, |workspace, window, cx| {
20901                                workspace
20902                                    .open_path_preview(path, None, false, false, false, window, cx)
20903                            })
20904                            .ok()
20905                        else {
20906                            continue;
20907                        };
20908                        task.await.log_err();
20909                    }
20910                }
20911            }
20912        })
20913        .detach();
20914        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20915            selections.refresh()
20916        });
20917    }
20918
20919    pub fn to_pixel_point(
20920        &self,
20921        source: multi_buffer::Anchor,
20922        editor_snapshot: &EditorSnapshot,
20923        window: &mut Window,
20924    ) -> Option<gpui::Point<Pixels>> {
20925        let source_point = source.to_display_point(editor_snapshot);
20926        self.display_to_pixel_point(source_point, editor_snapshot, window)
20927    }
20928
20929    pub fn display_to_pixel_point(
20930        &self,
20931        source: DisplayPoint,
20932        editor_snapshot: &EditorSnapshot,
20933        window: &mut Window,
20934    ) -> Option<gpui::Point<Pixels>> {
20935        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20936        let text_layout_details = self.text_layout_details(window);
20937        let scroll_top = text_layout_details
20938            .scroll_anchor
20939            .scroll_position(editor_snapshot)
20940            .y;
20941
20942        if source.row().as_f32() < scroll_top.floor() {
20943            return None;
20944        }
20945        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20946        let source_y = line_height * (source.row().as_f32() - scroll_top);
20947        Some(gpui::Point::new(source_x, source_y))
20948    }
20949
20950    pub fn has_visible_completions_menu(&self) -> bool {
20951        !self.edit_prediction_preview_is_active()
20952            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20953                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20954            })
20955    }
20956
20957    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20958        if self.mode.is_minimap() {
20959            return;
20960        }
20961        self.addons
20962            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20963    }
20964
20965    pub fn unregister_addon<T: Addon>(&mut self) {
20966        self.addons.remove(&std::any::TypeId::of::<T>());
20967    }
20968
20969    pub fn addon<T: Addon>(&self) -> Option<&T> {
20970        let type_id = std::any::TypeId::of::<T>();
20971        self.addons
20972            .get(&type_id)
20973            .and_then(|item| item.to_any().downcast_ref::<T>())
20974    }
20975
20976    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20977        let type_id = std::any::TypeId::of::<T>();
20978        self.addons
20979            .get_mut(&type_id)
20980            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20981    }
20982
20983    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20984        let text_layout_details = self.text_layout_details(window);
20985        let style = &text_layout_details.editor_style;
20986        let font_id = window.text_system().resolve_font(&style.text.font());
20987        let font_size = style.text.font_size.to_pixels(window.rem_size());
20988        let line_height = style.text.line_height_in_pixels(window.rem_size());
20989        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20990        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20991
20992        CharacterDimensions {
20993            em_width,
20994            em_advance,
20995            line_height,
20996        }
20997    }
20998
20999    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21000        self.load_diff_task.clone()
21001    }
21002
21003    fn read_metadata_from_db(
21004        &mut self,
21005        item_id: u64,
21006        workspace_id: WorkspaceId,
21007        window: &mut Window,
21008        cx: &mut Context<Editor>,
21009    ) {
21010        if self.is_singleton(cx)
21011            && !self.mode.is_minimap()
21012            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21013        {
21014            let buffer_snapshot = OnceCell::new();
21015
21016            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21017                if !folds.is_empty() {
21018                    let snapshot =
21019                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21020                    self.fold_ranges(
21021                        folds
21022                            .into_iter()
21023                            .map(|(start, end)| {
21024                                snapshot.clip_offset(start, Bias::Left)
21025                                    ..snapshot.clip_offset(end, Bias::Right)
21026                            })
21027                            .collect(),
21028                        false,
21029                        window,
21030                        cx,
21031                    );
21032                }
21033            }
21034
21035            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21036                if !selections.is_empty() {
21037                    let snapshot =
21038                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21039                    // skip adding the initial selection to selection history
21040                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21041                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21042                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21043                            snapshot.clip_offset(start, Bias::Left)
21044                                ..snapshot.clip_offset(end, Bias::Right)
21045                        }));
21046                    });
21047                    self.selection_history.mode = SelectionHistoryMode::Normal;
21048                }
21049            };
21050        }
21051
21052        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21053    }
21054
21055    fn update_lsp_data(
21056        &mut self,
21057        ignore_cache: bool,
21058        for_buffer: Option<BufferId>,
21059        window: &mut Window,
21060        cx: &mut Context<'_, Self>,
21061    ) {
21062        self.pull_diagnostics(for_buffer, window, cx);
21063        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21064    }
21065}
21066
21067fn vim_enabled(cx: &App) -> bool {
21068    cx.global::<SettingsStore>()
21069        .raw_user_settings()
21070        .get("vim_mode")
21071        == Some(&serde_json::Value::Bool(true))
21072}
21073
21074fn process_completion_for_edit(
21075    completion: &Completion,
21076    intent: CompletionIntent,
21077    buffer: &Entity<Buffer>,
21078    cursor_position: &text::Anchor,
21079    cx: &mut Context<Editor>,
21080) -> CompletionEdit {
21081    let buffer = buffer.read(cx);
21082    let buffer_snapshot = buffer.snapshot();
21083    let (snippet, new_text) = if completion.is_snippet() {
21084        // Workaround for typescript language server issues so that methods don't expand within
21085        // strings and functions with type expressions. The previous point is used because the query
21086        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21087        let mut snippet_source = completion.new_text.clone();
21088        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21089        previous_point.column = previous_point.column.saturating_sub(1);
21090        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21091            if scope.prefers_label_for_snippet_in_completion() {
21092                if let Some(label) = completion.label() {
21093                    if matches!(
21094                        completion.kind(),
21095                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21096                    ) {
21097                        snippet_source = label;
21098                    }
21099                }
21100            }
21101        }
21102        match Snippet::parse(&snippet_source).log_err() {
21103            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21104            None => (None, completion.new_text.clone()),
21105        }
21106    } else {
21107        (None, completion.new_text.clone())
21108    };
21109
21110    let mut range_to_replace = {
21111        let replace_range = &completion.replace_range;
21112        if let CompletionSource::Lsp {
21113            insert_range: Some(insert_range),
21114            ..
21115        } = &completion.source
21116        {
21117            debug_assert_eq!(
21118                insert_range.start, replace_range.start,
21119                "insert_range and replace_range should start at the same position"
21120            );
21121            debug_assert!(
21122                insert_range
21123                    .start
21124                    .cmp(&cursor_position, &buffer_snapshot)
21125                    .is_le(),
21126                "insert_range should start before or at cursor position"
21127            );
21128            debug_assert!(
21129                replace_range
21130                    .start
21131                    .cmp(&cursor_position, &buffer_snapshot)
21132                    .is_le(),
21133                "replace_range should start before or at cursor position"
21134            );
21135
21136            let should_replace = match intent {
21137                CompletionIntent::CompleteWithInsert => false,
21138                CompletionIntent::CompleteWithReplace => true,
21139                CompletionIntent::Complete | CompletionIntent::Compose => {
21140                    let insert_mode =
21141                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21142                            .completions
21143                            .lsp_insert_mode;
21144                    match insert_mode {
21145                        LspInsertMode::Insert => false,
21146                        LspInsertMode::Replace => true,
21147                        LspInsertMode::ReplaceSubsequence => {
21148                            let mut text_to_replace = buffer.chars_for_range(
21149                                buffer.anchor_before(replace_range.start)
21150                                    ..buffer.anchor_after(replace_range.end),
21151                            );
21152                            let mut current_needle = text_to_replace.next();
21153                            for haystack_ch in completion.label.text.chars() {
21154                                if let Some(needle_ch) = current_needle {
21155                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21156                                        current_needle = text_to_replace.next();
21157                                    }
21158                                }
21159                            }
21160                            current_needle.is_none()
21161                        }
21162                        LspInsertMode::ReplaceSuffix => {
21163                            if replace_range
21164                                .end
21165                                .cmp(&cursor_position, &buffer_snapshot)
21166                                .is_gt()
21167                            {
21168                                let range_after_cursor = *cursor_position..replace_range.end;
21169                                let text_after_cursor = buffer
21170                                    .text_for_range(
21171                                        buffer.anchor_before(range_after_cursor.start)
21172                                            ..buffer.anchor_after(range_after_cursor.end),
21173                                    )
21174                                    .collect::<String>()
21175                                    .to_ascii_lowercase();
21176                                completion
21177                                    .label
21178                                    .text
21179                                    .to_ascii_lowercase()
21180                                    .ends_with(&text_after_cursor)
21181                            } else {
21182                                true
21183                            }
21184                        }
21185                    }
21186                }
21187            };
21188
21189            if should_replace {
21190                replace_range.clone()
21191            } else {
21192                insert_range.clone()
21193            }
21194        } else {
21195            replace_range.clone()
21196        }
21197    };
21198
21199    if range_to_replace
21200        .end
21201        .cmp(&cursor_position, &buffer_snapshot)
21202        .is_lt()
21203    {
21204        range_to_replace.end = *cursor_position;
21205    }
21206
21207    CompletionEdit {
21208        new_text,
21209        replace_range: range_to_replace.to_offset(&buffer),
21210        snippet,
21211    }
21212}
21213
21214struct CompletionEdit {
21215    new_text: String,
21216    replace_range: Range<usize>,
21217    snippet: Option<Snippet>,
21218}
21219
21220fn insert_extra_newline_brackets(
21221    buffer: &MultiBufferSnapshot,
21222    range: Range<usize>,
21223    language: &language::LanguageScope,
21224) -> bool {
21225    let leading_whitespace_len = buffer
21226        .reversed_chars_at(range.start)
21227        .take_while(|c| c.is_whitespace() && *c != '\n')
21228        .map(|c| c.len_utf8())
21229        .sum::<usize>();
21230    let trailing_whitespace_len = buffer
21231        .chars_at(range.end)
21232        .take_while(|c| c.is_whitespace() && *c != '\n')
21233        .map(|c| c.len_utf8())
21234        .sum::<usize>();
21235    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21236
21237    language.brackets().any(|(pair, enabled)| {
21238        let pair_start = pair.start.trim_end();
21239        let pair_end = pair.end.trim_start();
21240
21241        enabled
21242            && pair.newline
21243            && buffer.contains_str_at(range.end, pair_end)
21244            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21245    })
21246}
21247
21248fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21249    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21250        [(buffer, range, _)] => (*buffer, range.clone()),
21251        _ => return false,
21252    };
21253    let pair = {
21254        let mut result: Option<BracketMatch> = None;
21255
21256        for pair in buffer
21257            .all_bracket_ranges(range.clone())
21258            .filter(move |pair| {
21259                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21260            })
21261        {
21262            let len = pair.close_range.end - pair.open_range.start;
21263
21264            if let Some(existing) = &result {
21265                let existing_len = existing.close_range.end - existing.open_range.start;
21266                if len > existing_len {
21267                    continue;
21268                }
21269            }
21270
21271            result = Some(pair);
21272        }
21273
21274        result
21275    };
21276    let Some(pair) = pair else {
21277        return false;
21278    };
21279    pair.newline_only
21280        && buffer
21281            .chars_for_range(pair.open_range.end..range.start)
21282            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21283            .all(|c| c.is_whitespace() && c != '\n')
21284}
21285
21286fn update_uncommitted_diff_for_buffer(
21287    editor: Entity<Editor>,
21288    project: &Entity<Project>,
21289    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21290    buffer: Entity<MultiBuffer>,
21291    cx: &mut App,
21292) -> Task<()> {
21293    let mut tasks = Vec::new();
21294    project.update(cx, |project, cx| {
21295        for buffer in buffers {
21296            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21297                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21298            }
21299        }
21300    });
21301    cx.spawn(async move |cx| {
21302        let diffs = future::join_all(tasks).await;
21303        if editor
21304            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21305            .unwrap_or(false)
21306        {
21307            return;
21308        }
21309
21310        buffer
21311            .update(cx, |buffer, cx| {
21312                for diff in diffs.into_iter().flatten() {
21313                    buffer.add_diff(diff, cx);
21314                }
21315            })
21316            .ok();
21317    })
21318}
21319
21320fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21321    let tab_size = tab_size.get() as usize;
21322    let mut width = offset;
21323
21324    for ch in text.chars() {
21325        width += if ch == '\t' {
21326            tab_size - (width % tab_size)
21327        } else {
21328            1
21329        };
21330    }
21331
21332    width - offset
21333}
21334
21335#[cfg(test)]
21336mod tests {
21337    use super::*;
21338
21339    #[test]
21340    fn test_string_size_with_expanded_tabs() {
21341        let nz = |val| NonZeroU32::new(val).unwrap();
21342        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21343        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21344        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21345        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21346        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21347        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21348        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21349        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21350    }
21351}
21352
21353/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21354struct WordBreakingTokenizer<'a> {
21355    input: &'a str,
21356}
21357
21358impl<'a> WordBreakingTokenizer<'a> {
21359    fn new(input: &'a str) -> Self {
21360        Self { input }
21361    }
21362}
21363
21364fn is_char_ideographic(ch: char) -> bool {
21365    use unicode_script::Script::*;
21366    use unicode_script::UnicodeScript;
21367    matches!(ch.script(), Han | Tangut | Yi)
21368}
21369
21370fn is_grapheme_ideographic(text: &str) -> bool {
21371    text.chars().any(is_char_ideographic)
21372}
21373
21374fn is_grapheme_whitespace(text: &str) -> bool {
21375    text.chars().any(|x| x.is_whitespace())
21376}
21377
21378fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21379    text.chars().next().map_or(false, |ch| {
21380        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21381    })
21382}
21383
21384#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21385enum WordBreakToken<'a> {
21386    Word { token: &'a str, grapheme_len: usize },
21387    InlineWhitespace { token: &'a str, grapheme_len: usize },
21388    Newline,
21389}
21390
21391impl<'a> Iterator for WordBreakingTokenizer<'a> {
21392    /// Yields a span, the count of graphemes in the token, and whether it was
21393    /// whitespace. Note that it also breaks at word boundaries.
21394    type Item = WordBreakToken<'a>;
21395
21396    fn next(&mut self) -> Option<Self::Item> {
21397        use unicode_segmentation::UnicodeSegmentation;
21398        if self.input.is_empty() {
21399            return None;
21400        }
21401
21402        let mut iter = self.input.graphemes(true).peekable();
21403        let mut offset = 0;
21404        let mut grapheme_len = 0;
21405        if let Some(first_grapheme) = iter.next() {
21406            let is_newline = first_grapheme == "\n";
21407            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21408            offset += first_grapheme.len();
21409            grapheme_len += 1;
21410            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21411                if let Some(grapheme) = iter.peek().copied() {
21412                    if should_stay_with_preceding_ideograph(grapheme) {
21413                        offset += grapheme.len();
21414                        grapheme_len += 1;
21415                    }
21416                }
21417            } else {
21418                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21419                let mut next_word_bound = words.peek().copied();
21420                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21421                    next_word_bound = words.next();
21422                }
21423                while let Some(grapheme) = iter.peek().copied() {
21424                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21425                        break;
21426                    };
21427                    if is_grapheme_whitespace(grapheme) != is_whitespace
21428                        || (grapheme == "\n") != is_newline
21429                    {
21430                        break;
21431                    };
21432                    offset += grapheme.len();
21433                    grapheme_len += 1;
21434                    iter.next();
21435                }
21436            }
21437            let token = &self.input[..offset];
21438            self.input = &self.input[offset..];
21439            if token == "\n" {
21440                Some(WordBreakToken::Newline)
21441            } else if is_whitespace {
21442                Some(WordBreakToken::InlineWhitespace {
21443                    token,
21444                    grapheme_len,
21445                })
21446            } else {
21447                Some(WordBreakToken::Word {
21448                    token,
21449                    grapheme_len,
21450                })
21451            }
21452        } else {
21453            None
21454        }
21455    }
21456}
21457
21458#[test]
21459fn test_word_breaking_tokenizer() {
21460    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21461        ("", &[]),
21462        ("  ", &[whitespace("  ", 2)]),
21463        ("Ʒ", &[word("Ʒ", 1)]),
21464        ("Ǽ", &[word("Ǽ", 1)]),
21465        ("", &[word("", 1)]),
21466        ("⋑⋑", &[word("⋑⋑", 2)]),
21467        (
21468            "原理,进而",
21469            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21470        ),
21471        (
21472            "hello world",
21473            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21474        ),
21475        (
21476            "hello, world",
21477            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21478        ),
21479        (
21480            "  hello world",
21481            &[
21482                whitespace("  ", 2),
21483                word("hello", 5),
21484                whitespace(" ", 1),
21485                word("world", 5),
21486            ],
21487        ),
21488        (
21489            "这是什么 \n 钢笔",
21490            &[
21491                word("", 1),
21492                word("", 1),
21493                word("", 1),
21494                word("", 1),
21495                whitespace(" ", 1),
21496                newline(),
21497                whitespace(" ", 1),
21498                word("", 1),
21499                word("", 1),
21500            ],
21501        ),
21502        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21503    ];
21504
21505    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21506        WordBreakToken::Word {
21507            token,
21508            grapheme_len,
21509        }
21510    }
21511
21512    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21513        WordBreakToken::InlineWhitespace {
21514            token,
21515            grapheme_len,
21516        }
21517    }
21518
21519    fn newline() -> WordBreakToken<'static> {
21520        WordBreakToken::Newline
21521    }
21522
21523    for (input, result) in tests {
21524        assert_eq!(
21525            WordBreakingTokenizer::new(input)
21526                .collect::<Vec<_>>()
21527                .as_slice(),
21528            *result,
21529        );
21530    }
21531}
21532
21533fn wrap_with_prefix(
21534    first_line_prefix: String,
21535    subsequent_lines_prefix: String,
21536    unwrapped_text: String,
21537    wrap_column: usize,
21538    tab_size: NonZeroU32,
21539    preserve_existing_whitespace: bool,
21540) -> String {
21541    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21542    let subsequent_lines_prefix_len =
21543        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21544    let mut wrapped_text = String::new();
21545    let mut current_line = first_line_prefix.clone();
21546    let mut is_first_line = true;
21547
21548    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21549    let mut current_line_len = first_line_prefix_len;
21550    let mut in_whitespace = false;
21551    for token in tokenizer {
21552        let have_preceding_whitespace = in_whitespace;
21553        match token {
21554            WordBreakToken::Word {
21555                token,
21556                grapheme_len,
21557            } => {
21558                in_whitespace = false;
21559                let current_prefix_len = if is_first_line {
21560                    first_line_prefix_len
21561                } else {
21562                    subsequent_lines_prefix_len
21563                };
21564                if current_line_len + grapheme_len > wrap_column
21565                    && current_line_len != current_prefix_len
21566                {
21567                    wrapped_text.push_str(current_line.trim_end());
21568                    wrapped_text.push('\n');
21569                    is_first_line = false;
21570                    current_line = subsequent_lines_prefix.clone();
21571                    current_line_len = subsequent_lines_prefix_len;
21572                }
21573                current_line.push_str(token);
21574                current_line_len += grapheme_len;
21575            }
21576            WordBreakToken::InlineWhitespace {
21577                mut token,
21578                mut grapheme_len,
21579            } => {
21580                in_whitespace = true;
21581                if have_preceding_whitespace && !preserve_existing_whitespace {
21582                    continue;
21583                }
21584                if !preserve_existing_whitespace {
21585                    token = " ";
21586                    grapheme_len = 1;
21587                }
21588                let current_prefix_len = if is_first_line {
21589                    first_line_prefix_len
21590                } else {
21591                    subsequent_lines_prefix_len
21592                };
21593                if current_line_len + grapheme_len > wrap_column {
21594                    wrapped_text.push_str(current_line.trim_end());
21595                    wrapped_text.push('\n');
21596                    is_first_line = false;
21597                    current_line = subsequent_lines_prefix.clone();
21598                    current_line_len = subsequent_lines_prefix_len;
21599                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21600                    current_line.push_str(token);
21601                    current_line_len += grapheme_len;
21602                }
21603            }
21604            WordBreakToken::Newline => {
21605                in_whitespace = true;
21606                let current_prefix_len = if is_first_line {
21607                    first_line_prefix_len
21608                } else {
21609                    subsequent_lines_prefix_len
21610                };
21611                if preserve_existing_whitespace {
21612                    wrapped_text.push_str(current_line.trim_end());
21613                    wrapped_text.push('\n');
21614                    is_first_line = false;
21615                    current_line = subsequent_lines_prefix.clone();
21616                    current_line_len = subsequent_lines_prefix_len;
21617                } else if have_preceding_whitespace {
21618                    continue;
21619                } else if current_line_len + 1 > wrap_column
21620                    && current_line_len != current_prefix_len
21621                {
21622                    wrapped_text.push_str(current_line.trim_end());
21623                    wrapped_text.push('\n');
21624                    is_first_line = false;
21625                    current_line = subsequent_lines_prefix.clone();
21626                    current_line_len = subsequent_lines_prefix_len;
21627                } else if current_line_len != current_prefix_len {
21628                    current_line.push(' ');
21629                    current_line_len += 1;
21630                }
21631            }
21632        }
21633    }
21634
21635    if !current_line.is_empty() {
21636        wrapped_text.push_str(&current_line);
21637    }
21638    wrapped_text
21639}
21640
21641#[test]
21642fn test_wrap_with_prefix() {
21643    assert_eq!(
21644        wrap_with_prefix(
21645            "# ".to_string(),
21646            "# ".to_string(),
21647            "abcdefg".to_string(),
21648            4,
21649            NonZeroU32::new(4).unwrap(),
21650            false,
21651        ),
21652        "# abcdefg"
21653    );
21654    assert_eq!(
21655        wrap_with_prefix(
21656            "".to_string(),
21657            "".to_string(),
21658            "\thello world".to_string(),
21659            8,
21660            NonZeroU32::new(4).unwrap(),
21661            false,
21662        ),
21663        "hello\nworld"
21664    );
21665    assert_eq!(
21666        wrap_with_prefix(
21667            "// ".to_string(),
21668            "// ".to_string(),
21669            "xx \nyy zz aa bb cc".to_string(),
21670            12,
21671            NonZeroU32::new(4).unwrap(),
21672            false,
21673        ),
21674        "// xx yy zz\n// aa bb cc"
21675    );
21676    assert_eq!(
21677        wrap_with_prefix(
21678            String::new(),
21679            String::new(),
21680            "这是什么 \n 钢笔".to_string(),
21681            3,
21682            NonZeroU32::new(4).unwrap(),
21683            false,
21684        ),
21685        "这是什\n么 钢\n"
21686    );
21687}
21688
21689pub trait CollaborationHub {
21690    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21691    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21692    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21693}
21694
21695impl CollaborationHub for Entity<Project> {
21696    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21697        self.read(cx).collaborators()
21698    }
21699
21700    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21701        self.read(cx).user_store().read(cx).participant_indices()
21702    }
21703
21704    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21705        let this = self.read(cx);
21706        let user_ids = this.collaborators().values().map(|c| c.user_id);
21707        this.user_store().read(cx).participant_names(user_ids, cx)
21708    }
21709}
21710
21711pub trait SemanticsProvider {
21712    fn hover(
21713        &self,
21714        buffer: &Entity<Buffer>,
21715        position: text::Anchor,
21716        cx: &mut App,
21717    ) -> Option<Task<Vec<project::Hover>>>;
21718
21719    fn inline_values(
21720        &self,
21721        buffer_handle: Entity<Buffer>,
21722        range: Range<text::Anchor>,
21723        cx: &mut App,
21724    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21725
21726    fn inlay_hints(
21727        &self,
21728        buffer_handle: Entity<Buffer>,
21729        range: Range<text::Anchor>,
21730        cx: &mut App,
21731    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21732
21733    fn resolve_inlay_hint(
21734        &self,
21735        hint: InlayHint,
21736        buffer_handle: Entity<Buffer>,
21737        server_id: LanguageServerId,
21738        cx: &mut App,
21739    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21740
21741    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21742
21743    fn document_highlights(
21744        &self,
21745        buffer: &Entity<Buffer>,
21746        position: text::Anchor,
21747        cx: &mut App,
21748    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21749
21750    fn definitions(
21751        &self,
21752        buffer: &Entity<Buffer>,
21753        position: text::Anchor,
21754        kind: GotoDefinitionKind,
21755        cx: &mut App,
21756    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21757
21758    fn range_for_rename(
21759        &self,
21760        buffer: &Entity<Buffer>,
21761        position: text::Anchor,
21762        cx: &mut App,
21763    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21764
21765    fn perform_rename(
21766        &self,
21767        buffer: &Entity<Buffer>,
21768        position: text::Anchor,
21769        new_name: String,
21770        cx: &mut App,
21771    ) -> Option<Task<Result<ProjectTransaction>>>;
21772}
21773
21774pub trait CompletionProvider {
21775    fn completions(
21776        &self,
21777        excerpt_id: ExcerptId,
21778        buffer: &Entity<Buffer>,
21779        buffer_position: text::Anchor,
21780        trigger: CompletionContext,
21781        window: &mut Window,
21782        cx: &mut Context<Editor>,
21783    ) -> Task<Result<Vec<CompletionResponse>>>;
21784
21785    fn resolve_completions(
21786        &self,
21787        _buffer: Entity<Buffer>,
21788        _completion_indices: Vec<usize>,
21789        _completions: Rc<RefCell<Box<[Completion]>>>,
21790        _cx: &mut Context<Editor>,
21791    ) -> Task<Result<bool>> {
21792        Task::ready(Ok(false))
21793    }
21794
21795    fn apply_additional_edits_for_completion(
21796        &self,
21797        _buffer: Entity<Buffer>,
21798        _completions: Rc<RefCell<Box<[Completion]>>>,
21799        _completion_index: usize,
21800        _push_to_history: bool,
21801        _cx: &mut Context<Editor>,
21802    ) -> Task<Result<Option<language::Transaction>>> {
21803        Task::ready(Ok(None))
21804    }
21805
21806    fn is_completion_trigger(
21807        &self,
21808        buffer: &Entity<Buffer>,
21809        position: language::Anchor,
21810        text: &str,
21811        trigger_in_words: bool,
21812        menu_is_open: bool,
21813        cx: &mut Context<Editor>,
21814    ) -> bool;
21815
21816    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21817
21818    fn sort_completions(&self) -> bool {
21819        true
21820    }
21821
21822    fn filter_completions(&self) -> bool {
21823        true
21824    }
21825}
21826
21827pub trait CodeActionProvider {
21828    fn id(&self) -> Arc<str>;
21829
21830    fn code_actions(
21831        &self,
21832        buffer: &Entity<Buffer>,
21833        range: Range<text::Anchor>,
21834        window: &mut Window,
21835        cx: &mut App,
21836    ) -> Task<Result<Vec<CodeAction>>>;
21837
21838    fn apply_code_action(
21839        &self,
21840        buffer_handle: Entity<Buffer>,
21841        action: CodeAction,
21842        excerpt_id: ExcerptId,
21843        push_to_history: bool,
21844        window: &mut Window,
21845        cx: &mut App,
21846    ) -> Task<Result<ProjectTransaction>>;
21847}
21848
21849impl CodeActionProvider for Entity<Project> {
21850    fn id(&self) -> Arc<str> {
21851        "project".into()
21852    }
21853
21854    fn code_actions(
21855        &self,
21856        buffer: &Entity<Buffer>,
21857        range: Range<text::Anchor>,
21858        _window: &mut Window,
21859        cx: &mut App,
21860    ) -> Task<Result<Vec<CodeAction>>> {
21861        self.update(cx, |project, cx| {
21862            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21863            let code_actions = project.code_actions(buffer, range, None, cx);
21864            cx.background_spawn(async move {
21865                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21866                Ok(code_lens_actions
21867                    .context("code lens fetch")?
21868                    .into_iter()
21869                    .chain(code_actions.context("code action fetch")?)
21870                    .collect())
21871            })
21872        })
21873    }
21874
21875    fn apply_code_action(
21876        &self,
21877        buffer_handle: Entity<Buffer>,
21878        action: CodeAction,
21879        _excerpt_id: ExcerptId,
21880        push_to_history: bool,
21881        _window: &mut Window,
21882        cx: &mut App,
21883    ) -> Task<Result<ProjectTransaction>> {
21884        self.update(cx, |project, cx| {
21885            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21886        })
21887    }
21888}
21889
21890fn snippet_completions(
21891    project: &Project,
21892    buffer: &Entity<Buffer>,
21893    buffer_position: text::Anchor,
21894    cx: &mut App,
21895) -> Task<Result<CompletionResponse>> {
21896    let languages = buffer.read(cx).languages_at(buffer_position);
21897    let snippet_store = project.snippets().read(cx);
21898
21899    let scopes: Vec<_> = languages
21900        .iter()
21901        .filter_map(|language| {
21902            let language_name = language.lsp_id();
21903            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21904
21905            if snippets.is_empty() {
21906                None
21907            } else {
21908                Some((language.default_scope(), snippets))
21909            }
21910        })
21911        .collect();
21912
21913    if scopes.is_empty() {
21914        return Task::ready(Ok(CompletionResponse {
21915            completions: vec![],
21916            is_incomplete: false,
21917        }));
21918    }
21919
21920    let snapshot = buffer.read(cx).text_snapshot();
21921    let chars: String = snapshot
21922        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21923        .collect();
21924    let executor = cx.background_executor().clone();
21925
21926    cx.background_spawn(async move {
21927        let mut is_incomplete = false;
21928        let mut completions: Vec<Completion> = Vec::new();
21929        for (scope, snippets) in scopes.into_iter() {
21930            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21931            let mut last_word = chars
21932                .chars()
21933                .take_while(|c| classifier.is_word(*c))
21934                .collect::<String>();
21935            last_word = last_word.chars().rev().collect();
21936
21937            if last_word.is_empty() {
21938                return Ok(CompletionResponse {
21939                    completions: vec![],
21940                    is_incomplete: true,
21941                });
21942            }
21943
21944            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21945            let to_lsp = |point: &text::Anchor| {
21946                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21947                point_to_lsp(end)
21948            };
21949            let lsp_end = to_lsp(&buffer_position);
21950
21951            let candidates = snippets
21952                .iter()
21953                .enumerate()
21954                .flat_map(|(ix, snippet)| {
21955                    snippet
21956                        .prefix
21957                        .iter()
21958                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21959                })
21960                .collect::<Vec<StringMatchCandidate>>();
21961
21962            const MAX_RESULTS: usize = 100;
21963            let mut matches = fuzzy::match_strings(
21964                &candidates,
21965                &last_word,
21966                last_word.chars().any(|c| c.is_uppercase()),
21967                true,
21968                MAX_RESULTS,
21969                &Default::default(),
21970                executor.clone(),
21971            )
21972            .await;
21973
21974            if matches.len() >= MAX_RESULTS {
21975                is_incomplete = true;
21976            }
21977
21978            // Remove all candidates where the query's start does not match the start of any word in the candidate
21979            if let Some(query_start) = last_word.chars().next() {
21980                matches.retain(|string_match| {
21981                    split_words(&string_match.string).any(|word| {
21982                        // Check that the first codepoint of the word as lowercase matches the first
21983                        // codepoint of the query as lowercase
21984                        word.chars()
21985                            .flat_map(|codepoint| codepoint.to_lowercase())
21986                            .zip(query_start.to_lowercase())
21987                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21988                    })
21989                });
21990            }
21991
21992            let matched_strings = matches
21993                .into_iter()
21994                .map(|m| m.string)
21995                .collect::<HashSet<_>>();
21996
21997            completions.extend(snippets.iter().filter_map(|snippet| {
21998                let matching_prefix = snippet
21999                    .prefix
22000                    .iter()
22001                    .find(|prefix| matched_strings.contains(*prefix))?;
22002                let start = as_offset - last_word.len();
22003                let start = snapshot.anchor_before(start);
22004                let range = start..buffer_position;
22005                let lsp_start = to_lsp(&start);
22006                let lsp_range = lsp::Range {
22007                    start: lsp_start,
22008                    end: lsp_end,
22009                };
22010                Some(Completion {
22011                    replace_range: range,
22012                    new_text: snippet.body.clone(),
22013                    source: CompletionSource::Lsp {
22014                        insert_range: None,
22015                        server_id: LanguageServerId(usize::MAX),
22016                        resolved: true,
22017                        lsp_completion: Box::new(lsp::CompletionItem {
22018                            label: snippet.prefix.first().unwrap().clone(),
22019                            kind: Some(CompletionItemKind::SNIPPET),
22020                            label_details: snippet.description.as_ref().map(|description| {
22021                                lsp::CompletionItemLabelDetails {
22022                                    detail: Some(description.clone()),
22023                                    description: None,
22024                                }
22025                            }),
22026                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22027                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22028                                lsp::InsertReplaceEdit {
22029                                    new_text: snippet.body.clone(),
22030                                    insert: lsp_range,
22031                                    replace: lsp_range,
22032                                },
22033                            )),
22034                            filter_text: Some(snippet.body.clone()),
22035                            sort_text: Some(char::MAX.to_string()),
22036                            ..lsp::CompletionItem::default()
22037                        }),
22038                        lsp_defaults: None,
22039                    },
22040                    label: CodeLabel {
22041                        text: matching_prefix.clone(),
22042                        runs: Vec::new(),
22043                        filter_range: 0..matching_prefix.len(),
22044                    },
22045                    icon_path: None,
22046                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22047                        single_line: snippet.name.clone().into(),
22048                        plain_text: snippet
22049                            .description
22050                            .clone()
22051                            .map(|description| description.into()),
22052                    }),
22053                    insert_text_mode: None,
22054                    confirm: None,
22055                })
22056            }))
22057        }
22058
22059        Ok(CompletionResponse {
22060            completions,
22061            is_incomplete,
22062        })
22063    })
22064}
22065
22066impl CompletionProvider for Entity<Project> {
22067    fn completions(
22068        &self,
22069        _excerpt_id: ExcerptId,
22070        buffer: &Entity<Buffer>,
22071        buffer_position: text::Anchor,
22072        options: CompletionContext,
22073        _window: &mut Window,
22074        cx: &mut Context<Editor>,
22075    ) -> Task<Result<Vec<CompletionResponse>>> {
22076        self.update(cx, |project, cx| {
22077            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22078            let project_completions = project.completions(buffer, buffer_position, options, cx);
22079            cx.background_spawn(async move {
22080                let mut responses = project_completions.await?;
22081                let snippets = snippets.await?;
22082                if !snippets.completions.is_empty() {
22083                    responses.push(snippets);
22084                }
22085                Ok(responses)
22086            })
22087        })
22088    }
22089
22090    fn resolve_completions(
22091        &self,
22092        buffer: Entity<Buffer>,
22093        completion_indices: Vec<usize>,
22094        completions: Rc<RefCell<Box<[Completion]>>>,
22095        cx: &mut Context<Editor>,
22096    ) -> Task<Result<bool>> {
22097        self.update(cx, |project, cx| {
22098            project.lsp_store().update(cx, |lsp_store, cx| {
22099                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22100            })
22101        })
22102    }
22103
22104    fn apply_additional_edits_for_completion(
22105        &self,
22106        buffer: Entity<Buffer>,
22107        completions: Rc<RefCell<Box<[Completion]>>>,
22108        completion_index: usize,
22109        push_to_history: bool,
22110        cx: &mut Context<Editor>,
22111    ) -> Task<Result<Option<language::Transaction>>> {
22112        self.update(cx, |project, cx| {
22113            project.lsp_store().update(cx, |lsp_store, cx| {
22114                lsp_store.apply_additional_edits_for_completion(
22115                    buffer,
22116                    completions,
22117                    completion_index,
22118                    push_to_history,
22119                    cx,
22120                )
22121            })
22122        })
22123    }
22124
22125    fn is_completion_trigger(
22126        &self,
22127        buffer: &Entity<Buffer>,
22128        position: language::Anchor,
22129        text: &str,
22130        trigger_in_words: bool,
22131        menu_is_open: bool,
22132        cx: &mut Context<Editor>,
22133    ) -> bool {
22134        let mut chars = text.chars();
22135        let char = if let Some(char) = chars.next() {
22136            char
22137        } else {
22138            return false;
22139        };
22140        if chars.next().is_some() {
22141            return false;
22142        }
22143
22144        let buffer = buffer.read(cx);
22145        let snapshot = buffer.snapshot();
22146        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22147            return false;
22148        }
22149        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22150        if trigger_in_words && classifier.is_word(char) {
22151            return true;
22152        }
22153
22154        buffer.completion_triggers().contains(text)
22155    }
22156}
22157
22158impl SemanticsProvider for Entity<Project> {
22159    fn hover(
22160        &self,
22161        buffer: &Entity<Buffer>,
22162        position: text::Anchor,
22163        cx: &mut App,
22164    ) -> Option<Task<Vec<project::Hover>>> {
22165        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22166    }
22167
22168    fn document_highlights(
22169        &self,
22170        buffer: &Entity<Buffer>,
22171        position: text::Anchor,
22172        cx: &mut App,
22173    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22174        Some(self.update(cx, |project, cx| {
22175            project.document_highlights(buffer, position, cx)
22176        }))
22177    }
22178
22179    fn definitions(
22180        &self,
22181        buffer: &Entity<Buffer>,
22182        position: text::Anchor,
22183        kind: GotoDefinitionKind,
22184        cx: &mut App,
22185    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22186        Some(self.update(cx, |project, cx| match kind {
22187            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22188            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22189            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22190            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22191        }))
22192    }
22193
22194    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22195        self.update(cx, |project, cx| {
22196            if project
22197                .active_debug_session(cx)
22198                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22199            {
22200                return true;
22201            }
22202
22203            buffer.update(cx, |buffer, cx| {
22204                project.any_language_server_supports_inlay_hints(buffer, cx)
22205            })
22206        })
22207    }
22208
22209    fn inline_values(
22210        &self,
22211        buffer_handle: Entity<Buffer>,
22212        range: Range<text::Anchor>,
22213        cx: &mut App,
22214    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22215        self.update(cx, |project, cx| {
22216            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22217
22218            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22219        })
22220    }
22221
22222    fn inlay_hints(
22223        &self,
22224        buffer_handle: Entity<Buffer>,
22225        range: Range<text::Anchor>,
22226        cx: &mut App,
22227    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22228        Some(self.update(cx, |project, cx| {
22229            project.inlay_hints(buffer_handle, range, cx)
22230        }))
22231    }
22232
22233    fn resolve_inlay_hint(
22234        &self,
22235        hint: InlayHint,
22236        buffer_handle: Entity<Buffer>,
22237        server_id: LanguageServerId,
22238        cx: &mut App,
22239    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22240        Some(self.update(cx, |project, cx| {
22241            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22242        }))
22243    }
22244
22245    fn range_for_rename(
22246        &self,
22247        buffer: &Entity<Buffer>,
22248        position: text::Anchor,
22249        cx: &mut App,
22250    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22251        Some(self.update(cx, |project, cx| {
22252            let buffer = buffer.clone();
22253            let task = project.prepare_rename(buffer.clone(), position, cx);
22254            cx.spawn(async move |_, cx| {
22255                Ok(match task.await? {
22256                    PrepareRenameResponse::Success(range) => Some(range),
22257                    PrepareRenameResponse::InvalidPosition => None,
22258                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22259                        // Fallback on using TreeSitter info to determine identifier range
22260                        buffer.read_with(cx, |buffer, _| {
22261                            let snapshot = buffer.snapshot();
22262                            let (range, kind) = snapshot.surrounding_word(position, false);
22263                            if kind != Some(CharKind::Word) {
22264                                return None;
22265                            }
22266                            Some(
22267                                snapshot.anchor_before(range.start)
22268                                    ..snapshot.anchor_after(range.end),
22269                            )
22270                        })?
22271                    }
22272                })
22273            })
22274        }))
22275    }
22276
22277    fn perform_rename(
22278        &self,
22279        buffer: &Entity<Buffer>,
22280        position: text::Anchor,
22281        new_name: String,
22282        cx: &mut App,
22283    ) -> Option<Task<Result<ProjectTransaction>>> {
22284        Some(self.update(cx, |project, cx| {
22285            project.perform_rename(buffer.clone(), position, new_name, cx)
22286        }))
22287    }
22288}
22289
22290fn inlay_hint_settings(
22291    location: Anchor,
22292    snapshot: &MultiBufferSnapshot,
22293    cx: &mut Context<Editor>,
22294) -> InlayHintSettings {
22295    let file = snapshot.file_at(location);
22296    let language = snapshot.language_at(location).map(|l| l.name());
22297    language_settings(language, file, cx).inlay_hints
22298}
22299
22300fn consume_contiguous_rows(
22301    contiguous_row_selections: &mut Vec<Selection<Point>>,
22302    selection: &Selection<Point>,
22303    display_map: &DisplaySnapshot,
22304    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22305) -> (MultiBufferRow, MultiBufferRow) {
22306    contiguous_row_selections.push(selection.clone());
22307    let start_row = starting_row(selection, display_map);
22308    let mut end_row = ending_row(selection, display_map);
22309
22310    while let Some(next_selection) = selections.peek() {
22311        if next_selection.start.row <= end_row.0 {
22312            end_row = ending_row(next_selection, display_map);
22313            contiguous_row_selections.push(selections.next().unwrap().clone());
22314        } else {
22315            break;
22316        }
22317    }
22318    (start_row, end_row)
22319}
22320
22321fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22322    if selection.start.column > 0 {
22323        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22324    } else {
22325        MultiBufferRow(selection.start.row)
22326    }
22327}
22328
22329fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22330    if next_selection.end.column > 0 || next_selection.is_empty() {
22331        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22332    } else {
22333        MultiBufferRow(next_selection.end.row)
22334    }
22335}
22336
22337impl EditorSnapshot {
22338    pub fn remote_selections_in_range<'a>(
22339        &'a self,
22340        range: &'a Range<Anchor>,
22341        collaboration_hub: &dyn CollaborationHub,
22342        cx: &'a App,
22343    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22344        let participant_names = collaboration_hub.user_names(cx);
22345        let participant_indices = collaboration_hub.user_participant_indices(cx);
22346        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22347        let collaborators_by_replica_id = collaborators_by_peer_id
22348            .values()
22349            .map(|collaborator| (collaborator.replica_id, collaborator))
22350            .collect::<HashMap<_, _>>();
22351        self.buffer_snapshot
22352            .selections_in_range(range, false)
22353            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22354                if replica_id == AGENT_REPLICA_ID {
22355                    Some(RemoteSelection {
22356                        replica_id,
22357                        selection,
22358                        cursor_shape,
22359                        line_mode,
22360                        collaborator_id: CollaboratorId::Agent,
22361                        user_name: Some("Agent".into()),
22362                        color: cx.theme().players().agent(),
22363                    })
22364                } else {
22365                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22366                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22367                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22368                    Some(RemoteSelection {
22369                        replica_id,
22370                        selection,
22371                        cursor_shape,
22372                        line_mode,
22373                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22374                        user_name,
22375                        color: if let Some(index) = participant_index {
22376                            cx.theme().players().color_for_participant(index.0)
22377                        } else {
22378                            cx.theme().players().absent()
22379                        },
22380                    })
22381                }
22382            })
22383    }
22384
22385    pub fn hunks_for_ranges(
22386        &self,
22387        ranges: impl IntoIterator<Item = Range<Point>>,
22388    ) -> Vec<MultiBufferDiffHunk> {
22389        let mut hunks = Vec::new();
22390        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22391            HashMap::default();
22392        for query_range in ranges {
22393            let query_rows =
22394                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22395            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22396                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22397            ) {
22398                // Include deleted hunks that are adjacent to the query range, because
22399                // otherwise they would be missed.
22400                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22401                if hunk.status().is_deleted() {
22402                    intersects_range |= hunk.row_range.start == query_rows.end;
22403                    intersects_range |= hunk.row_range.end == query_rows.start;
22404                }
22405                if intersects_range {
22406                    if !processed_buffer_rows
22407                        .entry(hunk.buffer_id)
22408                        .or_default()
22409                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22410                    {
22411                        continue;
22412                    }
22413                    hunks.push(hunk);
22414                }
22415            }
22416        }
22417
22418        hunks
22419    }
22420
22421    fn display_diff_hunks_for_rows<'a>(
22422        &'a self,
22423        display_rows: Range<DisplayRow>,
22424        folded_buffers: &'a HashSet<BufferId>,
22425    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22426        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22427        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22428
22429        self.buffer_snapshot
22430            .diff_hunks_in_range(buffer_start..buffer_end)
22431            .filter_map(|hunk| {
22432                if folded_buffers.contains(&hunk.buffer_id) {
22433                    return None;
22434                }
22435
22436                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22437                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22438
22439                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22440                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22441
22442                let display_hunk = if hunk_display_start.column() != 0 {
22443                    DisplayDiffHunk::Folded {
22444                        display_row: hunk_display_start.row(),
22445                    }
22446                } else {
22447                    let mut end_row = hunk_display_end.row();
22448                    if hunk_display_end.column() > 0 {
22449                        end_row.0 += 1;
22450                    }
22451                    let is_created_file = hunk.is_created_file();
22452                    DisplayDiffHunk::Unfolded {
22453                        status: hunk.status(),
22454                        diff_base_byte_range: hunk.diff_base_byte_range,
22455                        display_row_range: hunk_display_start.row()..end_row,
22456                        multi_buffer_range: Anchor::range_in_buffer(
22457                            hunk.excerpt_id,
22458                            hunk.buffer_id,
22459                            hunk.buffer_range,
22460                        ),
22461                        is_created_file,
22462                    }
22463                };
22464
22465                Some(display_hunk)
22466            })
22467    }
22468
22469    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22470        self.display_snapshot.buffer_snapshot.language_at(position)
22471    }
22472
22473    pub fn is_focused(&self) -> bool {
22474        self.is_focused
22475    }
22476
22477    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22478        self.placeholder_text.as_ref()
22479    }
22480
22481    pub fn scroll_position(&self) -> gpui::Point<f32> {
22482        self.scroll_anchor.scroll_position(&self.display_snapshot)
22483    }
22484
22485    fn gutter_dimensions(
22486        &self,
22487        font_id: FontId,
22488        font_size: Pixels,
22489        max_line_number_width: Pixels,
22490        cx: &App,
22491    ) -> Option<GutterDimensions> {
22492        if !self.show_gutter {
22493            return None;
22494        }
22495
22496        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22497        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22498
22499        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22500            matches!(
22501                ProjectSettings::get_global(cx).git.git_gutter,
22502                Some(GitGutterSetting::TrackedFiles)
22503            )
22504        });
22505        let gutter_settings = EditorSettings::get_global(cx).gutter;
22506        let show_line_numbers = self
22507            .show_line_numbers
22508            .unwrap_or(gutter_settings.line_numbers);
22509        let line_gutter_width = if show_line_numbers {
22510            // Avoid flicker-like gutter resizes when the line number gains another digit by
22511            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22512            let min_width_for_number_on_gutter =
22513                ch_advance * gutter_settings.min_line_number_digits as f32;
22514            max_line_number_width.max(min_width_for_number_on_gutter)
22515        } else {
22516            0.0.into()
22517        };
22518
22519        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22520        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22521
22522        let git_blame_entries_width =
22523            self.git_blame_gutter_max_author_length
22524                .map(|max_author_length| {
22525                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22526                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22527
22528                    /// The number of characters to dedicate to gaps and margins.
22529                    const SPACING_WIDTH: usize = 4;
22530
22531                    let max_char_count = max_author_length.min(renderer.max_author_length())
22532                        + ::git::SHORT_SHA_LENGTH
22533                        + MAX_RELATIVE_TIMESTAMP.len()
22534                        + SPACING_WIDTH;
22535
22536                    ch_advance * max_char_count
22537                });
22538
22539        let is_singleton = self.buffer_snapshot.is_singleton();
22540
22541        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22542        left_padding += if !is_singleton {
22543            ch_width * 4.0
22544        } else if show_runnables || show_breakpoints {
22545            ch_width * 3.0
22546        } else if show_git_gutter && show_line_numbers {
22547            ch_width * 2.0
22548        } else if show_git_gutter || show_line_numbers {
22549            ch_width
22550        } else {
22551            px(0.)
22552        };
22553
22554        let shows_folds = is_singleton && gutter_settings.folds;
22555
22556        let right_padding = if shows_folds && show_line_numbers {
22557            ch_width * 4.0
22558        } else if shows_folds || (!is_singleton && show_line_numbers) {
22559            ch_width * 3.0
22560        } else if show_line_numbers {
22561            ch_width
22562        } else {
22563            px(0.)
22564        };
22565
22566        Some(GutterDimensions {
22567            left_padding,
22568            right_padding,
22569            width: line_gutter_width + left_padding + right_padding,
22570            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22571            git_blame_entries_width,
22572        })
22573    }
22574
22575    pub fn render_crease_toggle(
22576        &self,
22577        buffer_row: MultiBufferRow,
22578        row_contains_cursor: bool,
22579        editor: Entity<Editor>,
22580        window: &mut Window,
22581        cx: &mut App,
22582    ) -> Option<AnyElement> {
22583        let folded = self.is_line_folded(buffer_row);
22584        let mut is_foldable = false;
22585
22586        if let Some(crease) = self
22587            .crease_snapshot
22588            .query_row(buffer_row, &self.buffer_snapshot)
22589        {
22590            is_foldable = true;
22591            match crease {
22592                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22593                    if let Some(render_toggle) = render_toggle {
22594                        let toggle_callback =
22595                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22596                                if folded {
22597                                    editor.update(cx, |editor, cx| {
22598                                        editor.fold_at(buffer_row, window, cx)
22599                                    });
22600                                } else {
22601                                    editor.update(cx, |editor, cx| {
22602                                        editor.unfold_at(buffer_row, window, cx)
22603                                    });
22604                                }
22605                            });
22606                        return Some((render_toggle)(
22607                            buffer_row,
22608                            folded,
22609                            toggle_callback,
22610                            window,
22611                            cx,
22612                        ));
22613                    }
22614                }
22615            }
22616        }
22617
22618        is_foldable |= self.starts_indent(buffer_row);
22619
22620        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22621            Some(
22622                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22623                    .toggle_state(folded)
22624                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22625                        if folded {
22626                            this.unfold_at(buffer_row, window, cx);
22627                        } else {
22628                            this.fold_at(buffer_row, window, cx);
22629                        }
22630                    }))
22631                    .into_any_element(),
22632            )
22633        } else {
22634            None
22635        }
22636    }
22637
22638    pub fn render_crease_trailer(
22639        &self,
22640        buffer_row: MultiBufferRow,
22641        window: &mut Window,
22642        cx: &mut App,
22643    ) -> Option<AnyElement> {
22644        let folded = self.is_line_folded(buffer_row);
22645        if let Crease::Inline { render_trailer, .. } = self
22646            .crease_snapshot
22647            .query_row(buffer_row, &self.buffer_snapshot)?
22648        {
22649            let render_trailer = render_trailer.as_ref()?;
22650            Some(render_trailer(buffer_row, folded, window, cx))
22651        } else {
22652            None
22653        }
22654    }
22655}
22656
22657impl Deref for EditorSnapshot {
22658    type Target = DisplaySnapshot;
22659
22660    fn deref(&self) -> &Self::Target {
22661        &self.display_snapshot
22662    }
22663}
22664
22665#[derive(Clone, Debug, PartialEq, Eq)]
22666pub enum EditorEvent {
22667    InputIgnored {
22668        text: Arc<str>,
22669    },
22670    InputHandled {
22671        utf16_range_to_replace: Option<Range<isize>>,
22672        text: Arc<str>,
22673    },
22674    ExcerptsAdded {
22675        buffer: Entity<Buffer>,
22676        predecessor: ExcerptId,
22677        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22678    },
22679    ExcerptsRemoved {
22680        ids: Vec<ExcerptId>,
22681        removed_buffer_ids: Vec<BufferId>,
22682    },
22683    BufferFoldToggled {
22684        ids: Vec<ExcerptId>,
22685        folded: bool,
22686    },
22687    ExcerptsEdited {
22688        ids: Vec<ExcerptId>,
22689    },
22690    ExcerptsExpanded {
22691        ids: Vec<ExcerptId>,
22692    },
22693    BufferEdited,
22694    Edited {
22695        transaction_id: clock::Lamport,
22696    },
22697    Reparsed(BufferId),
22698    Focused,
22699    FocusedIn,
22700    Blurred,
22701    DirtyChanged,
22702    Saved,
22703    TitleChanged,
22704    DiffBaseChanged,
22705    SelectionsChanged {
22706        local: bool,
22707    },
22708    ScrollPositionChanged {
22709        local: bool,
22710        autoscroll: bool,
22711    },
22712    Closed,
22713    TransactionUndone {
22714        transaction_id: clock::Lamport,
22715    },
22716    TransactionBegun {
22717        transaction_id: clock::Lamport,
22718    },
22719    Reloaded,
22720    CursorShapeChanged,
22721    PushedToNavHistory {
22722        anchor: Anchor,
22723        is_deactivate: bool,
22724    },
22725}
22726
22727impl EventEmitter<EditorEvent> for Editor {}
22728
22729impl Focusable for Editor {
22730    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22731        self.focus_handle.clone()
22732    }
22733}
22734
22735impl Render for Editor {
22736    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22737        let settings = ThemeSettings::get_global(cx);
22738
22739        let mut text_style = match self.mode {
22740            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22741                color: cx.theme().colors().editor_foreground,
22742                font_family: settings.ui_font.family.clone(),
22743                font_features: settings.ui_font.features.clone(),
22744                font_fallbacks: settings.ui_font.fallbacks.clone(),
22745                font_size: rems(0.875).into(),
22746                font_weight: settings.ui_font.weight,
22747                line_height: relative(settings.buffer_line_height.value()),
22748                ..Default::default()
22749            },
22750            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22751                color: cx.theme().colors().editor_foreground,
22752                font_family: settings.buffer_font.family.clone(),
22753                font_features: settings.buffer_font.features.clone(),
22754                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22755                font_size: settings.buffer_font_size(cx).into(),
22756                font_weight: settings.buffer_font.weight,
22757                line_height: relative(settings.buffer_line_height.value()),
22758                ..Default::default()
22759            },
22760        };
22761        if let Some(text_style_refinement) = &self.text_style_refinement {
22762            text_style.refine(text_style_refinement)
22763        }
22764
22765        let background = match self.mode {
22766            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22767            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22768            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22769            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22770        };
22771
22772        EditorElement::new(
22773            &cx.entity(),
22774            EditorStyle {
22775                background,
22776                border: cx.theme().colors().border,
22777                local_player: cx.theme().players().local(),
22778                text: text_style,
22779                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22780                syntax: cx.theme().syntax().clone(),
22781                status: cx.theme().status().clone(),
22782                inlay_hints_style: make_inlay_hints_style(cx),
22783                edit_prediction_styles: make_suggestion_styles(cx),
22784                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22785                show_underlines: self.diagnostics_enabled(),
22786            },
22787        )
22788    }
22789}
22790
22791impl EntityInputHandler for Editor {
22792    fn text_for_range(
22793        &mut self,
22794        range_utf16: Range<usize>,
22795        adjusted_range: &mut Option<Range<usize>>,
22796        _: &mut Window,
22797        cx: &mut Context<Self>,
22798    ) -> Option<String> {
22799        let snapshot = self.buffer.read(cx).read(cx);
22800        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22801        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22802        if (start.0..end.0) != range_utf16 {
22803            adjusted_range.replace(start.0..end.0);
22804        }
22805        Some(snapshot.text_for_range(start..end).collect())
22806    }
22807
22808    fn selected_text_range(
22809        &mut self,
22810        ignore_disabled_input: bool,
22811        _: &mut Window,
22812        cx: &mut Context<Self>,
22813    ) -> Option<UTF16Selection> {
22814        // Prevent the IME menu from appearing when holding down an alphabetic key
22815        // while input is disabled.
22816        if !ignore_disabled_input && !self.input_enabled {
22817            return None;
22818        }
22819
22820        let selection = self.selections.newest::<OffsetUtf16>(cx);
22821        let range = selection.range();
22822
22823        Some(UTF16Selection {
22824            range: range.start.0..range.end.0,
22825            reversed: selection.reversed,
22826        })
22827    }
22828
22829    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22830        let snapshot = self.buffer.read(cx).read(cx);
22831        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22832        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22833    }
22834
22835    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22836        self.clear_highlights::<InputComposition>(cx);
22837        self.ime_transaction.take();
22838    }
22839
22840    fn replace_text_in_range(
22841        &mut self,
22842        range_utf16: Option<Range<usize>>,
22843        text: &str,
22844        window: &mut Window,
22845        cx: &mut Context<Self>,
22846    ) {
22847        if !self.input_enabled {
22848            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22849            return;
22850        }
22851
22852        self.transact(window, cx, |this, window, cx| {
22853            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22854                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22855                Some(this.selection_replacement_ranges(range_utf16, cx))
22856            } else {
22857                this.marked_text_ranges(cx)
22858            };
22859
22860            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22861                let newest_selection_id = this.selections.newest_anchor().id;
22862                this.selections
22863                    .all::<OffsetUtf16>(cx)
22864                    .iter()
22865                    .zip(ranges_to_replace.iter())
22866                    .find_map(|(selection, range)| {
22867                        if selection.id == newest_selection_id {
22868                            Some(
22869                                (range.start.0 as isize - selection.head().0 as isize)
22870                                    ..(range.end.0 as isize - selection.head().0 as isize),
22871                            )
22872                        } else {
22873                            None
22874                        }
22875                    })
22876            });
22877
22878            cx.emit(EditorEvent::InputHandled {
22879                utf16_range_to_replace: range_to_replace,
22880                text: text.into(),
22881            });
22882
22883            if let Some(new_selected_ranges) = new_selected_ranges {
22884                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22885                    selections.select_ranges(new_selected_ranges)
22886                });
22887                this.backspace(&Default::default(), window, cx);
22888            }
22889
22890            this.handle_input(text, window, cx);
22891        });
22892
22893        if let Some(transaction) = self.ime_transaction {
22894            self.buffer.update(cx, |buffer, cx| {
22895                buffer.group_until_transaction(transaction, cx);
22896            });
22897        }
22898
22899        self.unmark_text(window, cx);
22900    }
22901
22902    fn replace_and_mark_text_in_range(
22903        &mut self,
22904        range_utf16: Option<Range<usize>>,
22905        text: &str,
22906        new_selected_range_utf16: Option<Range<usize>>,
22907        window: &mut Window,
22908        cx: &mut Context<Self>,
22909    ) {
22910        if !self.input_enabled {
22911            return;
22912        }
22913
22914        let transaction = self.transact(window, cx, |this, window, cx| {
22915            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22916                let snapshot = this.buffer.read(cx).read(cx);
22917                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22918                    for marked_range in &mut marked_ranges {
22919                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22920                        marked_range.start.0 += relative_range_utf16.start;
22921                        marked_range.start =
22922                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22923                        marked_range.end =
22924                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22925                    }
22926                }
22927                Some(marked_ranges)
22928            } else if let Some(range_utf16) = range_utf16 {
22929                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22930                Some(this.selection_replacement_ranges(range_utf16, cx))
22931            } else {
22932                None
22933            };
22934
22935            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22936                let newest_selection_id = this.selections.newest_anchor().id;
22937                this.selections
22938                    .all::<OffsetUtf16>(cx)
22939                    .iter()
22940                    .zip(ranges_to_replace.iter())
22941                    .find_map(|(selection, range)| {
22942                        if selection.id == newest_selection_id {
22943                            Some(
22944                                (range.start.0 as isize - selection.head().0 as isize)
22945                                    ..(range.end.0 as isize - selection.head().0 as isize),
22946                            )
22947                        } else {
22948                            None
22949                        }
22950                    })
22951            });
22952
22953            cx.emit(EditorEvent::InputHandled {
22954                utf16_range_to_replace: range_to_replace,
22955                text: text.into(),
22956            });
22957
22958            if let Some(ranges) = ranges_to_replace {
22959                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22960                    s.select_ranges(ranges)
22961                });
22962            }
22963
22964            let marked_ranges = {
22965                let snapshot = this.buffer.read(cx).read(cx);
22966                this.selections
22967                    .disjoint_anchors()
22968                    .iter()
22969                    .map(|selection| {
22970                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22971                    })
22972                    .collect::<Vec<_>>()
22973            };
22974
22975            if text.is_empty() {
22976                this.unmark_text(window, cx);
22977            } else {
22978                this.highlight_text::<InputComposition>(
22979                    marked_ranges.clone(),
22980                    HighlightStyle {
22981                        underline: Some(UnderlineStyle {
22982                            thickness: px(1.),
22983                            color: None,
22984                            wavy: false,
22985                        }),
22986                        ..Default::default()
22987                    },
22988                    cx,
22989                );
22990            }
22991
22992            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22993            let use_autoclose = this.use_autoclose;
22994            let use_auto_surround = this.use_auto_surround;
22995            this.set_use_autoclose(false);
22996            this.set_use_auto_surround(false);
22997            this.handle_input(text, window, cx);
22998            this.set_use_autoclose(use_autoclose);
22999            this.set_use_auto_surround(use_auto_surround);
23000
23001            if let Some(new_selected_range) = new_selected_range_utf16 {
23002                let snapshot = this.buffer.read(cx).read(cx);
23003                let new_selected_ranges = marked_ranges
23004                    .into_iter()
23005                    .map(|marked_range| {
23006                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23007                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23008                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23009                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23010                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23011                    })
23012                    .collect::<Vec<_>>();
23013
23014                drop(snapshot);
23015                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23016                    selections.select_ranges(new_selected_ranges)
23017                });
23018            }
23019        });
23020
23021        self.ime_transaction = self.ime_transaction.or(transaction);
23022        if let Some(transaction) = self.ime_transaction {
23023            self.buffer.update(cx, |buffer, cx| {
23024                buffer.group_until_transaction(transaction, cx);
23025            });
23026        }
23027
23028        if self.text_highlights::<InputComposition>(cx).is_none() {
23029            self.ime_transaction.take();
23030        }
23031    }
23032
23033    fn bounds_for_range(
23034        &mut self,
23035        range_utf16: Range<usize>,
23036        element_bounds: gpui::Bounds<Pixels>,
23037        window: &mut Window,
23038        cx: &mut Context<Self>,
23039    ) -> Option<gpui::Bounds<Pixels>> {
23040        let text_layout_details = self.text_layout_details(window);
23041        let CharacterDimensions {
23042            em_width,
23043            em_advance,
23044            line_height,
23045        } = self.character_dimensions(window);
23046
23047        let snapshot = self.snapshot(window, cx);
23048        let scroll_position = snapshot.scroll_position();
23049        let scroll_left = scroll_position.x * em_advance;
23050
23051        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23052        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23053            + self.gutter_dimensions.full_width();
23054        let y = line_height * (start.row().as_f32() - scroll_position.y);
23055
23056        Some(Bounds {
23057            origin: element_bounds.origin + point(x, y),
23058            size: size(em_width, line_height),
23059        })
23060    }
23061
23062    fn character_index_for_point(
23063        &mut self,
23064        point: gpui::Point<Pixels>,
23065        _window: &mut Window,
23066        _cx: &mut Context<Self>,
23067    ) -> Option<usize> {
23068        let position_map = self.last_position_map.as_ref()?;
23069        if !position_map.text_hitbox.contains(&point) {
23070            return None;
23071        }
23072        let display_point = position_map.point_for_position(point).previous_valid;
23073        let anchor = position_map
23074            .snapshot
23075            .display_point_to_anchor(display_point, Bias::Left);
23076        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23077        Some(utf16_offset.0)
23078    }
23079}
23080
23081trait SelectionExt {
23082    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23083    fn spanned_rows(
23084        &self,
23085        include_end_if_at_line_start: bool,
23086        map: &DisplaySnapshot,
23087    ) -> Range<MultiBufferRow>;
23088}
23089
23090impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23091    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23092        let start = self
23093            .start
23094            .to_point(&map.buffer_snapshot)
23095            .to_display_point(map);
23096        let end = self
23097            .end
23098            .to_point(&map.buffer_snapshot)
23099            .to_display_point(map);
23100        if self.reversed {
23101            end..start
23102        } else {
23103            start..end
23104        }
23105    }
23106
23107    fn spanned_rows(
23108        &self,
23109        include_end_if_at_line_start: bool,
23110        map: &DisplaySnapshot,
23111    ) -> Range<MultiBufferRow> {
23112        let start = self.start.to_point(&map.buffer_snapshot);
23113        let mut end = self.end.to_point(&map.buffer_snapshot);
23114        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23115            end.row -= 1;
23116        }
23117
23118        let buffer_start = map.prev_line_boundary(start).0;
23119        let buffer_end = map.next_line_boundary(end).0;
23120        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23121    }
23122}
23123
23124impl<T: InvalidationRegion> InvalidationStack<T> {
23125    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23126    where
23127        S: Clone + ToOffset,
23128    {
23129        while let Some(region) = self.last() {
23130            let all_selections_inside_invalidation_ranges =
23131                if selections.len() == region.ranges().len() {
23132                    selections
23133                        .iter()
23134                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23135                        .all(|(selection, invalidation_range)| {
23136                            let head = selection.head().to_offset(buffer);
23137                            invalidation_range.start <= head && invalidation_range.end >= head
23138                        })
23139                } else {
23140                    false
23141                };
23142
23143            if all_selections_inside_invalidation_ranges {
23144                break;
23145            } else {
23146                self.pop();
23147            }
23148        }
23149    }
23150}
23151
23152impl<T> Default for InvalidationStack<T> {
23153    fn default() -> Self {
23154        Self(Default::default())
23155    }
23156}
23157
23158impl<T> Deref for InvalidationStack<T> {
23159    type Target = Vec<T>;
23160
23161    fn deref(&self) -> &Self::Target {
23162        &self.0
23163    }
23164}
23165
23166impl<T> DerefMut for InvalidationStack<T> {
23167    fn deref_mut(&mut self) -> &mut Self::Target {
23168        &mut self.0
23169    }
23170}
23171
23172impl InvalidationRegion for SnippetState {
23173    fn ranges(&self) -> &[Range<Anchor>] {
23174        &self.ranges[self.active_index]
23175    }
23176}
23177
23178fn edit_prediction_edit_text(
23179    current_snapshot: &BufferSnapshot,
23180    edits: &[(Range<Anchor>, String)],
23181    edit_preview: &EditPreview,
23182    include_deletions: bool,
23183    cx: &App,
23184) -> HighlightedText {
23185    let edits = edits
23186        .iter()
23187        .map(|(anchor, text)| {
23188            (
23189                anchor.start.text_anchor..anchor.end.text_anchor,
23190                text.clone(),
23191            )
23192        })
23193        .collect::<Vec<_>>();
23194
23195    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23196}
23197
23198pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23199    match severity {
23200        lsp::DiagnosticSeverity::ERROR => colors.error,
23201        lsp::DiagnosticSeverity::WARNING => colors.warning,
23202        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23203        lsp::DiagnosticSeverity::HINT => colors.info,
23204        _ => colors.ignored,
23205    }
23206}
23207
23208pub fn styled_runs_for_code_label<'a>(
23209    label: &'a CodeLabel,
23210    syntax_theme: &'a theme::SyntaxTheme,
23211) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23212    let fade_out = HighlightStyle {
23213        fade_out: Some(0.35),
23214        ..Default::default()
23215    };
23216
23217    let mut prev_end = label.filter_range.end;
23218    label
23219        .runs
23220        .iter()
23221        .enumerate()
23222        .flat_map(move |(ix, (range, highlight_id))| {
23223            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23224                style
23225            } else {
23226                return Default::default();
23227            };
23228            let mut muted_style = style;
23229            muted_style.highlight(fade_out);
23230
23231            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23232            if range.start >= label.filter_range.end {
23233                if range.start > prev_end {
23234                    runs.push((prev_end..range.start, fade_out));
23235                }
23236                runs.push((range.clone(), muted_style));
23237            } else if range.end <= label.filter_range.end {
23238                runs.push((range.clone(), style));
23239            } else {
23240                runs.push((range.start..label.filter_range.end, style));
23241                runs.push((label.filter_range.end..range.end, muted_style));
23242            }
23243            prev_end = cmp::max(prev_end, range.end);
23244
23245            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23246                runs.push((prev_end..label.text.len(), fade_out));
23247            }
23248
23249            runs
23250        })
23251}
23252
23253pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23254    let mut prev_index = 0;
23255    let mut prev_codepoint: Option<char> = None;
23256    text.char_indices()
23257        .chain([(text.len(), '\0')])
23258        .filter_map(move |(index, codepoint)| {
23259            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23260            let is_boundary = index == text.len()
23261                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23262                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23263            if is_boundary {
23264                let chunk = &text[prev_index..index];
23265                prev_index = index;
23266                Some(chunk)
23267            } else {
23268                None
23269            }
23270        })
23271}
23272
23273pub trait RangeToAnchorExt: Sized {
23274    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23275
23276    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23277        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23278        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23279    }
23280}
23281
23282impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23283    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23284        let start_offset = self.start.to_offset(snapshot);
23285        let end_offset = self.end.to_offset(snapshot);
23286        if start_offset == end_offset {
23287            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23288        } else {
23289            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23290        }
23291    }
23292}
23293
23294pub trait RowExt {
23295    fn as_f32(&self) -> f32;
23296
23297    fn next_row(&self) -> Self;
23298
23299    fn previous_row(&self) -> Self;
23300
23301    fn minus(&self, other: Self) -> u32;
23302}
23303
23304impl RowExt for DisplayRow {
23305    fn as_f32(&self) -> f32 {
23306        self.0 as f32
23307    }
23308
23309    fn next_row(&self) -> Self {
23310        Self(self.0 + 1)
23311    }
23312
23313    fn previous_row(&self) -> Self {
23314        Self(self.0.saturating_sub(1))
23315    }
23316
23317    fn minus(&self, other: Self) -> u32 {
23318        self.0 - other.0
23319    }
23320}
23321
23322impl RowExt for MultiBufferRow {
23323    fn as_f32(&self) -> f32 {
23324        self.0 as f32
23325    }
23326
23327    fn next_row(&self) -> Self {
23328        Self(self.0 + 1)
23329    }
23330
23331    fn previous_row(&self) -> Self {
23332        Self(self.0.saturating_sub(1))
23333    }
23334
23335    fn minus(&self, other: Self) -> u32 {
23336        self.0 - other.0
23337    }
23338}
23339
23340trait RowRangeExt {
23341    type Row;
23342
23343    fn len(&self) -> usize;
23344
23345    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23346}
23347
23348impl RowRangeExt for Range<MultiBufferRow> {
23349    type Row = MultiBufferRow;
23350
23351    fn len(&self) -> usize {
23352        (self.end.0 - self.start.0) as usize
23353    }
23354
23355    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23356        (self.start.0..self.end.0).map(MultiBufferRow)
23357    }
23358}
23359
23360impl RowRangeExt for Range<DisplayRow> {
23361    type Row = DisplayRow;
23362
23363    fn len(&self) -> usize {
23364        (self.end.0 - self.start.0) as usize
23365    }
23366
23367    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23368        (self.start.0..self.end.0).map(DisplayRow)
23369    }
23370}
23371
23372/// If select range has more than one line, we
23373/// just point the cursor to range.start.
23374fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23375    if range.start.row == range.end.row {
23376        range
23377    } else {
23378        range.start..range.start
23379    }
23380}
23381pub struct KillRing(ClipboardItem);
23382impl Global for KillRing {}
23383
23384const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23385
23386enum BreakpointPromptEditAction {
23387    Log,
23388    Condition,
23389    HitCondition,
23390}
23391
23392struct BreakpointPromptEditor {
23393    pub(crate) prompt: Entity<Editor>,
23394    editor: WeakEntity<Editor>,
23395    breakpoint_anchor: Anchor,
23396    breakpoint: Breakpoint,
23397    edit_action: BreakpointPromptEditAction,
23398    block_ids: HashSet<CustomBlockId>,
23399    editor_margins: Arc<Mutex<EditorMargins>>,
23400    _subscriptions: Vec<Subscription>,
23401}
23402
23403impl BreakpointPromptEditor {
23404    const MAX_LINES: u8 = 4;
23405
23406    fn new(
23407        editor: WeakEntity<Editor>,
23408        breakpoint_anchor: Anchor,
23409        breakpoint: Breakpoint,
23410        edit_action: BreakpointPromptEditAction,
23411        window: &mut Window,
23412        cx: &mut Context<Self>,
23413    ) -> Self {
23414        let base_text = match edit_action {
23415            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23416            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23417            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23418        }
23419        .map(|msg| msg.to_string())
23420        .unwrap_or_default();
23421
23422        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23423        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23424
23425        let prompt = cx.new(|cx| {
23426            let mut prompt = Editor::new(
23427                EditorMode::AutoHeight {
23428                    min_lines: 1,
23429                    max_lines: Some(Self::MAX_LINES as usize),
23430                },
23431                buffer,
23432                None,
23433                window,
23434                cx,
23435            );
23436            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23437            prompt.set_show_cursor_when_unfocused(false, cx);
23438            prompt.set_placeholder_text(
23439                match edit_action {
23440                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23441                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23442                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23443                },
23444                cx,
23445            );
23446
23447            prompt
23448        });
23449
23450        Self {
23451            prompt,
23452            editor,
23453            breakpoint_anchor,
23454            breakpoint,
23455            edit_action,
23456            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23457            block_ids: Default::default(),
23458            _subscriptions: vec![],
23459        }
23460    }
23461
23462    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23463        self.block_ids.extend(block_ids)
23464    }
23465
23466    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23467        if let Some(editor) = self.editor.upgrade() {
23468            let message = self
23469                .prompt
23470                .read(cx)
23471                .buffer
23472                .read(cx)
23473                .as_singleton()
23474                .expect("A multi buffer in breakpoint prompt isn't possible")
23475                .read(cx)
23476                .as_rope()
23477                .to_string();
23478
23479            editor.update(cx, |editor, cx| {
23480                editor.edit_breakpoint_at_anchor(
23481                    self.breakpoint_anchor,
23482                    self.breakpoint.clone(),
23483                    match self.edit_action {
23484                        BreakpointPromptEditAction::Log => {
23485                            BreakpointEditAction::EditLogMessage(message.into())
23486                        }
23487                        BreakpointPromptEditAction::Condition => {
23488                            BreakpointEditAction::EditCondition(message.into())
23489                        }
23490                        BreakpointPromptEditAction::HitCondition => {
23491                            BreakpointEditAction::EditHitCondition(message.into())
23492                        }
23493                    },
23494                    cx,
23495                );
23496
23497                editor.remove_blocks(self.block_ids.clone(), None, cx);
23498                cx.focus_self(window);
23499            });
23500        }
23501    }
23502
23503    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23504        self.editor
23505            .update(cx, |editor, cx| {
23506                editor.remove_blocks(self.block_ids.clone(), None, cx);
23507                window.focus(&editor.focus_handle);
23508            })
23509            .log_err();
23510    }
23511
23512    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23513        let settings = ThemeSettings::get_global(cx);
23514        let text_style = TextStyle {
23515            color: if self.prompt.read(cx).read_only(cx) {
23516                cx.theme().colors().text_disabled
23517            } else {
23518                cx.theme().colors().text
23519            },
23520            font_family: settings.buffer_font.family.clone(),
23521            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23522            font_size: settings.buffer_font_size(cx).into(),
23523            font_weight: settings.buffer_font.weight,
23524            line_height: relative(settings.buffer_line_height.value()),
23525            ..Default::default()
23526        };
23527        EditorElement::new(
23528            &self.prompt,
23529            EditorStyle {
23530                background: cx.theme().colors().editor_background,
23531                local_player: cx.theme().players().local(),
23532                text: text_style,
23533                ..Default::default()
23534            },
23535        )
23536    }
23537}
23538
23539impl Render for BreakpointPromptEditor {
23540    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23541        let editor_margins = *self.editor_margins.lock();
23542        let gutter_dimensions = editor_margins.gutter;
23543        h_flex()
23544            .key_context("Editor")
23545            .bg(cx.theme().colors().editor_background)
23546            .border_y_1()
23547            .border_color(cx.theme().status().info_border)
23548            .size_full()
23549            .py(window.line_height() / 2.5)
23550            .on_action(cx.listener(Self::confirm))
23551            .on_action(cx.listener(Self::cancel))
23552            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23553            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23554    }
23555}
23556
23557impl Focusable for BreakpointPromptEditor {
23558    fn focus_handle(&self, cx: &App) -> FocusHandle {
23559        self.prompt.focus_handle(cx)
23560    }
23561}
23562
23563fn all_edits_insertions_or_deletions(
23564    edits: &Vec<(Range<Anchor>, String)>,
23565    snapshot: &MultiBufferSnapshot,
23566) -> bool {
23567    let mut all_insertions = true;
23568    let mut all_deletions = true;
23569
23570    for (range, new_text) in edits.iter() {
23571        let range_is_empty = range.to_offset(&snapshot).is_empty();
23572        let text_is_empty = new_text.is_empty();
23573
23574        if range_is_empty != text_is_empty {
23575            if range_is_empty {
23576                all_deletions = false;
23577            } else {
23578                all_insertions = false;
23579            }
23580        } else {
23581            return false;
23582        }
23583
23584        if !all_insertions && !all_deletions {
23585            return false;
23586        }
23587    }
23588    all_insertions || all_deletions
23589}
23590
23591struct MissingEditPredictionKeybindingTooltip;
23592
23593impl Render for MissingEditPredictionKeybindingTooltip {
23594    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23595        ui::tooltip_container(window, cx, |container, _, cx| {
23596            container
23597                .flex_shrink_0()
23598                .max_w_80()
23599                .min_h(rems_from_px(124.))
23600                .justify_between()
23601                .child(
23602                    v_flex()
23603                        .flex_1()
23604                        .text_ui_sm(cx)
23605                        .child(Label::new("Conflict with Accept Keybinding"))
23606                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23607                )
23608                .child(
23609                    h_flex()
23610                        .pb_1()
23611                        .gap_1()
23612                        .items_end()
23613                        .w_full()
23614                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23615                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23616                        }))
23617                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23618                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23619                        })),
23620                )
23621        })
23622    }
23623}
23624
23625#[derive(Debug, Clone, Copy, PartialEq)]
23626pub struct LineHighlight {
23627    pub background: Background,
23628    pub border: Option<gpui::Hsla>,
23629    pub include_gutter: bool,
23630    pub type_id: Option<TypeId>,
23631}
23632
23633struct LineManipulationResult {
23634    pub new_text: String,
23635    pub line_count_before: usize,
23636    pub line_count_after: usize,
23637}
23638
23639fn render_diff_hunk_controls(
23640    row: u32,
23641    status: &DiffHunkStatus,
23642    hunk_range: Range<Anchor>,
23643    is_created_file: bool,
23644    line_height: Pixels,
23645    editor: &Entity<Editor>,
23646    _window: &mut Window,
23647    cx: &mut App,
23648) -> AnyElement {
23649    h_flex()
23650        .h(line_height)
23651        .mr_1()
23652        .gap_1()
23653        .px_0p5()
23654        .pb_1()
23655        .border_x_1()
23656        .border_b_1()
23657        .border_color(cx.theme().colors().border_variant)
23658        .rounded_b_lg()
23659        .bg(cx.theme().colors().editor_background)
23660        .gap_1()
23661        .block_mouse_except_scroll()
23662        .shadow_md()
23663        .child(if status.has_secondary_hunk() {
23664            Button::new(("stage", row as u64), "Stage")
23665                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23666                .tooltip({
23667                    let focus_handle = editor.focus_handle(cx);
23668                    move |window, cx| {
23669                        Tooltip::for_action_in(
23670                            "Stage Hunk",
23671                            &::git::ToggleStaged,
23672                            &focus_handle,
23673                            window,
23674                            cx,
23675                        )
23676                    }
23677                })
23678                .on_click({
23679                    let editor = editor.clone();
23680                    move |_event, _window, cx| {
23681                        editor.update(cx, |editor, cx| {
23682                            editor.stage_or_unstage_diff_hunks(
23683                                true,
23684                                vec![hunk_range.start..hunk_range.start],
23685                                cx,
23686                            );
23687                        });
23688                    }
23689                })
23690        } else {
23691            Button::new(("unstage", row as u64), "Unstage")
23692                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23693                .tooltip({
23694                    let focus_handle = editor.focus_handle(cx);
23695                    move |window, cx| {
23696                        Tooltip::for_action_in(
23697                            "Unstage Hunk",
23698                            &::git::ToggleStaged,
23699                            &focus_handle,
23700                            window,
23701                            cx,
23702                        )
23703                    }
23704                })
23705                .on_click({
23706                    let editor = editor.clone();
23707                    move |_event, _window, cx| {
23708                        editor.update(cx, |editor, cx| {
23709                            editor.stage_or_unstage_diff_hunks(
23710                                false,
23711                                vec![hunk_range.start..hunk_range.start],
23712                                cx,
23713                            );
23714                        });
23715                    }
23716                })
23717        })
23718        .child(
23719            Button::new(("restore", row as u64), "Restore")
23720                .tooltip({
23721                    let focus_handle = editor.focus_handle(cx);
23722                    move |window, cx| {
23723                        Tooltip::for_action_in(
23724                            "Restore Hunk",
23725                            &::git::Restore,
23726                            &focus_handle,
23727                            window,
23728                            cx,
23729                        )
23730                    }
23731                })
23732                .on_click({
23733                    let editor = editor.clone();
23734                    move |_event, window, cx| {
23735                        editor.update(cx, |editor, cx| {
23736                            let snapshot = editor.snapshot(window, cx);
23737                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23738                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23739                        });
23740                    }
23741                })
23742                .disabled(is_created_file),
23743        )
23744        .when(
23745            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23746            |el| {
23747                el.child(
23748                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23749                        .shape(IconButtonShape::Square)
23750                        .icon_size(IconSize::Small)
23751                        // .disabled(!has_multiple_hunks)
23752                        .tooltip({
23753                            let focus_handle = editor.focus_handle(cx);
23754                            move |window, cx| {
23755                                Tooltip::for_action_in(
23756                                    "Next Hunk",
23757                                    &GoToHunk,
23758                                    &focus_handle,
23759                                    window,
23760                                    cx,
23761                                )
23762                            }
23763                        })
23764                        .on_click({
23765                            let editor = editor.clone();
23766                            move |_event, window, cx| {
23767                                editor.update(cx, |editor, cx| {
23768                                    let snapshot = editor.snapshot(window, cx);
23769                                    let position =
23770                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23771                                    editor.go_to_hunk_before_or_after_position(
23772                                        &snapshot,
23773                                        position,
23774                                        Direction::Next,
23775                                        window,
23776                                        cx,
23777                                    );
23778                                    editor.expand_selected_diff_hunks(cx);
23779                                });
23780                            }
23781                        }),
23782                )
23783                .child(
23784                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23785                        .shape(IconButtonShape::Square)
23786                        .icon_size(IconSize::Small)
23787                        // .disabled(!has_multiple_hunks)
23788                        .tooltip({
23789                            let focus_handle = editor.focus_handle(cx);
23790                            move |window, cx| {
23791                                Tooltip::for_action_in(
23792                                    "Previous Hunk",
23793                                    &GoToPreviousHunk,
23794                                    &focus_handle,
23795                                    window,
23796                                    cx,
23797                                )
23798                            }
23799                        })
23800                        .on_click({
23801                            let editor = editor.clone();
23802                            move |_event, window, cx| {
23803                                editor.update(cx, |editor, cx| {
23804                                    let snapshot = editor.snapshot(window, cx);
23805                                    let point =
23806                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23807                                    editor.go_to_hunk_before_or_after_position(
23808                                        &snapshot,
23809                                        point,
23810                                        Direction::Prev,
23811                                        window,
23812                                        cx,
23813                                    );
23814                                    editor.expand_selected_diff_hunks(cx);
23815                                });
23816                            }
23817                        }),
23818                )
23819            },
23820        )
23821        .into_any_element()
23822}