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.down.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 = e.down.button == MouseButton::Left;
 8354            window.focus(&editor.focus_handle(cx));
 8355            editor.toggle_code_actions(
 8356                &ToggleCodeActions {
 8357                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8358                    quick_launch,
 8359                },
 8360                window,
 8361                cx,
 8362            );
 8363        }))
 8364        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8365            editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8366        }))
 8367    }
 8368
 8369    pub fn context_menu_visible(&self) -> bool {
 8370        !self.edit_prediction_preview_is_active()
 8371            && self
 8372                .context_menu
 8373                .borrow()
 8374                .as_ref()
 8375                .map_or(false, |menu| menu.visible())
 8376    }
 8377
 8378    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8379        self.context_menu
 8380            .borrow()
 8381            .as_ref()
 8382            .map(|menu| menu.origin())
 8383    }
 8384
 8385    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8386        self.context_menu_options = Some(options);
 8387    }
 8388
 8389    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8390    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8391
 8392    fn render_edit_prediction_popover(
 8393        &mut self,
 8394        text_bounds: &Bounds<Pixels>,
 8395        content_origin: gpui::Point<Pixels>,
 8396        right_margin: Pixels,
 8397        editor_snapshot: &EditorSnapshot,
 8398        visible_row_range: Range<DisplayRow>,
 8399        scroll_top: f32,
 8400        scroll_bottom: f32,
 8401        line_layouts: &[LineWithInvisibles],
 8402        line_height: Pixels,
 8403        scroll_pixel_position: gpui::Point<Pixels>,
 8404        newest_selection_head: Option<DisplayPoint>,
 8405        editor_width: Pixels,
 8406        style: &EditorStyle,
 8407        window: &mut Window,
 8408        cx: &mut App,
 8409    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8410        if self.mode().is_minimap() {
 8411            return None;
 8412        }
 8413        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8414
 8415        if self.edit_prediction_visible_in_cursor_popover(true) {
 8416            return None;
 8417        }
 8418
 8419        match &active_edit_prediction.completion {
 8420            EditPrediction::Move { target, .. } => {
 8421                let target_display_point = target.to_display_point(editor_snapshot);
 8422
 8423                if self.edit_prediction_requires_modifier() {
 8424                    if !self.edit_prediction_preview_is_active() {
 8425                        return None;
 8426                    }
 8427
 8428                    self.render_edit_prediction_modifier_jump_popover(
 8429                        text_bounds,
 8430                        content_origin,
 8431                        visible_row_range,
 8432                        line_layouts,
 8433                        line_height,
 8434                        scroll_pixel_position,
 8435                        newest_selection_head,
 8436                        target_display_point,
 8437                        window,
 8438                        cx,
 8439                    )
 8440                } else {
 8441                    self.render_edit_prediction_eager_jump_popover(
 8442                        text_bounds,
 8443                        content_origin,
 8444                        editor_snapshot,
 8445                        visible_row_range,
 8446                        scroll_top,
 8447                        scroll_bottom,
 8448                        line_height,
 8449                        scroll_pixel_position,
 8450                        target_display_point,
 8451                        editor_width,
 8452                        window,
 8453                        cx,
 8454                    )
 8455                }
 8456            }
 8457            EditPrediction::Edit {
 8458                display_mode: EditDisplayMode::Inline,
 8459                ..
 8460            } => None,
 8461            EditPrediction::Edit {
 8462                display_mode: EditDisplayMode::TabAccept,
 8463                edits,
 8464                ..
 8465            } => {
 8466                let range = &edits.first()?.0;
 8467                let target_display_point = range.end.to_display_point(editor_snapshot);
 8468
 8469                self.render_edit_prediction_end_of_line_popover(
 8470                    "Accept",
 8471                    editor_snapshot,
 8472                    visible_row_range,
 8473                    target_display_point,
 8474                    line_height,
 8475                    scroll_pixel_position,
 8476                    content_origin,
 8477                    editor_width,
 8478                    window,
 8479                    cx,
 8480                )
 8481            }
 8482            EditPrediction::Edit {
 8483                edits,
 8484                edit_preview,
 8485                display_mode: EditDisplayMode::DiffPopover,
 8486                snapshot,
 8487            } => self.render_edit_prediction_diff_popover(
 8488                text_bounds,
 8489                content_origin,
 8490                right_margin,
 8491                editor_snapshot,
 8492                visible_row_range,
 8493                line_layouts,
 8494                line_height,
 8495                scroll_pixel_position,
 8496                newest_selection_head,
 8497                editor_width,
 8498                style,
 8499                edits,
 8500                edit_preview,
 8501                snapshot,
 8502                window,
 8503                cx,
 8504            ),
 8505        }
 8506    }
 8507
 8508    fn render_edit_prediction_modifier_jump_popover(
 8509        &mut self,
 8510        text_bounds: &Bounds<Pixels>,
 8511        content_origin: gpui::Point<Pixels>,
 8512        visible_row_range: Range<DisplayRow>,
 8513        line_layouts: &[LineWithInvisibles],
 8514        line_height: Pixels,
 8515        scroll_pixel_position: gpui::Point<Pixels>,
 8516        newest_selection_head: Option<DisplayPoint>,
 8517        target_display_point: DisplayPoint,
 8518        window: &mut Window,
 8519        cx: &mut App,
 8520    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8521        let scrolled_content_origin =
 8522            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8523
 8524        const SCROLL_PADDING_Y: Pixels = px(12.);
 8525
 8526        if target_display_point.row() < visible_row_range.start {
 8527            return self.render_edit_prediction_scroll_popover(
 8528                |_| SCROLL_PADDING_Y,
 8529                IconName::ArrowUp,
 8530                visible_row_range,
 8531                line_layouts,
 8532                newest_selection_head,
 8533                scrolled_content_origin,
 8534                window,
 8535                cx,
 8536            );
 8537        } else if target_display_point.row() >= visible_row_range.end {
 8538            return self.render_edit_prediction_scroll_popover(
 8539                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8540                IconName::ArrowDown,
 8541                visible_row_range,
 8542                line_layouts,
 8543                newest_selection_head,
 8544                scrolled_content_origin,
 8545                window,
 8546                cx,
 8547            );
 8548        }
 8549
 8550        const POLE_WIDTH: Pixels = px(2.);
 8551
 8552        let line_layout =
 8553            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8554        let target_column = target_display_point.column() as usize;
 8555
 8556        let target_x = line_layout.x_for_index(target_column);
 8557        let target_y =
 8558            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8559
 8560        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8561
 8562        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8563        border_color.l += 0.001;
 8564
 8565        let mut element = v_flex()
 8566            .items_end()
 8567            .when(flag_on_right, |el| el.items_start())
 8568            .child(if flag_on_right {
 8569                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8570                    .rounded_bl(px(0.))
 8571                    .rounded_tl(px(0.))
 8572                    .border_l_2()
 8573                    .border_color(border_color)
 8574            } else {
 8575                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8576                    .rounded_br(px(0.))
 8577                    .rounded_tr(px(0.))
 8578                    .border_r_2()
 8579                    .border_color(border_color)
 8580            })
 8581            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8582            .into_any();
 8583
 8584        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8585
 8586        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8587            - point(
 8588                if flag_on_right {
 8589                    POLE_WIDTH
 8590                } else {
 8591                    size.width - POLE_WIDTH
 8592                },
 8593                size.height - line_height,
 8594            );
 8595
 8596        origin.x = origin.x.max(content_origin.x);
 8597
 8598        element.prepaint_at(origin, window, cx);
 8599
 8600        Some((element, origin))
 8601    }
 8602
 8603    fn render_edit_prediction_scroll_popover(
 8604        &mut self,
 8605        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8606        scroll_icon: IconName,
 8607        visible_row_range: Range<DisplayRow>,
 8608        line_layouts: &[LineWithInvisibles],
 8609        newest_selection_head: Option<DisplayPoint>,
 8610        scrolled_content_origin: gpui::Point<Pixels>,
 8611        window: &mut Window,
 8612        cx: &mut App,
 8613    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8614        let mut element = self
 8615            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8616            .into_any();
 8617
 8618        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8619
 8620        let cursor = newest_selection_head?;
 8621        let cursor_row_layout =
 8622            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8623        let cursor_column = cursor.column() as usize;
 8624
 8625        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8626
 8627        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8628
 8629        element.prepaint_at(origin, window, cx);
 8630        Some((element, origin))
 8631    }
 8632
 8633    fn render_edit_prediction_eager_jump_popover(
 8634        &mut self,
 8635        text_bounds: &Bounds<Pixels>,
 8636        content_origin: gpui::Point<Pixels>,
 8637        editor_snapshot: &EditorSnapshot,
 8638        visible_row_range: Range<DisplayRow>,
 8639        scroll_top: f32,
 8640        scroll_bottom: f32,
 8641        line_height: Pixels,
 8642        scroll_pixel_position: gpui::Point<Pixels>,
 8643        target_display_point: DisplayPoint,
 8644        editor_width: Pixels,
 8645        window: &mut Window,
 8646        cx: &mut App,
 8647    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8648        if target_display_point.row().as_f32() < scroll_top {
 8649            let mut element = self
 8650                .render_edit_prediction_line_popover(
 8651                    "Jump to Edit",
 8652                    Some(IconName::ArrowUp),
 8653                    window,
 8654                    cx,
 8655                )?
 8656                .into_any();
 8657
 8658            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8659            let offset = point(
 8660                (text_bounds.size.width - size.width) / 2.,
 8661                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8662            );
 8663
 8664            let origin = text_bounds.origin + offset;
 8665            element.prepaint_at(origin, window, cx);
 8666            Some((element, origin))
 8667        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8668            let mut element = self
 8669                .render_edit_prediction_line_popover(
 8670                    "Jump to Edit",
 8671                    Some(IconName::ArrowDown),
 8672                    window,
 8673                    cx,
 8674                )?
 8675                .into_any();
 8676
 8677            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8678            let offset = point(
 8679                (text_bounds.size.width - size.width) / 2.,
 8680                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8681            );
 8682
 8683            let origin = text_bounds.origin + offset;
 8684            element.prepaint_at(origin, window, cx);
 8685            Some((element, origin))
 8686        } else {
 8687            self.render_edit_prediction_end_of_line_popover(
 8688                "Jump to Edit",
 8689                editor_snapshot,
 8690                visible_row_range,
 8691                target_display_point,
 8692                line_height,
 8693                scroll_pixel_position,
 8694                content_origin,
 8695                editor_width,
 8696                window,
 8697                cx,
 8698            )
 8699        }
 8700    }
 8701
 8702    fn render_edit_prediction_end_of_line_popover(
 8703        self: &mut Editor,
 8704        label: &'static str,
 8705        editor_snapshot: &EditorSnapshot,
 8706        visible_row_range: Range<DisplayRow>,
 8707        target_display_point: DisplayPoint,
 8708        line_height: Pixels,
 8709        scroll_pixel_position: gpui::Point<Pixels>,
 8710        content_origin: gpui::Point<Pixels>,
 8711        editor_width: Pixels,
 8712        window: &mut Window,
 8713        cx: &mut App,
 8714    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8715        let target_line_end = DisplayPoint::new(
 8716            target_display_point.row(),
 8717            editor_snapshot.line_len(target_display_point.row()),
 8718        );
 8719
 8720        let mut element = self
 8721            .render_edit_prediction_line_popover(label, None, window, cx)?
 8722            .into_any();
 8723
 8724        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8725
 8726        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8727
 8728        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8729        let mut origin = start_point
 8730            + line_origin
 8731            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8732        origin.x = origin.x.max(content_origin.x);
 8733
 8734        let max_x = content_origin.x + editor_width - size.width;
 8735
 8736        if origin.x > max_x {
 8737            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8738
 8739            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8740                origin.y += offset;
 8741                IconName::ArrowUp
 8742            } else {
 8743                origin.y -= offset;
 8744                IconName::ArrowDown
 8745            };
 8746
 8747            element = self
 8748                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8749                .into_any();
 8750
 8751            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8752
 8753            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8754        }
 8755
 8756        element.prepaint_at(origin, window, cx);
 8757        Some((element, origin))
 8758    }
 8759
 8760    fn render_edit_prediction_diff_popover(
 8761        self: &Editor,
 8762        text_bounds: &Bounds<Pixels>,
 8763        content_origin: gpui::Point<Pixels>,
 8764        right_margin: Pixels,
 8765        editor_snapshot: &EditorSnapshot,
 8766        visible_row_range: Range<DisplayRow>,
 8767        line_layouts: &[LineWithInvisibles],
 8768        line_height: Pixels,
 8769        scroll_pixel_position: gpui::Point<Pixels>,
 8770        newest_selection_head: Option<DisplayPoint>,
 8771        editor_width: Pixels,
 8772        style: &EditorStyle,
 8773        edits: &Vec<(Range<Anchor>, String)>,
 8774        edit_preview: &Option<language::EditPreview>,
 8775        snapshot: &language::BufferSnapshot,
 8776        window: &mut Window,
 8777        cx: &mut App,
 8778    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8779        let edit_start = edits
 8780            .first()
 8781            .unwrap()
 8782            .0
 8783            .start
 8784            .to_display_point(editor_snapshot);
 8785        let edit_end = edits
 8786            .last()
 8787            .unwrap()
 8788            .0
 8789            .end
 8790            .to_display_point(editor_snapshot);
 8791
 8792        let is_visible = visible_row_range.contains(&edit_start.row())
 8793            || visible_row_range.contains(&edit_end.row());
 8794        if !is_visible {
 8795            return None;
 8796        }
 8797
 8798        let highlighted_edits =
 8799            crate::edit_prediction_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8800
 8801        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8802        let line_count = highlighted_edits.text.lines().count();
 8803
 8804        const BORDER_WIDTH: Pixels = px(1.);
 8805
 8806        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8807        let has_keybind = keybind.is_some();
 8808
 8809        let mut element = h_flex()
 8810            .items_start()
 8811            .child(
 8812                h_flex()
 8813                    .bg(cx.theme().colors().editor_background)
 8814                    .border(BORDER_WIDTH)
 8815                    .shadow_xs()
 8816                    .border_color(cx.theme().colors().border)
 8817                    .rounded_l_lg()
 8818                    .when(line_count > 1, |el| el.rounded_br_lg())
 8819                    .pr_1()
 8820                    .child(styled_text),
 8821            )
 8822            .child(
 8823                h_flex()
 8824                    .h(line_height + BORDER_WIDTH * 2.)
 8825                    .px_1p5()
 8826                    .gap_1()
 8827                    // Workaround: For some reason, there's a gap if we don't do this
 8828                    .ml(-BORDER_WIDTH)
 8829                    .shadow(vec![gpui::BoxShadow {
 8830                        color: gpui::black().opacity(0.05),
 8831                        offset: point(px(1.), px(1.)),
 8832                        blur_radius: px(2.),
 8833                        spread_radius: px(0.),
 8834                    }])
 8835                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8836                    .border(BORDER_WIDTH)
 8837                    .border_color(cx.theme().colors().border)
 8838                    .rounded_r_lg()
 8839                    .id("edit_prediction_diff_popover_keybind")
 8840                    .when(!has_keybind, |el| {
 8841                        let status_colors = cx.theme().status();
 8842
 8843                        el.bg(status_colors.error_background)
 8844                            .border_color(status_colors.error.opacity(0.6))
 8845                            .child(Icon::new(IconName::Info).color(Color::Error))
 8846                            .cursor_default()
 8847                            .hoverable_tooltip(move |_window, cx| {
 8848                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8849                            })
 8850                    })
 8851                    .children(keybind),
 8852            )
 8853            .into_any();
 8854
 8855        let longest_row =
 8856            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8857        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8858            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8859        } else {
 8860            layout_line(
 8861                longest_row,
 8862                editor_snapshot,
 8863                style,
 8864                editor_width,
 8865                |_| false,
 8866                window,
 8867                cx,
 8868            )
 8869            .width
 8870        };
 8871
 8872        let viewport_bounds =
 8873            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8874                right: -right_margin,
 8875                ..Default::default()
 8876            });
 8877
 8878        let x_after_longest =
 8879            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8880                - scroll_pixel_position.x;
 8881
 8882        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8883
 8884        // Fully visible if it can be displayed within the window (allow overlapping other
 8885        // panes). However, this is only allowed if the popover starts within text_bounds.
 8886        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8887            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8888
 8889        let mut origin = if can_position_to_the_right {
 8890            point(
 8891                x_after_longest,
 8892                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8893                    - scroll_pixel_position.y,
 8894            )
 8895        } else {
 8896            let cursor_row = newest_selection_head.map(|head| head.row());
 8897            let above_edit = edit_start
 8898                .row()
 8899                .0
 8900                .checked_sub(line_count as u32)
 8901                .map(DisplayRow);
 8902            let below_edit = Some(edit_end.row() + 1);
 8903            let above_cursor =
 8904                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8905            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8906
 8907            // Place the edit popover adjacent to the edit if there is a location
 8908            // available that is onscreen and does not obscure the cursor. Otherwise,
 8909            // place it adjacent to the cursor.
 8910            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8911                .into_iter()
 8912                .flatten()
 8913                .find(|&start_row| {
 8914                    let end_row = start_row + line_count as u32;
 8915                    visible_row_range.contains(&start_row)
 8916                        && visible_row_range.contains(&end_row)
 8917                        && cursor_row.map_or(true, |cursor_row| {
 8918                            !((start_row..end_row).contains(&cursor_row))
 8919                        })
 8920                })?;
 8921
 8922            content_origin
 8923                + point(
 8924                    -scroll_pixel_position.x,
 8925                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8926                )
 8927        };
 8928
 8929        origin.x -= BORDER_WIDTH;
 8930
 8931        window.defer_draw(element, origin, 1);
 8932
 8933        // Do not return an element, since it will already be drawn due to defer_draw.
 8934        None
 8935    }
 8936
 8937    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8938        px(30.)
 8939    }
 8940
 8941    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8942        if self.read_only(cx) {
 8943            cx.theme().players().read_only()
 8944        } else {
 8945            self.style.as_ref().unwrap().local_player
 8946        }
 8947    }
 8948
 8949    fn render_edit_prediction_accept_keybind(
 8950        &self,
 8951        window: &mut Window,
 8952        cx: &App,
 8953    ) -> Option<AnyElement> {
 8954        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8955        let accept_keystroke = accept_binding.keystroke()?;
 8956
 8957        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8958
 8959        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8960            Color::Accent
 8961        } else {
 8962            Color::Muted
 8963        };
 8964
 8965        h_flex()
 8966            .px_0p5()
 8967            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8968            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8969            .text_size(TextSize::XSmall.rems(cx))
 8970            .child(h_flex().children(ui::render_modifiers(
 8971                &accept_keystroke.modifiers,
 8972                PlatformStyle::platform(),
 8973                Some(modifiers_color),
 8974                Some(IconSize::XSmall.rems().into()),
 8975                true,
 8976            )))
 8977            .when(is_platform_style_mac, |parent| {
 8978                parent.child(accept_keystroke.key.clone())
 8979            })
 8980            .when(!is_platform_style_mac, |parent| {
 8981                parent.child(
 8982                    Key::new(
 8983                        util::capitalize(&accept_keystroke.key),
 8984                        Some(Color::Default),
 8985                    )
 8986                    .size(Some(IconSize::XSmall.rems().into())),
 8987                )
 8988            })
 8989            .into_any()
 8990            .into()
 8991    }
 8992
 8993    fn render_edit_prediction_line_popover(
 8994        &self,
 8995        label: impl Into<SharedString>,
 8996        icon: Option<IconName>,
 8997        window: &mut Window,
 8998        cx: &App,
 8999    ) -> Option<Stateful<Div>> {
 9000        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9001
 9002        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9003        let has_keybind = keybind.is_some();
 9004
 9005        let result = h_flex()
 9006            .id("ep-line-popover")
 9007            .py_0p5()
 9008            .pl_1()
 9009            .pr(padding_right)
 9010            .gap_1()
 9011            .rounded_md()
 9012            .border_1()
 9013            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9014            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9015            .shadow_xs()
 9016            .when(!has_keybind, |el| {
 9017                let status_colors = cx.theme().status();
 9018
 9019                el.bg(status_colors.error_background)
 9020                    .border_color(status_colors.error.opacity(0.6))
 9021                    .pl_2()
 9022                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9023                    .cursor_default()
 9024                    .hoverable_tooltip(move |_window, cx| {
 9025                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9026                    })
 9027            })
 9028            .children(keybind)
 9029            .child(
 9030                Label::new(label)
 9031                    .size(LabelSize::Small)
 9032                    .when(!has_keybind, |el| {
 9033                        el.color(cx.theme().status().error.into()).strikethrough()
 9034                    }),
 9035            )
 9036            .when(!has_keybind, |el| {
 9037                el.child(
 9038                    h_flex().ml_1().child(
 9039                        Icon::new(IconName::Info)
 9040                            .size(IconSize::Small)
 9041                            .color(cx.theme().status().error.into()),
 9042                    ),
 9043                )
 9044            })
 9045            .when_some(icon, |element, icon| {
 9046                element.child(
 9047                    div()
 9048                        .mt(px(1.5))
 9049                        .child(Icon::new(icon).size(IconSize::Small)),
 9050                )
 9051            });
 9052
 9053        Some(result)
 9054    }
 9055
 9056    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9057        let accent_color = cx.theme().colors().text_accent;
 9058        let editor_bg_color = cx.theme().colors().editor_background;
 9059        editor_bg_color.blend(accent_color.opacity(0.1))
 9060    }
 9061
 9062    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9063        let accent_color = cx.theme().colors().text_accent;
 9064        let editor_bg_color = cx.theme().colors().editor_background;
 9065        editor_bg_color.blend(accent_color.opacity(0.6))
 9066    }
 9067
 9068    fn render_edit_prediction_cursor_popover(
 9069        &self,
 9070        min_width: Pixels,
 9071        max_width: Pixels,
 9072        cursor_point: Point,
 9073        style: &EditorStyle,
 9074        accept_keystroke: Option<&gpui::Keystroke>,
 9075        _window: &Window,
 9076        cx: &mut Context<Editor>,
 9077    ) -> Option<AnyElement> {
 9078        let provider = self.edit_prediction_provider.as_ref()?;
 9079
 9080        if provider.provider.needs_terms_acceptance(cx) {
 9081            return Some(
 9082                h_flex()
 9083                    .min_w(min_width)
 9084                    .flex_1()
 9085                    .px_2()
 9086                    .py_1()
 9087                    .gap_3()
 9088                    .elevation_2(cx)
 9089                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9090                    .id("accept-terms")
 9091                    .cursor_pointer()
 9092                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9093                    .on_click(cx.listener(|this, _event, window, cx| {
 9094                        cx.stop_propagation();
 9095                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9096                        window.dispatch_action(
 9097                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9098                            cx,
 9099                        );
 9100                    }))
 9101                    .child(
 9102                        h_flex()
 9103                            .flex_1()
 9104                            .gap_2()
 9105                            .child(Icon::new(IconName::ZedPredict))
 9106                            .child(Label::new("Accept Terms of Service"))
 9107                            .child(div().w_full())
 9108                            .child(
 9109                                Icon::new(IconName::ArrowUpRight)
 9110                                    .color(Color::Muted)
 9111                                    .size(IconSize::Small),
 9112                            )
 9113                            .into_any_element(),
 9114                    )
 9115                    .into_any(),
 9116            );
 9117        }
 9118
 9119        let is_refreshing = provider.provider.is_refreshing(cx);
 9120
 9121        fn pending_completion_container() -> Div {
 9122            h_flex()
 9123                .h_full()
 9124                .flex_1()
 9125                .gap_2()
 9126                .child(Icon::new(IconName::ZedPredict))
 9127        }
 9128
 9129        let completion = match &self.active_edit_prediction {
 9130            Some(prediction) => {
 9131                if !self.has_visible_completions_menu() {
 9132                    const RADIUS: Pixels = px(6.);
 9133                    const BORDER_WIDTH: Pixels = px(1.);
 9134
 9135                    return Some(
 9136                        h_flex()
 9137                            .elevation_2(cx)
 9138                            .border(BORDER_WIDTH)
 9139                            .border_color(cx.theme().colors().border)
 9140                            .when(accept_keystroke.is_none(), |el| {
 9141                                el.border_color(cx.theme().status().error)
 9142                            })
 9143                            .rounded(RADIUS)
 9144                            .rounded_tl(px(0.))
 9145                            .overflow_hidden()
 9146                            .child(div().px_1p5().child(match &prediction.completion {
 9147                                EditPrediction::Move { target, snapshot } => {
 9148                                    use text::ToPoint as _;
 9149                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9150                                    {
 9151                                        Icon::new(IconName::ZedPredictDown)
 9152                                    } else {
 9153                                        Icon::new(IconName::ZedPredictUp)
 9154                                    }
 9155                                }
 9156                                EditPrediction::Edit { .. } => Icon::new(IconName::ZedPredict),
 9157                            }))
 9158                            .child(
 9159                                h_flex()
 9160                                    .gap_1()
 9161                                    .py_1()
 9162                                    .px_2()
 9163                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9164                                    .border_l_1()
 9165                                    .border_color(cx.theme().colors().border)
 9166                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9167                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9168                                        el.child(
 9169                                            Label::new("Hold")
 9170                                                .size(LabelSize::Small)
 9171                                                .when(accept_keystroke.is_none(), |el| {
 9172                                                    el.strikethrough()
 9173                                                })
 9174                                                .line_height_style(LineHeightStyle::UiLabel),
 9175                                        )
 9176                                    })
 9177                                    .id("edit_prediction_cursor_popover_keybind")
 9178                                    .when(accept_keystroke.is_none(), |el| {
 9179                                        let status_colors = cx.theme().status();
 9180
 9181                                        el.bg(status_colors.error_background)
 9182                                            .border_color(status_colors.error.opacity(0.6))
 9183                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9184                                            .cursor_default()
 9185                                            .hoverable_tooltip(move |_window, cx| {
 9186                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9187                                                    .into()
 9188                                            })
 9189                                    })
 9190                                    .when_some(
 9191                                        accept_keystroke.as_ref(),
 9192                                        |el, accept_keystroke| {
 9193                                            el.child(h_flex().children(ui::render_modifiers(
 9194                                                &accept_keystroke.modifiers,
 9195                                                PlatformStyle::platform(),
 9196                                                Some(Color::Default),
 9197                                                Some(IconSize::XSmall.rems().into()),
 9198                                                false,
 9199                                            )))
 9200                                        },
 9201                                    ),
 9202                            )
 9203                            .into_any(),
 9204                    );
 9205                }
 9206
 9207                self.render_edit_prediction_cursor_popover_preview(
 9208                    prediction,
 9209                    cursor_point,
 9210                    style,
 9211                    cx,
 9212                )?
 9213            }
 9214
 9215            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9216                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9217                    stale_completion,
 9218                    cursor_point,
 9219                    style,
 9220                    cx,
 9221                )?,
 9222
 9223                None => {
 9224                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9225                }
 9226            },
 9227
 9228            None => pending_completion_container().child(Label::new("No Prediction")),
 9229        };
 9230
 9231        let completion = if is_refreshing {
 9232            completion
 9233                .with_animation(
 9234                    "loading-completion",
 9235                    Animation::new(Duration::from_secs(2))
 9236                        .repeat()
 9237                        .with_easing(pulsating_between(0.4, 0.8)),
 9238                    |label, delta| label.opacity(delta),
 9239                )
 9240                .into_any_element()
 9241        } else {
 9242            completion.into_any_element()
 9243        };
 9244
 9245        let has_completion = self.active_edit_prediction.is_some();
 9246
 9247        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9248        Some(
 9249            h_flex()
 9250                .min_w(min_width)
 9251                .max_w(max_width)
 9252                .flex_1()
 9253                .elevation_2(cx)
 9254                .border_color(cx.theme().colors().border)
 9255                .child(
 9256                    div()
 9257                        .flex_1()
 9258                        .py_1()
 9259                        .px_2()
 9260                        .overflow_hidden()
 9261                        .child(completion),
 9262                )
 9263                .when_some(accept_keystroke, |el, accept_keystroke| {
 9264                    if !accept_keystroke.modifiers.modified() {
 9265                        return el;
 9266                    }
 9267
 9268                    el.child(
 9269                        h_flex()
 9270                            .h_full()
 9271                            .border_l_1()
 9272                            .rounded_r_lg()
 9273                            .border_color(cx.theme().colors().border)
 9274                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9275                            .gap_1()
 9276                            .py_1()
 9277                            .px_2()
 9278                            .child(
 9279                                h_flex()
 9280                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9281                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9282                                    .child(h_flex().children(ui::render_modifiers(
 9283                                        &accept_keystroke.modifiers,
 9284                                        PlatformStyle::platform(),
 9285                                        Some(if !has_completion {
 9286                                            Color::Muted
 9287                                        } else {
 9288                                            Color::Default
 9289                                        }),
 9290                                        None,
 9291                                        false,
 9292                                    ))),
 9293                            )
 9294                            .child(Label::new("Preview").into_any_element())
 9295                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9296                    )
 9297                })
 9298                .into_any(),
 9299        )
 9300    }
 9301
 9302    fn render_edit_prediction_cursor_popover_preview(
 9303        &self,
 9304        completion: &EditPredictionState,
 9305        cursor_point: Point,
 9306        style: &EditorStyle,
 9307        cx: &mut Context<Editor>,
 9308    ) -> Option<Div> {
 9309        use text::ToPoint as _;
 9310
 9311        fn render_relative_row_jump(
 9312            prefix: impl Into<String>,
 9313            current_row: u32,
 9314            target_row: u32,
 9315        ) -> Div {
 9316            let (row_diff, arrow) = if target_row < current_row {
 9317                (current_row - target_row, IconName::ArrowUp)
 9318            } else {
 9319                (target_row - current_row, IconName::ArrowDown)
 9320            };
 9321
 9322            h_flex()
 9323                .child(
 9324                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9325                        .color(Color::Muted)
 9326                        .size(LabelSize::Small),
 9327                )
 9328                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9329        }
 9330
 9331        match &completion.completion {
 9332            EditPrediction::Move {
 9333                target, snapshot, ..
 9334            } => Some(
 9335                h_flex()
 9336                    .px_2()
 9337                    .gap_2()
 9338                    .flex_1()
 9339                    .child(
 9340                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9341                            Icon::new(IconName::ZedPredictDown)
 9342                        } else {
 9343                            Icon::new(IconName::ZedPredictUp)
 9344                        },
 9345                    )
 9346                    .child(Label::new("Jump to Edit")),
 9347            ),
 9348
 9349            EditPrediction::Edit {
 9350                edits,
 9351                edit_preview,
 9352                snapshot,
 9353                display_mode: _,
 9354            } => {
 9355                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9356
 9357                let (highlighted_edits, has_more_lines) = crate::edit_prediction_edit_text(
 9358                    &snapshot,
 9359                    &edits,
 9360                    edit_preview.as_ref()?,
 9361                    true,
 9362                    cx,
 9363                )
 9364                .first_line_preview();
 9365
 9366                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9367                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9368
 9369                let preview = h_flex()
 9370                    .gap_1()
 9371                    .min_w_16()
 9372                    .child(styled_text)
 9373                    .when(has_more_lines, |parent| parent.child(""));
 9374
 9375                let left = if first_edit_row != cursor_point.row {
 9376                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9377                        .into_any_element()
 9378                } else {
 9379                    Icon::new(IconName::ZedPredict).into_any_element()
 9380                };
 9381
 9382                Some(
 9383                    h_flex()
 9384                        .h_full()
 9385                        .flex_1()
 9386                        .gap_2()
 9387                        .pr_1()
 9388                        .overflow_x_hidden()
 9389                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9390                        .child(left)
 9391                        .child(preview),
 9392                )
 9393            }
 9394        }
 9395    }
 9396
 9397    pub fn render_context_menu(
 9398        &self,
 9399        style: &EditorStyle,
 9400        max_height_in_lines: u32,
 9401        window: &mut Window,
 9402        cx: &mut Context<Editor>,
 9403    ) -> Option<AnyElement> {
 9404        let menu = self.context_menu.borrow();
 9405        let menu = menu.as_ref()?;
 9406        if !menu.visible() {
 9407            return None;
 9408        };
 9409        Some(menu.render(style, max_height_in_lines, window, cx))
 9410    }
 9411
 9412    fn render_context_menu_aside(
 9413        &mut self,
 9414        max_size: Size<Pixels>,
 9415        window: &mut Window,
 9416        cx: &mut Context<Editor>,
 9417    ) -> Option<AnyElement> {
 9418        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9419            if menu.visible() {
 9420                menu.render_aside(max_size, window, cx)
 9421            } else {
 9422                None
 9423            }
 9424        })
 9425    }
 9426
 9427    fn hide_context_menu(
 9428        &mut self,
 9429        window: &mut Window,
 9430        cx: &mut Context<Self>,
 9431    ) -> Option<CodeContextMenu> {
 9432        cx.notify();
 9433        self.completion_tasks.clear();
 9434        let context_menu = self.context_menu.borrow_mut().take();
 9435        self.stale_edit_prediction_in_menu.take();
 9436        self.update_visible_edit_prediction(window, cx);
 9437        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9438            if let Some(completion_provider) = &self.completion_provider {
 9439                completion_provider.selection_changed(None, window, cx);
 9440            }
 9441        }
 9442        context_menu
 9443    }
 9444
 9445    fn show_snippet_choices(
 9446        &mut self,
 9447        choices: &Vec<String>,
 9448        selection: Range<Anchor>,
 9449        cx: &mut Context<Self>,
 9450    ) {
 9451        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9452            (Some(a), Some(b)) if a == b => a,
 9453            _ => {
 9454                log::error!("expected anchor range to have matching buffer IDs");
 9455                return;
 9456            }
 9457        };
 9458        let multi_buffer = self.buffer().read(cx);
 9459        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9460            return;
 9461        };
 9462
 9463        let id = post_inc(&mut self.next_completion_id);
 9464        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9465        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9466            CompletionsMenu::new_snippet_choices(
 9467                id,
 9468                true,
 9469                choices,
 9470                selection,
 9471                buffer,
 9472                snippet_sort_order,
 9473            ),
 9474        ));
 9475    }
 9476
 9477    pub fn insert_snippet(
 9478        &mut self,
 9479        insertion_ranges: &[Range<usize>],
 9480        snippet: Snippet,
 9481        window: &mut Window,
 9482        cx: &mut Context<Self>,
 9483    ) -> Result<()> {
 9484        struct Tabstop<T> {
 9485            is_end_tabstop: bool,
 9486            ranges: Vec<Range<T>>,
 9487            choices: Option<Vec<String>>,
 9488        }
 9489
 9490        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9491            let snippet_text: Arc<str> = snippet.text.clone().into();
 9492            let edits = insertion_ranges
 9493                .iter()
 9494                .cloned()
 9495                .map(|range| (range, snippet_text.clone()));
 9496            let autoindent_mode = AutoindentMode::Block {
 9497                original_indent_columns: Vec::new(),
 9498            };
 9499            buffer.edit(edits, Some(autoindent_mode), cx);
 9500
 9501            let snapshot = &*buffer.read(cx);
 9502            let snippet = &snippet;
 9503            snippet
 9504                .tabstops
 9505                .iter()
 9506                .map(|tabstop| {
 9507                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9508                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9509                    });
 9510                    let mut tabstop_ranges = tabstop
 9511                        .ranges
 9512                        .iter()
 9513                        .flat_map(|tabstop_range| {
 9514                            let mut delta = 0_isize;
 9515                            insertion_ranges.iter().map(move |insertion_range| {
 9516                                let insertion_start = insertion_range.start as isize + delta;
 9517                                delta +=
 9518                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9519
 9520                                let start = ((insertion_start + tabstop_range.start) as usize)
 9521                                    .min(snapshot.len());
 9522                                let end = ((insertion_start + tabstop_range.end) as usize)
 9523                                    .min(snapshot.len());
 9524                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9525                            })
 9526                        })
 9527                        .collect::<Vec<_>>();
 9528                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9529
 9530                    Tabstop {
 9531                        is_end_tabstop,
 9532                        ranges: tabstop_ranges,
 9533                        choices: tabstop.choices.clone(),
 9534                    }
 9535                })
 9536                .collect::<Vec<_>>()
 9537        });
 9538        if let Some(tabstop) = tabstops.first() {
 9539            self.change_selections(Default::default(), window, cx, |s| {
 9540                // Reverse order so that the first range is the newest created selection.
 9541                // Completions will use it and autoscroll will prioritize it.
 9542                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9543            });
 9544
 9545            if let Some(choices) = &tabstop.choices {
 9546                if let Some(selection) = tabstop.ranges.first() {
 9547                    self.show_snippet_choices(choices, selection.clone(), cx)
 9548                }
 9549            }
 9550
 9551            // If we're already at the last tabstop and it's at the end of the snippet,
 9552            // we're done, we don't need to keep the state around.
 9553            if !tabstop.is_end_tabstop {
 9554                let choices = tabstops
 9555                    .iter()
 9556                    .map(|tabstop| tabstop.choices.clone())
 9557                    .collect();
 9558
 9559                let ranges = tabstops
 9560                    .into_iter()
 9561                    .map(|tabstop| tabstop.ranges)
 9562                    .collect::<Vec<_>>();
 9563
 9564                self.snippet_stack.push(SnippetState {
 9565                    active_index: 0,
 9566                    ranges,
 9567                    choices,
 9568                });
 9569            }
 9570
 9571            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9572            if self.autoclose_regions.is_empty() {
 9573                let snapshot = self.buffer.read(cx).snapshot(cx);
 9574                let mut all_selections = self.selections.all::<Point>(cx);
 9575                for selection in &mut all_selections {
 9576                    let selection_head = selection.head();
 9577                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9578                        continue;
 9579                    };
 9580
 9581                    let mut bracket_pair = None;
 9582                    let max_lookup_length = scope
 9583                        .brackets()
 9584                        .map(|(pair, _)| {
 9585                            pair.start
 9586                                .as_str()
 9587                                .chars()
 9588                                .count()
 9589                                .max(pair.end.as_str().chars().count())
 9590                        })
 9591                        .max();
 9592                    if let Some(max_lookup_length) = max_lookup_length {
 9593                        let next_text = snapshot
 9594                            .chars_at(selection_head)
 9595                            .take(max_lookup_length)
 9596                            .collect::<String>();
 9597                        let prev_text = snapshot
 9598                            .reversed_chars_at(selection_head)
 9599                            .take(max_lookup_length)
 9600                            .collect::<String>();
 9601
 9602                        for (pair, enabled) in scope.brackets() {
 9603                            if enabled
 9604                                && pair.close
 9605                                && prev_text.starts_with(pair.start.as_str())
 9606                                && next_text.starts_with(pair.end.as_str())
 9607                            {
 9608                                bracket_pair = Some(pair.clone());
 9609                                break;
 9610                            }
 9611                        }
 9612                    }
 9613
 9614                    if let Some(pair) = bracket_pair {
 9615                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9616                        let autoclose_enabled =
 9617                            self.use_autoclose && snapshot_settings.use_autoclose;
 9618                        if autoclose_enabled {
 9619                            let start = snapshot.anchor_after(selection_head);
 9620                            let end = snapshot.anchor_after(selection_head);
 9621                            self.autoclose_regions.push(AutocloseRegion {
 9622                                selection_id: selection.id,
 9623                                range: start..end,
 9624                                pair,
 9625                            });
 9626                        }
 9627                    }
 9628                }
 9629            }
 9630        }
 9631        Ok(())
 9632    }
 9633
 9634    pub fn move_to_next_snippet_tabstop(
 9635        &mut self,
 9636        window: &mut Window,
 9637        cx: &mut Context<Self>,
 9638    ) -> bool {
 9639        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9640    }
 9641
 9642    pub fn move_to_prev_snippet_tabstop(
 9643        &mut self,
 9644        window: &mut Window,
 9645        cx: &mut Context<Self>,
 9646    ) -> bool {
 9647        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9648    }
 9649
 9650    pub fn move_to_snippet_tabstop(
 9651        &mut self,
 9652        bias: Bias,
 9653        window: &mut Window,
 9654        cx: &mut Context<Self>,
 9655    ) -> bool {
 9656        if let Some(mut snippet) = self.snippet_stack.pop() {
 9657            match bias {
 9658                Bias::Left => {
 9659                    if snippet.active_index > 0 {
 9660                        snippet.active_index -= 1;
 9661                    } else {
 9662                        self.snippet_stack.push(snippet);
 9663                        return false;
 9664                    }
 9665                }
 9666                Bias::Right => {
 9667                    if snippet.active_index + 1 < snippet.ranges.len() {
 9668                        snippet.active_index += 1;
 9669                    } else {
 9670                        self.snippet_stack.push(snippet);
 9671                        return false;
 9672                    }
 9673                }
 9674            }
 9675            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9676                self.change_selections(Default::default(), window, cx, |s| {
 9677                    // Reverse order so that the first range is the newest created selection.
 9678                    // Completions will use it and autoscroll will prioritize it.
 9679                    s.select_ranges(current_ranges.iter().rev().cloned())
 9680                });
 9681
 9682                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9683                    if let Some(selection) = current_ranges.first() {
 9684                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9685                    }
 9686                }
 9687
 9688                // If snippet state is not at the last tabstop, push it back on the stack
 9689                if snippet.active_index + 1 < snippet.ranges.len() {
 9690                    self.snippet_stack.push(snippet);
 9691                }
 9692                return true;
 9693            }
 9694        }
 9695
 9696        false
 9697    }
 9698
 9699    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9700        self.transact(window, cx, |this, window, cx| {
 9701            this.select_all(&SelectAll, window, cx);
 9702            this.insert("", window, cx);
 9703        });
 9704    }
 9705
 9706    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9708        self.transact(window, cx, |this, window, cx| {
 9709            this.select_autoclose_pair(window, cx);
 9710            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9711            if !this.linked_edit_ranges.is_empty() {
 9712                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9713                let snapshot = this.buffer.read(cx).snapshot(cx);
 9714
 9715                for selection in selections.iter() {
 9716                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9717                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9718                    if selection_start.buffer_id != selection_end.buffer_id {
 9719                        continue;
 9720                    }
 9721                    if let Some(ranges) =
 9722                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9723                    {
 9724                        for (buffer, entries) in ranges {
 9725                            linked_ranges.entry(buffer).or_default().extend(entries);
 9726                        }
 9727                    }
 9728                }
 9729            }
 9730
 9731            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9732            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9733            for selection in &mut selections {
 9734                if selection.is_empty() {
 9735                    let old_head = selection.head();
 9736                    let mut new_head =
 9737                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9738                            .to_point(&display_map);
 9739                    if let Some((buffer, line_buffer_range)) = display_map
 9740                        .buffer_snapshot
 9741                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9742                    {
 9743                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9744                        let indent_len = match indent_size.kind {
 9745                            IndentKind::Space => {
 9746                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9747                            }
 9748                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9749                        };
 9750                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9751                            let indent_len = indent_len.get();
 9752                            new_head = cmp::min(
 9753                                new_head,
 9754                                MultiBufferPoint::new(
 9755                                    old_head.row,
 9756                                    ((old_head.column - 1) / indent_len) * indent_len,
 9757                                ),
 9758                            );
 9759                        }
 9760                    }
 9761
 9762                    selection.set_head(new_head, SelectionGoal::None);
 9763                }
 9764            }
 9765
 9766            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9767            this.insert("", window, cx);
 9768            let empty_str: Arc<str> = Arc::from("");
 9769            for (buffer, edits) in linked_ranges {
 9770                let snapshot = buffer.read(cx).snapshot();
 9771                use text::ToPoint as TP;
 9772
 9773                let edits = edits
 9774                    .into_iter()
 9775                    .map(|range| {
 9776                        let end_point = TP::to_point(&range.end, &snapshot);
 9777                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9778
 9779                        if end_point == start_point {
 9780                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9781                                .saturating_sub(1);
 9782                            start_point =
 9783                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9784                        };
 9785
 9786                        (start_point..end_point, empty_str.clone())
 9787                    })
 9788                    .sorted_by_key(|(range, _)| range.start)
 9789                    .collect::<Vec<_>>();
 9790                buffer.update(cx, |this, cx| {
 9791                    this.edit(edits, None, cx);
 9792                })
 9793            }
 9794            this.refresh_edit_prediction(true, false, window, cx);
 9795            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9796        });
 9797    }
 9798
 9799    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9800        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9801        self.transact(window, cx, |this, window, cx| {
 9802            this.change_selections(Default::default(), window, cx, |s| {
 9803                s.move_with(|map, selection| {
 9804                    if selection.is_empty() {
 9805                        let cursor = movement::right(map, selection.head());
 9806                        selection.end = cursor;
 9807                        selection.reversed = true;
 9808                        selection.goal = SelectionGoal::None;
 9809                    }
 9810                })
 9811            });
 9812            this.insert("", window, cx);
 9813            this.refresh_edit_prediction(true, false, window, cx);
 9814        });
 9815    }
 9816
 9817    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9818        if self.mode.is_single_line() {
 9819            cx.propagate();
 9820            return;
 9821        }
 9822
 9823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9824        if self.move_to_prev_snippet_tabstop(window, cx) {
 9825            return;
 9826        }
 9827        self.outdent(&Outdent, window, cx);
 9828    }
 9829
 9830    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9831        if self.mode.is_single_line() {
 9832            cx.propagate();
 9833            return;
 9834        }
 9835
 9836        if self.move_to_next_snippet_tabstop(window, cx) {
 9837            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9838            return;
 9839        }
 9840        if self.read_only(cx) {
 9841            return;
 9842        }
 9843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9844        let mut selections = self.selections.all_adjusted(cx);
 9845        let buffer = self.buffer.read(cx);
 9846        let snapshot = buffer.snapshot(cx);
 9847        let rows_iter = selections.iter().map(|s| s.head().row);
 9848        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9849
 9850        let has_some_cursor_in_whitespace = selections
 9851            .iter()
 9852            .filter(|selection| selection.is_empty())
 9853            .any(|selection| {
 9854                let cursor = selection.head();
 9855                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9856                cursor.column < current_indent.len
 9857            });
 9858
 9859        let mut edits = Vec::new();
 9860        let mut prev_edited_row = 0;
 9861        let mut row_delta = 0;
 9862        for selection in &mut selections {
 9863            if selection.start.row != prev_edited_row {
 9864                row_delta = 0;
 9865            }
 9866            prev_edited_row = selection.end.row;
 9867
 9868            // If the selection is non-empty, then increase the indentation of the selected lines.
 9869            if !selection.is_empty() {
 9870                row_delta =
 9871                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9872                continue;
 9873            }
 9874
 9875            let cursor = selection.head();
 9876            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9877            if let Some(suggested_indent) =
 9878                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9879            {
 9880                // Don't do anything if already at suggested indent
 9881                // and there is any other cursor which is not
 9882                if has_some_cursor_in_whitespace
 9883                    && cursor.column == current_indent.len
 9884                    && current_indent.len == suggested_indent.len
 9885                {
 9886                    continue;
 9887                }
 9888
 9889                // Adjust line and move cursor to suggested indent
 9890                // if cursor is not at suggested indent
 9891                if cursor.column < suggested_indent.len
 9892                    && cursor.column <= current_indent.len
 9893                    && current_indent.len <= suggested_indent.len
 9894                {
 9895                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9896                    selection.end = selection.start;
 9897                    if row_delta == 0 {
 9898                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9899                            cursor.row,
 9900                            current_indent,
 9901                            suggested_indent,
 9902                        ));
 9903                        row_delta = suggested_indent.len - current_indent.len;
 9904                    }
 9905                    continue;
 9906                }
 9907
 9908                // If current indent is more than suggested indent
 9909                // only move cursor to current indent and skip indent
 9910                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9911                    selection.start = Point::new(cursor.row, current_indent.len);
 9912                    selection.end = selection.start;
 9913                    continue;
 9914                }
 9915            }
 9916
 9917            // Otherwise, insert a hard or soft tab.
 9918            let settings = buffer.language_settings_at(cursor, cx);
 9919            let tab_size = if settings.hard_tabs {
 9920                IndentSize::tab()
 9921            } else {
 9922                let tab_size = settings.tab_size.get();
 9923                let indent_remainder = snapshot
 9924                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9925                    .flat_map(str::chars)
 9926                    .fold(row_delta % tab_size, |counter: u32, c| {
 9927                        if c == '\t' {
 9928                            0
 9929                        } else {
 9930                            (counter + 1) % tab_size
 9931                        }
 9932                    });
 9933
 9934                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9935                IndentSize::spaces(chars_to_next_tab_stop)
 9936            };
 9937            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9938            selection.end = selection.start;
 9939            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9940            row_delta += tab_size.len;
 9941        }
 9942
 9943        self.transact(window, cx, |this, window, cx| {
 9944            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9945            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9946            this.refresh_edit_prediction(true, false, window, cx);
 9947        });
 9948    }
 9949
 9950    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9951        if self.read_only(cx) {
 9952            return;
 9953        }
 9954        if self.mode.is_single_line() {
 9955            cx.propagate();
 9956            return;
 9957        }
 9958
 9959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9960        let mut selections = self.selections.all::<Point>(cx);
 9961        let mut prev_edited_row = 0;
 9962        let mut row_delta = 0;
 9963        let mut edits = Vec::new();
 9964        let buffer = self.buffer.read(cx);
 9965        let snapshot = buffer.snapshot(cx);
 9966        for selection in &mut selections {
 9967            if selection.start.row != prev_edited_row {
 9968                row_delta = 0;
 9969            }
 9970            prev_edited_row = selection.end.row;
 9971
 9972            row_delta =
 9973                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9974        }
 9975
 9976        self.transact(window, cx, |this, window, cx| {
 9977            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9978            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9979        });
 9980    }
 9981
 9982    fn indent_selection(
 9983        buffer: &MultiBuffer,
 9984        snapshot: &MultiBufferSnapshot,
 9985        selection: &mut Selection<Point>,
 9986        edits: &mut Vec<(Range<Point>, String)>,
 9987        delta_for_start_row: u32,
 9988        cx: &App,
 9989    ) -> u32 {
 9990        let settings = buffer.language_settings_at(selection.start, cx);
 9991        let tab_size = settings.tab_size.get();
 9992        let indent_kind = if settings.hard_tabs {
 9993            IndentKind::Tab
 9994        } else {
 9995            IndentKind::Space
 9996        };
 9997        let mut start_row = selection.start.row;
 9998        let mut end_row = selection.end.row + 1;
 9999
10000        // If a selection ends at the beginning of a line, don't indent
10001        // that last line.
10002        if selection.end.column == 0 && selection.end.row > selection.start.row {
10003            end_row -= 1;
10004        }
10005
10006        // Avoid re-indenting a row that has already been indented by a
10007        // previous selection, but still update this selection's column
10008        // to reflect that indentation.
10009        if delta_for_start_row > 0 {
10010            start_row += 1;
10011            selection.start.column += delta_for_start_row;
10012            if selection.end.row == selection.start.row {
10013                selection.end.column += delta_for_start_row;
10014            }
10015        }
10016
10017        let mut delta_for_end_row = 0;
10018        let has_multiple_rows = start_row + 1 != end_row;
10019        for row in start_row..end_row {
10020            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10021            let indent_delta = match (current_indent.kind, indent_kind) {
10022                (IndentKind::Space, IndentKind::Space) => {
10023                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10024                    IndentSize::spaces(columns_to_next_tab_stop)
10025                }
10026                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10027                (_, IndentKind::Tab) => IndentSize::tab(),
10028            };
10029
10030            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10031                0
10032            } else {
10033                selection.start.column
10034            };
10035            let row_start = Point::new(row, start);
10036            edits.push((
10037                row_start..row_start,
10038                indent_delta.chars().collect::<String>(),
10039            ));
10040
10041            // Update this selection's endpoints to reflect the indentation.
10042            if row == selection.start.row {
10043                selection.start.column += indent_delta.len;
10044            }
10045            if row == selection.end.row {
10046                selection.end.column += indent_delta.len;
10047                delta_for_end_row = indent_delta.len;
10048            }
10049        }
10050
10051        if selection.start.row == selection.end.row {
10052            delta_for_start_row + delta_for_end_row
10053        } else {
10054            delta_for_end_row
10055        }
10056    }
10057
10058    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10059        if self.read_only(cx) {
10060            return;
10061        }
10062        if self.mode.is_single_line() {
10063            cx.propagate();
10064            return;
10065        }
10066
10067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10068        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10069        let selections = self.selections.all::<Point>(cx);
10070        let mut deletion_ranges = Vec::new();
10071        let mut last_outdent = None;
10072        {
10073            let buffer = self.buffer.read(cx);
10074            let snapshot = buffer.snapshot(cx);
10075            for selection in &selections {
10076                let settings = buffer.language_settings_at(selection.start, cx);
10077                let tab_size = settings.tab_size.get();
10078                let mut rows = selection.spanned_rows(false, &display_map);
10079
10080                // Avoid re-outdenting a row that has already been outdented by a
10081                // previous selection.
10082                if let Some(last_row) = last_outdent {
10083                    if last_row == rows.start {
10084                        rows.start = rows.start.next_row();
10085                    }
10086                }
10087                let has_multiple_rows = rows.len() > 1;
10088                for row in rows.iter_rows() {
10089                    let indent_size = snapshot.indent_size_for_line(row);
10090                    if indent_size.len > 0 {
10091                        let deletion_len = match indent_size.kind {
10092                            IndentKind::Space => {
10093                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10094                                if columns_to_prev_tab_stop == 0 {
10095                                    tab_size
10096                                } else {
10097                                    columns_to_prev_tab_stop
10098                                }
10099                            }
10100                            IndentKind::Tab => 1,
10101                        };
10102                        let start = if has_multiple_rows
10103                            || deletion_len > selection.start.column
10104                            || indent_size.len < selection.start.column
10105                        {
10106                            0
10107                        } else {
10108                            selection.start.column - deletion_len
10109                        };
10110                        deletion_ranges.push(
10111                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10112                        );
10113                        last_outdent = Some(row);
10114                    }
10115                }
10116            }
10117        }
10118
10119        self.transact(window, cx, |this, window, cx| {
10120            this.buffer.update(cx, |buffer, cx| {
10121                let empty_str: Arc<str> = Arc::default();
10122                buffer.edit(
10123                    deletion_ranges
10124                        .into_iter()
10125                        .map(|range| (range, empty_str.clone())),
10126                    None,
10127                    cx,
10128                );
10129            });
10130            let selections = this.selections.all::<usize>(cx);
10131            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10132        });
10133    }
10134
10135    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10136        if self.read_only(cx) {
10137            return;
10138        }
10139        if self.mode.is_single_line() {
10140            cx.propagate();
10141            return;
10142        }
10143
10144        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10145        let selections = self
10146            .selections
10147            .all::<usize>(cx)
10148            .into_iter()
10149            .map(|s| s.range());
10150
10151        self.transact(window, cx, |this, window, cx| {
10152            this.buffer.update(cx, |buffer, cx| {
10153                buffer.autoindent_ranges(selections, cx);
10154            });
10155            let selections = this.selections.all::<usize>(cx);
10156            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10157        });
10158    }
10159
10160    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10161        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10163        let selections = self.selections.all::<Point>(cx);
10164
10165        let mut new_cursors = Vec::new();
10166        let mut edit_ranges = Vec::new();
10167        let mut selections = selections.iter().peekable();
10168        while let Some(selection) = selections.next() {
10169            let mut rows = selection.spanned_rows(false, &display_map);
10170            let goal_display_column = selection.head().to_display_point(&display_map).column();
10171
10172            // Accumulate contiguous regions of rows that we want to delete.
10173            while let Some(next_selection) = selections.peek() {
10174                let next_rows = next_selection.spanned_rows(false, &display_map);
10175                if next_rows.start <= rows.end {
10176                    rows.end = next_rows.end;
10177                    selections.next().unwrap();
10178                } else {
10179                    break;
10180                }
10181            }
10182
10183            let buffer = &display_map.buffer_snapshot;
10184            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10185            let edit_end;
10186            let cursor_buffer_row;
10187            if buffer.max_point().row >= rows.end.0 {
10188                // If there's a line after the range, delete the \n from the end of the row range
10189                // and position the cursor on the next line.
10190                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10191                cursor_buffer_row = rows.end;
10192            } else {
10193                // If there isn't a line after the range, delete the \n from the line before the
10194                // start of the row range and position the cursor there.
10195                edit_start = edit_start.saturating_sub(1);
10196                edit_end = buffer.len();
10197                cursor_buffer_row = rows.start.previous_row();
10198            }
10199
10200            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10201            *cursor.column_mut() =
10202                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10203
10204            new_cursors.push((
10205                selection.id,
10206                buffer.anchor_after(cursor.to_point(&display_map)),
10207            ));
10208            edit_ranges.push(edit_start..edit_end);
10209        }
10210
10211        self.transact(window, cx, |this, window, cx| {
10212            let buffer = this.buffer.update(cx, |buffer, cx| {
10213                let empty_str: Arc<str> = Arc::default();
10214                buffer.edit(
10215                    edit_ranges
10216                        .into_iter()
10217                        .map(|range| (range, empty_str.clone())),
10218                    None,
10219                    cx,
10220                );
10221                buffer.snapshot(cx)
10222            });
10223            let new_selections = new_cursors
10224                .into_iter()
10225                .map(|(id, cursor)| {
10226                    let cursor = cursor.to_point(&buffer);
10227                    Selection {
10228                        id,
10229                        start: cursor,
10230                        end: cursor,
10231                        reversed: false,
10232                        goal: SelectionGoal::None,
10233                    }
10234                })
10235                .collect();
10236
10237            this.change_selections(Default::default(), window, cx, |s| {
10238                s.select(new_selections);
10239            });
10240        });
10241    }
10242
10243    pub fn join_lines_impl(
10244        &mut self,
10245        insert_whitespace: bool,
10246        window: &mut Window,
10247        cx: &mut Context<Self>,
10248    ) {
10249        if self.read_only(cx) {
10250            return;
10251        }
10252        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10253        for selection in self.selections.all::<Point>(cx) {
10254            let start = MultiBufferRow(selection.start.row);
10255            // Treat single line selections as if they include the next line. Otherwise this action
10256            // would do nothing for single line selections individual cursors.
10257            let end = if selection.start.row == selection.end.row {
10258                MultiBufferRow(selection.start.row + 1)
10259            } else {
10260                MultiBufferRow(selection.end.row)
10261            };
10262
10263            if let Some(last_row_range) = row_ranges.last_mut() {
10264                if start <= last_row_range.end {
10265                    last_row_range.end = end;
10266                    continue;
10267                }
10268            }
10269            row_ranges.push(start..end);
10270        }
10271
10272        let snapshot = self.buffer.read(cx).snapshot(cx);
10273        let mut cursor_positions = Vec::new();
10274        for row_range in &row_ranges {
10275            let anchor = snapshot.anchor_before(Point::new(
10276                row_range.end.previous_row().0,
10277                snapshot.line_len(row_range.end.previous_row()),
10278            ));
10279            cursor_positions.push(anchor..anchor);
10280        }
10281
10282        self.transact(window, cx, |this, window, cx| {
10283            for row_range in row_ranges.into_iter().rev() {
10284                for row in row_range.iter_rows().rev() {
10285                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10286                    let next_line_row = row.next_row();
10287                    let indent = snapshot.indent_size_for_line(next_line_row);
10288                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10289
10290                    let replace =
10291                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10292                            " "
10293                        } else {
10294                            ""
10295                        };
10296
10297                    this.buffer.update(cx, |buffer, cx| {
10298                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10299                    });
10300                }
10301            }
10302
10303            this.change_selections(Default::default(), window, cx, |s| {
10304                s.select_anchor_ranges(cursor_positions)
10305            });
10306        });
10307    }
10308
10309    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10311        self.join_lines_impl(true, window, cx);
10312    }
10313
10314    pub fn sort_lines_case_sensitive(
10315        &mut self,
10316        _: &SortLinesCaseSensitive,
10317        window: &mut Window,
10318        cx: &mut Context<Self>,
10319    ) {
10320        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10321    }
10322
10323    pub fn sort_lines_by_length(
10324        &mut self,
10325        _: &SortLinesByLength,
10326        window: &mut Window,
10327        cx: &mut Context<Self>,
10328    ) {
10329        self.manipulate_immutable_lines(window, cx, |lines| {
10330            lines.sort_by_key(|&line| line.chars().count())
10331        })
10332    }
10333
10334    pub fn sort_lines_case_insensitive(
10335        &mut self,
10336        _: &SortLinesCaseInsensitive,
10337        window: &mut Window,
10338        cx: &mut Context<Self>,
10339    ) {
10340        self.manipulate_immutable_lines(window, cx, |lines| {
10341            lines.sort_by_key(|line| line.to_lowercase())
10342        })
10343    }
10344
10345    pub fn unique_lines_case_insensitive(
10346        &mut self,
10347        _: &UniqueLinesCaseInsensitive,
10348        window: &mut Window,
10349        cx: &mut Context<Self>,
10350    ) {
10351        self.manipulate_immutable_lines(window, cx, |lines| {
10352            let mut seen = HashSet::default();
10353            lines.retain(|line| seen.insert(line.to_lowercase()));
10354        })
10355    }
10356
10357    pub fn unique_lines_case_sensitive(
10358        &mut self,
10359        _: &UniqueLinesCaseSensitive,
10360        window: &mut Window,
10361        cx: &mut Context<Self>,
10362    ) {
10363        self.manipulate_immutable_lines(window, cx, |lines| {
10364            let mut seen = HashSet::default();
10365            lines.retain(|line| seen.insert(*line));
10366        })
10367    }
10368
10369    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10370        let Some(project) = self.project.clone() else {
10371            return;
10372        };
10373        self.reload(project, window, cx)
10374            .detach_and_notify_err(window, cx);
10375    }
10376
10377    pub fn restore_file(
10378        &mut self,
10379        _: &::git::RestoreFile,
10380        window: &mut Window,
10381        cx: &mut Context<Self>,
10382    ) {
10383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10384        let mut buffer_ids = HashSet::default();
10385        let snapshot = self.buffer().read(cx).snapshot(cx);
10386        for selection in self.selections.all::<usize>(cx) {
10387            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10388        }
10389
10390        let buffer = self.buffer().read(cx);
10391        let ranges = buffer_ids
10392            .into_iter()
10393            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10394            .collect::<Vec<_>>();
10395
10396        self.restore_hunks_in_ranges(ranges, window, cx);
10397    }
10398
10399    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10400        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10401        let selections = self
10402            .selections
10403            .all(cx)
10404            .into_iter()
10405            .map(|s| s.range())
10406            .collect();
10407        self.restore_hunks_in_ranges(selections, window, cx);
10408    }
10409
10410    pub fn restore_hunks_in_ranges(
10411        &mut self,
10412        ranges: Vec<Range<Point>>,
10413        window: &mut Window,
10414        cx: &mut Context<Editor>,
10415    ) {
10416        let mut revert_changes = HashMap::default();
10417        let chunk_by = self
10418            .snapshot(window, cx)
10419            .hunks_for_ranges(ranges)
10420            .into_iter()
10421            .chunk_by(|hunk| hunk.buffer_id);
10422        for (buffer_id, hunks) in &chunk_by {
10423            let hunks = hunks.collect::<Vec<_>>();
10424            for hunk in &hunks {
10425                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10426            }
10427            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10428        }
10429        drop(chunk_by);
10430        if !revert_changes.is_empty() {
10431            self.transact(window, cx, |editor, window, cx| {
10432                editor.restore(revert_changes, window, cx);
10433            });
10434        }
10435    }
10436
10437    pub fn open_active_item_in_terminal(
10438        &mut self,
10439        _: &OpenInTerminal,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10444            let project_path = buffer.read(cx).project_path(cx)?;
10445            let project = self.project.as_ref()?.read(cx);
10446            let entry = project.entry_for_path(&project_path, cx)?;
10447            let parent = match &entry.canonical_path {
10448                Some(canonical_path) => canonical_path.to_path_buf(),
10449                None => project.absolute_path(&project_path, cx)?,
10450            }
10451            .parent()?
10452            .to_path_buf();
10453            Some(parent)
10454        }) {
10455            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10456        }
10457    }
10458
10459    fn set_breakpoint_context_menu(
10460        &mut self,
10461        display_row: DisplayRow,
10462        position: Option<Anchor>,
10463        clicked_point: gpui::Point<Pixels>,
10464        window: &mut Window,
10465        cx: &mut Context<Self>,
10466    ) {
10467        let source = self
10468            .buffer
10469            .read(cx)
10470            .snapshot(cx)
10471            .anchor_before(Point::new(display_row.0, 0u32));
10472
10473        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10474
10475        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10476            self,
10477            source,
10478            clicked_point,
10479            context_menu,
10480            window,
10481            cx,
10482        );
10483    }
10484
10485    fn add_edit_breakpoint_block(
10486        &mut self,
10487        anchor: Anchor,
10488        breakpoint: &Breakpoint,
10489        edit_action: BreakpointPromptEditAction,
10490        window: &mut Window,
10491        cx: &mut Context<Self>,
10492    ) {
10493        let weak_editor = cx.weak_entity();
10494        let bp_prompt = cx.new(|cx| {
10495            BreakpointPromptEditor::new(
10496                weak_editor,
10497                anchor,
10498                breakpoint.clone(),
10499                edit_action,
10500                window,
10501                cx,
10502            )
10503        });
10504
10505        let height = bp_prompt.update(cx, |this, cx| {
10506            this.prompt
10507                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10508        });
10509        let cloned_prompt = bp_prompt.clone();
10510        let blocks = vec![BlockProperties {
10511            style: BlockStyle::Sticky,
10512            placement: BlockPlacement::Above(anchor),
10513            height: Some(height),
10514            render: Arc::new(move |cx| {
10515                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10516                cloned_prompt.clone().into_any_element()
10517            }),
10518            priority: 0,
10519        }];
10520
10521        let focus_handle = bp_prompt.focus_handle(cx);
10522        window.focus(&focus_handle);
10523
10524        let block_ids = self.insert_blocks(blocks, None, cx);
10525        bp_prompt.update(cx, |prompt, _| {
10526            prompt.add_block_ids(block_ids);
10527        });
10528    }
10529
10530    pub(crate) fn breakpoint_at_row(
10531        &self,
10532        row: u32,
10533        window: &mut Window,
10534        cx: &mut Context<Self>,
10535    ) -> Option<(Anchor, Breakpoint)> {
10536        let snapshot = self.snapshot(window, cx);
10537        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10538
10539        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10540    }
10541
10542    pub(crate) fn breakpoint_at_anchor(
10543        &self,
10544        breakpoint_position: Anchor,
10545        snapshot: &EditorSnapshot,
10546        cx: &mut Context<Self>,
10547    ) -> Option<(Anchor, Breakpoint)> {
10548        let project = self.project.clone()?;
10549
10550        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10551            snapshot
10552                .buffer_snapshot
10553                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10554        })?;
10555
10556        let enclosing_excerpt = breakpoint_position.excerpt_id;
10557        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10558        let buffer_snapshot = buffer.read(cx).snapshot();
10559
10560        let row = buffer_snapshot
10561            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10562            .row;
10563
10564        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10565        let anchor_end = snapshot
10566            .buffer_snapshot
10567            .anchor_after(Point::new(row, line_len));
10568
10569        let bp = self
10570            .breakpoint_store
10571            .as_ref()?
10572            .read_with(cx, |breakpoint_store, cx| {
10573                breakpoint_store
10574                    .breakpoints(
10575                        &buffer,
10576                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10577                        &buffer_snapshot,
10578                        cx,
10579                    )
10580                    .next()
10581                    .and_then(|(bp, _)| {
10582                        let breakpoint_row = buffer_snapshot
10583                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10584                            .row;
10585
10586                        if breakpoint_row == row {
10587                            snapshot
10588                                .buffer_snapshot
10589                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10590                                .map(|position| (position, bp.bp.clone()))
10591                        } else {
10592                            None
10593                        }
10594                    })
10595            });
10596        bp
10597    }
10598
10599    pub fn edit_log_breakpoint(
10600        &mut self,
10601        _: &EditLogBreakpoint,
10602        window: &mut Window,
10603        cx: &mut Context<Self>,
10604    ) {
10605        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10606            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10607                message: None,
10608                state: BreakpointState::Enabled,
10609                condition: None,
10610                hit_condition: None,
10611            });
10612
10613            self.add_edit_breakpoint_block(
10614                anchor,
10615                &breakpoint,
10616                BreakpointPromptEditAction::Log,
10617                window,
10618                cx,
10619            );
10620        }
10621    }
10622
10623    fn breakpoints_at_cursors(
10624        &self,
10625        window: &mut Window,
10626        cx: &mut Context<Self>,
10627    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10628        let snapshot = self.snapshot(window, cx);
10629        let cursors = self
10630            .selections
10631            .disjoint_anchors()
10632            .into_iter()
10633            .map(|selection| {
10634                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10635
10636                let breakpoint_position = self
10637                    .breakpoint_at_row(cursor_position.row, window, cx)
10638                    .map(|bp| bp.0)
10639                    .unwrap_or_else(|| {
10640                        snapshot
10641                            .display_snapshot
10642                            .buffer_snapshot
10643                            .anchor_after(Point::new(cursor_position.row, 0))
10644                    });
10645
10646                let breakpoint = self
10647                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10648                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10649
10650                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10651            })
10652            // 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.
10653            .collect::<HashMap<Anchor, _>>();
10654
10655        cursors.into_iter().collect()
10656    }
10657
10658    pub fn enable_breakpoint(
10659        &mut self,
10660        _: &crate::actions::EnableBreakpoint,
10661        window: &mut Window,
10662        cx: &mut Context<Self>,
10663    ) {
10664        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10665            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10666                continue;
10667            };
10668            self.edit_breakpoint_at_anchor(
10669                anchor,
10670                breakpoint,
10671                BreakpointEditAction::InvertState,
10672                cx,
10673            );
10674        }
10675    }
10676
10677    pub fn disable_breakpoint(
10678        &mut self,
10679        _: &crate::actions::DisableBreakpoint,
10680        window: &mut Window,
10681        cx: &mut Context<Self>,
10682    ) {
10683        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10684            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10685                continue;
10686            };
10687            self.edit_breakpoint_at_anchor(
10688                anchor,
10689                breakpoint,
10690                BreakpointEditAction::InvertState,
10691                cx,
10692            );
10693        }
10694    }
10695
10696    pub fn toggle_breakpoint(
10697        &mut self,
10698        _: &crate::actions::ToggleBreakpoint,
10699        window: &mut Window,
10700        cx: &mut Context<Self>,
10701    ) {
10702        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10703            if let Some(breakpoint) = breakpoint {
10704                self.edit_breakpoint_at_anchor(
10705                    anchor,
10706                    breakpoint,
10707                    BreakpointEditAction::Toggle,
10708                    cx,
10709                );
10710            } else {
10711                self.edit_breakpoint_at_anchor(
10712                    anchor,
10713                    Breakpoint::new_standard(),
10714                    BreakpointEditAction::Toggle,
10715                    cx,
10716                );
10717            }
10718        }
10719    }
10720
10721    pub fn edit_breakpoint_at_anchor(
10722        &mut self,
10723        breakpoint_position: Anchor,
10724        breakpoint: Breakpoint,
10725        edit_action: BreakpointEditAction,
10726        cx: &mut Context<Self>,
10727    ) {
10728        let Some(breakpoint_store) = &self.breakpoint_store else {
10729            return;
10730        };
10731
10732        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10733            if breakpoint_position == Anchor::min() {
10734                self.buffer()
10735                    .read(cx)
10736                    .excerpt_buffer_ids()
10737                    .into_iter()
10738                    .next()
10739            } else {
10740                None
10741            }
10742        }) else {
10743            return;
10744        };
10745
10746        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10747            return;
10748        };
10749
10750        breakpoint_store.update(cx, |breakpoint_store, cx| {
10751            breakpoint_store.toggle_breakpoint(
10752                buffer,
10753                BreakpointWithPosition {
10754                    position: breakpoint_position.text_anchor,
10755                    bp: breakpoint,
10756                },
10757                edit_action,
10758                cx,
10759            );
10760        });
10761
10762        cx.notify();
10763    }
10764
10765    #[cfg(any(test, feature = "test-support"))]
10766    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10767        self.breakpoint_store.clone()
10768    }
10769
10770    pub fn prepare_restore_change(
10771        &self,
10772        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10773        hunk: &MultiBufferDiffHunk,
10774        cx: &mut App,
10775    ) -> Option<()> {
10776        if hunk.is_created_file() {
10777            return None;
10778        }
10779        let buffer = self.buffer.read(cx);
10780        let diff = buffer.diff_for(hunk.buffer_id)?;
10781        let buffer = buffer.buffer(hunk.buffer_id)?;
10782        let buffer = buffer.read(cx);
10783        let original_text = diff
10784            .read(cx)
10785            .base_text()
10786            .as_rope()
10787            .slice(hunk.diff_base_byte_range.clone());
10788        let buffer_snapshot = buffer.snapshot();
10789        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10790        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10791            probe
10792                .0
10793                .start
10794                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10795                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10796        }) {
10797            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10798            Some(())
10799        } else {
10800            None
10801        }
10802    }
10803
10804    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10805        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10806    }
10807
10808    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10809        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10810    }
10811
10812    fn manipulate_lines<M>(
10813        &mut self,
10814        window: &mut Window,
10815        cx: &mut Context<Self>,
10816        mut manipulate: M,
10817    ) where
10818        M: FnMut(&str) -> LineManipulationResult,
10819    {
10820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10821
10822        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10823        let buffer = self.buffer.read(cx).snapshot(cx);
10824
10825        let mut edits = Vec::new();
10826
10827        let selections = self.selections.all::<Point>(cx);
10828        let mut selections = selections.iter().peekable();
10829        let mut contiguous_row_selections = Vec::new();
10830        let mut new_selections = Vec::new();
10831        let mut added_lines = 0;
10832        let mut removed_lines = 0;
10833
10834        while let Some(selection) = selections.next() {
10835            let (start_row, end_row) = consume_contiguous_rows(
10836                &mut contiguous_row_selections,
10837                selection,
10838                &display_map,
10839                &mut selections,
10840            );
10841
10842            let start_point = Point::new(start_row.0, 0);
10843            let end_point = Point::new(
10844                end_row.previous_row().0,
10845                buffer.line_len(end_row.previous_row()),
10846            );
10847            let text = buffer
10848                .text_for_range(start_point..end_point)
10849                .collect::<String>();
10850
10851            let LineManipulationResult {
10852                new_text,
10853                line_count_before,
10854                line_count_after,
10855            } = manipulate(&text);
10856
10857            edits.push((start_point..end_point, new_text));
10858
10859            // Selections must change based on added and removed line count
10860            let start_row =
10861                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10862            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10863            new_selections.push(Selection {
10864                id: selection.id,
10865                start: start_row,
10866                end: end_row,
10867                goal: SelectionGoal::None,
10868                reversed: selection.reversed,
10869            });
10870
10871            if line_count_after > line_count_before {
10872                added_lines += line_count_after - line_count_before;
10873            } else if line_count_before > line_count_after {
10874                removed_lines += line_count_before - line_count_after;
10875            }
10876        }
10877
10878        self.transact(window, cx, |this, window, cx| {
10879            let buffer = this.buffer.update(cx, |buffer, cx| {
10880                buffer.edit(edits, None, cx);
10881                buffer.snapshot(cx)
10882            });
10883
10884            // Recalculate offsets on newly edited buffer
10885            let new_selections = new_selections
10886                .iter()
10887                .map(|s| {
10888                    let start_point = Point::new(s.start.0, 0);
10889                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10890                    Selection {
10891                        id: s.id,
10892                        start: buffer.point_to_offset(start_point),
10893                        end: buffer.point_to_offset(end_point),
10894                        goal: s.goal,
10895                        reversed: s.reversed,
10896                    }
10897                })
10898                .collect();
10899
10900            this.change_selections(Default::default(), window, cx, |s| {
10901                s.select(new_selections);
10902            });
10903
10904            this.request_autoscroll(Autoscroll::fit(), cx);
10905        });
10906    }
10907
10908    fn manipulate_immutable_lines<Fn>(
10909        &mut self,
10910        window: &mut Window,
10911        cx: &mut Context<Self>,
10912        mut callback: Fn,
10913    ) where
10914        Fn: FnMut(&mut Vec<&str>),
10915    {
10916        self.manipulate_lines(window, cx, |text| {
10917            let mut lines: Vec<&str> = text.split('\n').collect();
10918            let line_count_before = lines.len();
10919
10920            callback(&mut lines);
10921
10922            LineManipulationResult {
10923                new_text: lines.join("\n"),
10924                line_count_before,
10925                line_count_after: lines.len(),
10926            }
10927        });
10928    }
10929
10930    fn manipulate_mutable_lines<Fn>(
10931        &mut self,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934        mut callback: Fn,
10935    ) where
10936        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10937    {
10938        self.manipulate_lines(window, cx, |text| {
10939            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10940            let line_count_before = lines.len();
10941
10942            callback(&mut lines);
10943
10944            LineManipulationResult {
10945                new_text: lines.join("\n"),
10946                line_count_before,
10947                line_count_after: lines.len(),
10948            }
10949        });
10950    }
10951
10952    pub fn convert_indentation_to_spaces(
10953        &mut self,
10954        _: &ConvertIndentationToSpaces,
10955        window: &mut Window,
10956        cx: &mut Context<Self>,
10957    ) {
10958        let settings = self.buffer.read(cx).language_settings(cx);
10959        let tab_size = settings.tab_size.get() as usize;
10960
10961        self.manipulate_mutable_lines(window, cx, |lines| {
10962            // Allocates a reasonably sized scratch buffer once for the whole loop
10963            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10964            // Avoids recomputing spaces that could be inserted many times
10965            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10966                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10967                .collect();
10968
10969            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10970                let mut chars = line.as_ref().chars();
10971                let mut col = 0;
10972                let mut changed = false;
10973
10974                while let Some(ch) = chars.next() {
10975                    match ch {
10976                        ' ' => {
10977                            reindented_line.push(' ');
10978                            col += 1;
10979                        }
10980                        '\t' => {
10981                            // \t are converted to spaces depending on the current column
10982                            let spaces_len = tab_size - (col % tab_size);
10983                            reindented_line.extend(&space_cache[spaces_len - 1]);
10984                            col += spaces_len;
10985                            changed = true;
10986                        }
10987                        _ => {
10988                            // If we dont append before break, the character is consumed
10989                            reindented_line.push(ch);
10990                            break;
10991                        }
10992                    }
10993                }
10994
10995                if !changed {
10996                    reindented_line.clear();
10997                    continue;
10998                }
10999                // Append the rest of the line and replace old reference with new one
11000                reindented_line.extend(chars);
11001                *line = Cow::Owned(reindented_line.clone());
11002                reindented_line.clear();
11003            }
11004        });
11005    }
11006
11007    pub fn convert_indentation_to_tabs(
11008        &mut self,
11009        _: &ConvertIndentationToTabs,
11010        window: &mut Window,
11011        cx: &mut Context<Self>,
11012    ) {
11013        let settings = self.buffer.read(cx).language_settings(cx);
11014        let tab_size = settings.tab_size.get() as usize;
11015
11016        self.manipulate_mutable_lines(window, cx, |lines| {
11017            // Allocates a reasonably sized buffer once for the whole loop
11018            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11019            // Avoids recomputing spaces that could be inserted many times
11020            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11021                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11022                .collect();
11023
11024            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11025                let mut chars = line.chars();
11026                let mut spaces_count = 0;
11027                let mut first_non_indent_char = None;
11028                let mut changed = false;
11029
11030                while let Some(ch) = chars.next() {
11031                    match ch {
11032                        ' ' => {
11033                            // Keep track of spaces. Append \t when we reach tab_size
11034                            spaces_count += 1;
11035                            changed = true;
11036                            if spaces_count == tab_size {
11037                                reindented_line.push('\t');
11038                                spaces_count = 0;
11039                            }
11040                        }
11041                        '\t' => {
11042                            reindented_line.push('\t');
11043                            spaces_count = 0;
11044                        }
11045                        _ => {
11046                            // Dont append it yet, we might have remaining spaces
11047                            first_non_indent_char = Some(ch);
11048                            break;
11049                        }
11050                    }
11051                }
11052
11053                if !changed {
11054                    reindented_line.clear();
11055                    continue;
11056                }
11057                // Remaining spaces that didn't make a full tab stop
11058                if spaces_count > 0 {
11059                    reindented_line.extend(&space_cache[spaces_count - 1]);
11060                }
11061                // If we consume an extra character that was not indentation, add it back
11062                if let Some(extra_char) = first_non_indent_char {
11063                    reindented_line.push(extra_char);
11064                }
11065                // Append the rest of the line and replace old reference with new one
11066                reindented_line.extend(chars);
11067                *line = Cow::Owned(reindented_line.clone());
11068                reindented_line.clear();
11069            }
11070        });
11071    }
11072
11073    pub fn convert_to_upper_case(
11074        &mut self,
11075        _: &ConvertToUpperCase,
11076        window: &mut Window,
11077        cx: &mut Context<Self>,
11078    ) {
11079        self.manipulate_text(window, cx, |text| text.to_uppercase())
11080    }
11081
11082    pub fn convert_to_lower_case(
11083        &mut self,
11084        _: &ConvertToLowerCase,
11085        window: &mut Window,
11086        cx: &mut Context<Self>,
11087    ) {
11088        self.manipulate_text(window, cx, |text| text.to_lowercase())
11089    }
11090
11091    pub fn convert_to_title_case(
11092        &mut self,
11093        _: &ConvertToTitleCase,
11094        window: &mut Window,
11095        cx: &mut Context<Self>,
11096    ) {
11097        self.manipulate_text(window, cx, |text| {
11098            text.split('\n')
11099                .map(|line| line.to_case(Case::Title))
11100                .join("\n")
11101        })
11102    }
11103
11104    pub fn convert_to_snake_case(
11105        &mut self,
11106        _: &ConvertToSnakeCase,
11107        window: &mut Window,
11108        cx: &mut Context<Self>,
11109    ) {
11110        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11111    }
11112
11113    pub fn convert_to_kebab_case(
11114        &mut self,
11115        _: &ConvertToKebabCase,
11116        window: &mut Window,
11117        cx: &mut Context<Self>,
11118    ) {
11119        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11120    }
11121
11122    pub fn convert_to_upper_camel_case(
11123        &mut self,
11124        _: &ConvertToUpperCamelCase,
11125        window: &mut Window,
11126        cx: &mut Context<Self>,
11127    ) {
11128        self.manipulate_text(window, cx, |text| {
11129            text.split('\n')
11130                .map(|line| line.to_case(Case::UpperCamel))
11131                .join("\n")
11132        })
11133    }
11134
11135    pub fn convert_to_lower_camel_case(
11136        &mut self,
11137        _: &ConvertToLowerCamelCase,
11138        window: &mut Window,
11139        cx: &mut Context<Self>,
11140    ) {
11141        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11142    }
11143
11144    pub fn convert_to_opposite_case(
11145        &mut self,
11146        _: &ConvertToOppositeCase,
11147        window: &mut Window,
11148        cx: &mut Context<Self>,
11149    ) {
11150        self.manipulate_text(window, cx, |text| {
11151            text.chars()
11152                .fold(String::with_capacity(text.len()), |mut t, c| {
11153                    if c.is_uppercase() {
11154                        t.extend(c.to_lowercase());
11155                    } else {
11156                        t.extend(c.to_uppercase());
11157                    }
11158                    t
11159                })
11160        })
11161    }
11162
11163    pub fn convert_to_sentence_case(
11164        &mut self,
11165        _: &ConvertToSentenceCase,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11170    }
11171
11172    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11173        self.manipulate_text(window, cx, |text| {
11174            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11175            if has_upper_case_characters {
11176                text.to_lowercase()
11177            } else {
11178                text.to_uppercase()
11179            }
11180        })
11181    }
11182
11183    pub fn convert_to_rot13(
11184        &mut self,
11185        _: &ConvertToRot13,
11186        window: &mut Window,
11187        cx: &mut Context<Self>,
11188    ) {
11189        self.manipulate_text(window, cx, |text| {
11190            text.chars()
11191                .map(|c| match c {
11192                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11193                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11194                    _ => c,
11195                })
11196                .collect()
11197        })
11198    }
11199
11200    pub fn convert_to_rot47(
11201        &mut self,
11202        _: &ConvertToRot47,
11203        window: &mut Window,
11204        cx: &mut Context<Self>,
11205    ) {
11206        self.manipulate_text(window, cx, |text| {
11207            text.chars()
11208                .map(|c| {
11209                    let code_point = c as u32;
11210                    if code_point >= 33 && code_point <= 126 {
11211                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11212                    }
11213                    c
11214                })
11215                .collect()
11216        })
11217    }
11218
11219    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11220    where
11221        Fn: FnMut(&str) -> String,
11222    {
11223        let buffer = self.buffer.read(cx).snapshot(cx);
11224
11225        let mut new_selections = Vec::new();
11226        let mut edits = Vec::new();
11227        let mut selection_adjustment = 0i32;
11228
11229        for selection in self.selections.all::<usize>(cx) {
11230            let selection_is_empty = selection.is_empty();
11231
11232            let (start, end) = if selection_is_empty {
11233                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11234                (word_range.start, word_range.end)
11235            } else {
11236                (selection.start, selection.end)
11237            };
11238
11239            let text = buffer.text_for_range(start..end).collect::<String>();
11240            let old_length = text.len() as i32;
11241            let text = callback(&text);
11242
11243            new_selections.push(Selection {
11244                start: (start as i32 - selection_adjustment) as usize,
11245                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11246                goal: SelectionGoal::None,
11247                ..selection
11248            });
11249
11250            selection_adjustment += old_length - text.len() as i32;
11251
11252            edits.push((start..end, text));
11253        }
11254
11255        self.transact(window, cx, |this, window, cx| {
11256            this.buffer.update(cx, |buffer, cx| {
11257                buffer.edit(edits, None, cx);
11258            });
11259
11260            this.change_selections(Default::default(), window, cx, |s| {
11261                s.select(new_selections);
11262            });
11263
11264            this.request_autoscroll(Autoscroll::fit(), cx);
11265        });
11266    }
11267
11268    pub fn move_selection_on_drop(
11269        &mut self,
11270        selection: &Selection<Anchor>,
11271        target: DisplayPoint,
11272        is_cut: bool,
11273        window: &mut Window,
11274        cx: &mut Context<Self>,
11275    ) {
11276        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11277        let buffer = &display_map.buffer_snapshot;
11278        let mut edits = Vec::new();
11279        let insert_point = display_map
11280            .clip_point(target, Bias::Left)
11281            .to_point(&display_map);
11282        let text = buffer
11283            .text_for_range(selection.start..selection.end)
11284            .collect::<String>();
11285        if is_cut {
11286            edits.push(((selection.start..selection.end), String::new()));
11287        }
11288        let insert_anchor = buffer.anchor_before(insert_point);
11289        edits.push(((insert_anchor..insert_anchor), text));
11290        let last_edit_start = insert_anchor.bias_left(buffer);
11291        let last_edit_end = insert_anchor.bias_right(buffer);
11292        self.transact(window, cx, |this, window, cx| {
11293            this.buffer.update(cx, |buffer, cx| {
11294                buffer.edit(edits, None, cx);
11295            });
11296            this.change_selections(Default::default(), window, cx, |s| {
11297                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11298            });
11299        });
11300    }
11301
11302    pub fn clear_selection_drag_state(&mut self) {
11303        self.selection_drag_state = SelectionDragState::None;
11304    }
11305
11306    pub fn duplicate(
11307        &mut self,
11308        upwards: bool,
11309        whole_lines: bool,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11314
11315        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11316        let buffer = &display_map.buffer_snapshot;
11317        let selections = self.selections.all::<Point>(cx);
11318
11319        let mut edits = Vec::new();
11320        let mut selections_iter = selections.iter().peekable();
11321        while let Some(selection) = selections_iter.next() {
11322            let mut rows = selection.spanned_rows(false, &display_map);
11323            // duplicate line-wise
11324            if whole_lines || selection.start == selection.end {
11325                // Avoid duplicating the same lines twice.
11326                while let Some(next_selection) = selections_iter.peek() {
11327                    let next_rows = next_selection.spanned_rows(false, &display_map);
11328                    if next_rows.start < rows.end {
11329                        rows.end = next_rows.end;
11330                        selections_iter.next().unwrap();
11331                    } else {
11332                        break;
11333                    }
11334                }
11335
11336                // Copy the text from the selected row region and splice it either at the start
11337                // or end of the region.
11338                let start = Point::new(rows.start.0, 0);
11339                let end = Point::new(
11340                    rows.end.previous_row().0,
11341                    buffer.line_len(rows.end.previous_row()),
11342                );
11343                let text = buffer
11344                    .text_for_range(start..end)
11345                    .chain(Some("\n"))
11346                    .collect::<String>();
11347                let insert_location = if upwards {
11348                    Point::new(rows.end.0, 0)
11349                } else {
11350                    start
11351                };
11352                edits.push((insert_location..insert_location, text));
11353            } else {
11354                // duplicate character-wise
11355                let start = selection.start;
11356                let end = selection.end;
11357                let text = buffer.text_for_range(start..end).collect::<String>();
11358                edits.push((selection.end..selection.end, text));
11359            }
11360        }
11361
11362        self.transact(window, cx, |this, _, cx| {
11363            this.buffer.update(cx, |buffer, cx| {
11364                buffer.edit(edits, None, cx);
11365            });
11366
11367            this.request_autoscroll(Autoscroll::fit(), cx);
11368        });
11369    }
11370
11371    pub fn duplicate_line_up(
11372        &mut self,
11373        _: &DuplicateLineUp,
11374        window: &mut Window,
11375        cx: &mut Context<Self>,
11376    ) {
11377        self.duplicate(true, true, window, cx);
11378    }
11379
11380    pub fn duplicate_line_down(
11381        &mut self,
11382        _: &DuplicateLineDown,
11383        window: &mut Window,
11384        cx: &mut Context<Self>,
11385    ) {
11386        self.duplicate(false, true, window, cx);
11387    }
11388
11389    pub fn duplicate_selection(
11390        &mut self,
11391        _: &DuplicateSelection,
11392        window: &mut Window,
11393        cx: &mut Context<Self>,
11394    ) {
11395        self.duplicate(false, false, window, cx);
11396    }
11397
11398    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11399        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11400        if self.mode.is_single_line() {
11401            cx.propagate();
11402            return;
11403        }
11404
11405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11406        let buffer = self.buffer.read(cx).snapshot(cx);
11407
11408        let mut edits = Vec::new();
11409        let mut unfold_ranges = Vec::new();
11410        let mut refold_creases = Vec::new();
11411
11412        let selections = self.selections.all::<Point>(cx);
11413        let mut selections = selections.iter().peekable();
11414        let mut contiguous_row_selections = Vec::new();
11415        let mut new_selections = Vec::new();
11416
11417        while let Some(selection) = selections.next() {
11418            // Find all the selections that span a contiguous row range
11419            let (start_row, end_row) = consume_contiguous_rows(
11420                &mut contiguous_row_selections,
11421                selection,
11422                &display_map,
11423                &mut selections,
11424            );
11425
11426            // Move the text spanned by the row range to be before the line preceding the row range
11427            if start_row.0 > 0 {
11428                let range_to_move = Point::new(
11429                    start_row.previous_row().0,
11430                    buffer.line_len(start_row.previous_row()),
11431                )
11432                    ..Point::new(
11433                        end_row.previous_row().0,
11434                        buffer.line_len(end_row.previous_row()),
11435                    );
11436                let insertion_point = display_map
11437                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11438                    .0;
11439
11440                // Don't move lines across excerpts
11441                if buffer
11442                    .excerpt_containing(insertion_point..range_to_move.end)
11443                    .is_some()
11444                {
11445                    let text = buffer
11446                        .text_for_range(range_to_move.clone())
11447                        .flat_map(|s| s.chars())
11448                        .skip(1)
11449                        .chain(['\n'])
11450                        .collect::<String>();
11451
11452                    edits.push((
11453                        buffer.anchor_after(range_to_move.start)
11454                            ..buffer.anchor_before(range_to_move.end),
11455                        String::new(),
11456                    ));
11457                    let insertion_anchor = buffer.anchor_after(insertion_point);
11458                    edits.push((insertion_anchor..insertion_anchor, text));
11459
11460                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11461
11462                    // Move selections up
11463                    new_selections.extend(contiguous_row_selections.drain(..).map(
11464                        |mut selection| {
11465                            selection.start.row -= row_delta;
11466                            selection.end.row -= row_delta;
11467                            selection
11468                        },
11469                    ));
11470
11471                    // Move folds up
11472                    unfold_ranges.push(range_to_move.clone());
11473                    for fold in display_map.folds_in_range(
11474                        buffer.anchor_before(range_to_move.start)
11475                            ..buffer.anchor_after(range_to_move.end),
11476                    ) {
11477                        let mut start = fold.range.start.to_point(&buffer);
11478                        let mut end = fold.range.end.to_point(&buffer);
11479                        start.row -= row_delta;
11480                        end.row -= row_delta;
11481                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11482                    }
11483                }
11484            }
11485
11486            // If we didn't move line(s), preserve the existing selections
11487            new_selections.append(&mut contiguous_row_selections);
11488        }
11489
11490        self.transact(window, cx, |this, window, cx| {
11491            this.unfold_ranges(&unfold_ranges, true, true, cx);
11492            this.buffer.update(cx, |buffer, cx| {
11493                for (range, text) in edits {
11494                    buffer.edit([(range, text)], None, cx);
11495                }
11496            });
11497            this.fold_creases(refold_creases, true, window, cx);
11498            this.change_selections(Default::default(), window, cx, |s| {
11499                s.select(new_selections);
11500            })
11501        });
11502    }
11503
11504    pub fn move_line_down(
11505        &mut self,
11506        _: &MoveLineDown,
11507        window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11511        if self.mode.is_single_line() {
11512            cx.propagate();
11513            return;
11514        }
11515
11516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11517        let buffer = self.buffer.read(cx).snapshot(cx);
11518
11519        let mut edits = Vec::new();
11520        let mut unfold_ranges = Vec::new();
11521        let mut refold_creases = Vec::new();
11522
11523        let selections = self.selections.all::<Point>(cx);
11524        let mut selections = selections.iter().peekable();
11525        let mut contiguous_row_selections = Vec::new();
11526        let mut new_selections = Vec::new();
11527
11528        while let Some(selection) = selections.next() {
11529            // Find all the selections that span a contiguous row range
11530            let (start_row, end_row) = consume_contiguous_rows(
11531                &mut contiguous_row_selections,
11532                selection,
11533                &display_map,
11534                &mut selections,
11535            );
11536
11537            // Move the text spanned by the row range to be after the last line of the row range
11538            if end_row.0 <= buffer.max_point().row {
11539                let range_to_move =
11540                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11541                let insertion_point = display_map
11542                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11543                    .0;
11544
11545                // Don't move lines across excerpt boundaries
11546                if buffer
11547                    .excerpt_containing(range_to_move.start..insertion_point)
11548                    .is_some()
11549                {
11550                    let mut text = String::from("\n");
11551                    text.extend(buffer.text_for_range(range_to_move.clone()));
11552                    text.pop(); // Drop trailing newline
11553                    edits.push((
11554                        buffer.anchor_after(range_to_move.start)
11555                            ..buffer.anchor_before(range_to_move.end),
11556                        String::new(),
11557                    ));
11558                    let insertion_anchor = buffer.anchor_after(insertion_point);
11559                    edits.push((insertion_anchor..insertion_anchor, text));
11560
11561                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11562
11563                    // Move selections down
11564                    new_selections.extend(contiguous_row_selections.drain(..).map(
11565                        |mut selection| {
11566                            selection.start.row += row_delta;
11567                            selection.end.row += row_delta;
11568                            selection
11569                        },
11570                    ));
11571
11572                    // Move folds down
11573                    unfold_ranges.push(range_to_move.clone());
11574                    for fold in display_map.folds_in_range(
11575                        buffer.anchor_before(range_to_move.start)
11576                            ..buffer.anchor_after(range_to_move.end),
11577                    ) {
11578                        let mut start = fold.range.start.to_point(&buffer);
11579                        let mut end = fold.range.end.to_point(&buffer);
11580                        start.row += row_delta;
11581                        end.row += row_delta;
11582                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11583                    }
11584                }
11585            }
11586
11587            // If we didn't move line(s), preserve the existing selections
11588            new_selections.append(&mut contiguous_row_selections);
11589        }
11590
11591        self.transact(window, cx, |this, window, cx| {
11592            this.unfold_ranges(&unfold_ranges, true, true, cx);
11593            this.buffer.update(cx, |buffer, cx| {
11594                for (range, text) in edits {
11595                    buffer.edit([(range, text)], None, cx);
11596                }
11597            });
11598            this.fold_creases(refold_creases, true, window, cx);
11599            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11600        });
11601    }
11602
11603    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11604        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11605        let text_layout_details = &self.text_layout_details(window);
11606        self.transact(window, cx, |this, window, cx| {
11607            let edits = this.change_selections(Default::default(), window, cx, |s| {
11608                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11609                s.move_with(|display_map, selection| {
11610                    if !selection.is_empty() {
11611                        return;
11612                    }
11613
11614                    let mut head = selection.head();
11615                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11616                    if head.column() == display_map.line_len(head.row()) {
11617                        transpose_offset = display_map
11618                            .buffer_snapshot
11619                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11620                    }
11621
11622                    if transpose_offset == 0 {
11623                        return;
11624                    }
11625
11626                    *head.column_mut() += 1;
11627                    head = display_map.clip_point(head, Bias::Right);
11628                    let goal = SelectionGoal::HorizontalPosition(
11629                        display_map
11630                            .x_for_display_point(head, text_layout_details)
11631                            .into(),
11632                    );
11633                    selection.collapse_to(head, goal);
11634
11635                    let transpose_start = display_map
11636                        .buffer_snapshot
11637                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11638                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11639                        let transpose_end = display_map
11640                            .buffer_snapshot
11641                            .clip_offset(transpose_offset + 1, Bias::Right);
11642                        if let Some(ch) =
11643                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11644                        {
11645                            edits.push((transpose_start..transpose_offset, String::new()));
11646                            edits.push((transpose_end..transpose_end, ch.to_string()));
11647                        }
11648                    }
11649                });
11650                edits
11651            });
11652            this.buffer
11653                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11654            let selections = this.selections.all::<usize>(cx);
11655            this.change_selections(Default::default(), window, cx, |s| {
11656                s.select(selections);
11657            });
11658        });
11659    }
11660
11661    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11663        if self.mode.is_single_line() {
11664            cx.propagate();
11665            return;
11666        }
11667
11668        self.rewrap_impl(RewrapOptions::default(), cx)
11669    }
11670
11671    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11672        let buffer = self.buffer.read(cx).snapshot(cx);
11673        let selections = self.selections.all::<Point>(cx);
11674
11675        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11676        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11677            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11678                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11679                .peekable();
11680
11681            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11682                row
11683            } else {
11684                return Vec::new();
11685            };
11686
11687            let language_settings = buffer.language_settings_at(selection.head(), cx);
11688            let language_scope = buffer.language_scope_at(selection.head());
11689
11690            let indent_and_prefix_for_row =
11691                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11692                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11693                    let (comment_prefix, rewrap_prefix) =
11694                        if let Some(language_scope) = &language_scope {
11695                            let indent_end = Point::new(row, indent.len);
11696                            let comment_prefix = language_scope
11697                                .line_comment_prefixes()
11698                                .iter()
11699                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11700                                .map(|prefix| prefix.to_string());
11701                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11702                            let line_text_after_indent = buffer
11703                                .text_for_range(indent_end..line_end)
11704                                .collect::<String>();
11705                            let rewrap_prefix = language_scope
11706                                .rewrap_prefixes()
11707                                .iter()
11708                                .find_map(|prefix_regex| {
11709                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11710                                        if mat.start() == 0 {
11711                                            Some(mat.as_str().to_string())
11712                                        } else {
11713                                            None
11714                                        }
11715                                    })
11716                                })
11717                                .flatten();
11718                            (comment_prefix, rewrap_prefix)
11719                        } else {
11720                            (None, None)
11721                        };
11722                    (indent, comment_prefix, rewrap_prefix)
11723                };
11724
11725            let mut ranges = Vec::new();
11726            let from_empty_selection = selection.is_empty();
11727
11728            let mut current_range_start = first_row;
11729            let mut prev_row = first_row;
11730            let (
11731                mut current_range_indent,
11732                mut current_range_comment_prefix,
11733                mut current_range_rewrap_prefix,
11734            ) = indent_and_prefix_for_row(first_row);
11735
11736            for row in non_blank_rows_iter.skip(1) {
11737                let has_paragraph_break = row > prev_row + 1;
11738
11739                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11740                    indent_and_prefix_for_row(row);
11741
11742                let has_indent_change = row_indent != current_range_indent;
11743                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11744
11745                let has_boundary_change = has_comment_change
11746                    || row_rewrap_prefix.is_some()
11747                    || (has_indent_change && current_range_comment_prefix.is_some());
11748
11749                if has_paragraph_break || has_boundary_change {
11750                    ranges.push((
11751                        language_settings.clone(),
11752                        Point::new(current_range_start, 0)
11753                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11754                        current_range_indent,
11755                        current_range_comment_prefix.clone(),
11756                        current_range_rewrap_prefix.clone(),
11757                        from_empty_selection,
11758                    ));
11759                    current_range_start = row;
11760                    current_range_indent = row_indent;
11761                    current_range_comment_prefix = row_comment_prefix;
11762                    current_range_rewrap_prefix = row_rewrap_prefix;
11763                }
11764                prev_row = row;
11765            }
11766
11767            ranges.push((
11768                language_settings.clone(),
11769                Point::new(current_range_start, 0)
11770                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11771                current_range_indent,
11772                current_range_comment_prefix,
11773                current_range_rewrap_prefix,
11774                from_empty_selection,
11775            ));
11776
11777            ranges
11778        });
11779
11780        let mut edits = Vec::new();
11781        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11782
11783        for (
11784            language_settings,
11785            wrap_range,
11786            indent_size,
11787            comment_prefix,
11788            rewrap_prefix,
11789            from_empty_selection,
11790        ) in wrap_ranges
11791        {
11792            let mut start_row = wrap_range.start.row;
11793            let mut end_row = wrap_range.end.row;
11794
11795            // Skip selections that overlap with a range that has already been rewrapped.
11796            let selection_range = start_row..end_row;
11797            if rewrapped_row_ranges
11798                .iter()
11799                .any(|range| range.overlaps(&selection_range))
11800            {
11801                continue;
11802            }
11803
11804            let tab_size = language_settings.tab_size;
11805
11806            let indent_prefix = indent_size.chars().collect::<String>();
11807            let mut line_prefix = indent_prefix.clone();
11808            let mut inside_comment = false;
11809            if let Some(prefix) = &comment_prefix {
11810                line_prefix.push_str(prefix);
11811                inside_comment = true;
11812            }
11813            if let Some(prefix) = &rewrap_prefix {
11814                line_prefix.push_str(prefix);
11815            }
11816
11817            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11818                RewrapBehavior::InComments => inside_comment,
11819                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11820                RewrapBehavior::Anywhere => true,
11821            };
11822
11823            let should_rewrap = options.override_language_settings
11824                || allow_rewrap_based_on_language
11825                || self.hard_wrap.is_some();
11826            if !should_rewrap {
11827                continue;
11828            }
11829
11830            if from_empty_selection {
11831                'expand_upwards: while start_row > 0 {
11832                    let prev_row = start_row - 1;
11833                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11834                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11835                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11836                    {
11837                        start_row = prev_row;
11838                    } else {
11839                        break 'expand_upwards;
11840                    }
11841                }
11842
11843                'expand_downwards: while end_row < buffer.max_point().row {
11844                    let next_row = end_row + 1;
11845                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11846                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11847                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11848                    {
11849                        end_row = next_row;
11850                    } else {
11851                        break 'expand_downwards;
11852                    }
11853                }
11854            }
11855
11856            let start = Point::new(start_row, 0);
11857            let start_offset = start.to_offset(&buffer);
11858            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11859            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11860            let Some(lines_without_prefixes) = selection_text
11861                .lines()
11862                .enumerate()
11863                .map(|(ix, line)| {
11864                    let line_trimmed = line.trim_start();
11865                    if rewrap_prefix.is_some() && ix > 0 {
11866                        Ok(line_trimmed)
11867                    } else {
11868                        line_trimmed
11869                            .strip_prefix(&line_prefix.trim_start())
11870                            .with_context(|| {
11871                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11872                            })
11873                    }
11874                })
11875                .collect::<Result<Vec<_>, _>>()
11876                .log_err()
11877            else {
11878                continue;
11879            };
11880
11881            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11882                buffer
11883                    .language_settings_at(Point::new(start_row, 0), cx)
11884                    .preferred_line_length as usize
11885            });
11886
11887            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11888                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11889            } else {
11890                line_prefix.clone()
11891            };
11892
11893            let wrapped_text = wrap_with_prefix(
11894                line_prefix,
11895                subsequent_lines_prefix,
11896                lines_without_prefixes.join("\n"),
11897                wrap_column,
11898                tab_size,
11899                options.preserve_existing_whitespace,
11900            );
11901
11902            // TODO: should always use char-based diff while still supporting cursor behavior that
11903            // matches vim.
11904            let mut diff_options = DiffOptions::default();
11905            if options.override_language_settings {
11906                diff_options.max_word_diff_len = 0;
11907                diff_options.max_word_diff_line_count = 0;
11908            } else {
11909                diff_options.max_word_diff_len = usize::MAX;
11910                diff_options.max_word_diff_line_count = usize::MAX;
11911            }
11912
11913            for (old_range, new_text) in
11914                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11915            {
11916                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11917                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11918                edits.push((edit_start..edit_end, new_text));
11919            }
11920
11921            rewrapped_row_ranges.push(start_row..=end_row);
11922        }
11923
11924        self.buffer
11925            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11926    }
11927
11928    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11929        let mut text = String::new();
11930        let buffer = self.buffer.read(cx).snapshot(cx);
11931        let mut selections = self.selections.all::<Point>(cx);
11932        let mut clipboard_selections = Vec::with_capacity(selections.len());
11933        {
11934            let max_point = buffer.max_point();
11935            let mut is_first = true;
11936            for selection in &mut selections {
11937                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11938                if is_entire_line {
11939                    selection.start = Point::new(selection.start.row, 0);
11940                    if !selection.is_empty() && selection.end.column == 0 {
11941                        selection.end = cmp::min(max_point, selection.end);
11942                    } else {
11943                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11944                    }
11945                    selection.goal = SelectionGoal::None;
11946                }
11947                if is_first {
11948                    is_first = false;
11949                } else {
11950                    text += "\n";
11951                }
11952                let mut len = 0;
11953                for chunk in buffer.text_for_range(selection.start..selection.end) {
11954                    text.push_str(chunk);
11955                    len += chunk.len();
11956                }
11957                clipboard_selections.push(ClipboardSelection {
11958                    len,
11959                    is_entire_line,
11960                    first_line_indent: buffer
11961                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11962                        .len,
11963                });
11964            }
11965        }
11966
11967        self.transact(window, cx, |this, window, cx| {
11968            this.change_selections(Default::default(), window, cx, |s| {
11969                s.select(selections);
11970            });
11971            this.insert("", window, cx);
11972        });
11973        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11974    }
11975
11976    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11978        let item = self.cut_common(window, cx);
11979        cx.write_to_clipboard(item);
11980    }
11981
11982    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11984        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11985            s.move_with(|snapshot, sel| {
11986                if sel.is_empty() {
11987                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11988                }
11989            });
11990        });
11991        let item = self.cut_common(window, cx);
11992        cx.set_global(KillRing(item))
11993    }
11994
11995    pub fn kill_ring_yank(
11996        &mut self,
11997        _: &KillRingYank,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12002        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12003            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12004                (kill_ring.text().to_string(), kill_ring.metadata_json())
12005            } else {
12006                return;
12007            }
12008        } else {
12009            return;
12010        };
12011        self.do_paste(&text, metadata, false, window, cx);
12012    }
12013
12014    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12015        self.do_copy(true, cx);
12016    }
12017
12018    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12019        self.do_copy(false, cx);
12020    }
12021
12022    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12023        let selections = self.selections.all::<Point>(cx);
12024        let buffer = self.buffer.read(cx).read(cx);
12025        let mut text = String::new();
12026
12027        let mut clipboard_selections = Vec::with_capacity(selections.len());
12028        {
12029            let max_point = buffer.max_point();
12030            let mut is_first = true;
12031            for selection in &selections {
12032                let mut start = selection.start;
12033                let mut end = selection.end;
12034                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12035                if is_entire_line {
12036                    start = Point::new(start.row, 0);
12037                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12038                }
12039
12040                let mut trimmed_selections = Vec::new();
12041                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12042                    let row = MultiBufferRow(start.row);
12043                    let first_indent = buffer.indent_size_for_line(row);
12044                    if first_indent.len == 0 || start.column > first_indent.len {
12045                        trimmed_selections.push(start..end);
12046                    } else {
12047                        trimmed_selections.push(
12048                            Point::new(row.0, first_indent.len)
12049                                ..Point::new(row.0, buffer.line_len(row)),
12050                        );
12051                        for row in start.row + 1..=end.row {
12052                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12053                            if row == end.row {
12054                                line_len = end.column;
12055                            }
12056                            if line_len == 0 {
12057                                trimmed_selections
12058                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12059                                continue;
12060                            }
12061                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12062                            if row_indent_size.len >= first_indent.len {
12063                                trimmed_selections.push(
12064                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12065                                );
12066                            } else {
12067                                trimmed_selections.clear();
12068                                trimmed_selections.push(start..end);
12069                                break;
12070                            }
12071                        }
12072                    }
12073                } else {
12074                    trimmed_selections.push(start..end);
12075                }
12076
12077                for trimmed_range in trimmed_selections {
12078                    if is_first {
12079                        is_first = false;
12080                    } else {
12081                        text += "\n";
12082                    }
12083                    let mut len = 0;
12084                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12085                        text.push_str(chunk);
12086                        len += chunk.len();
12087                    }
12088                    clipboard_selections.push(ClipboardSelection {
12089                        len,
12090                        is_entire_line,
12091                        first_line_indent: buffer
12092                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12093                            .len,
12094                    });
12095                }
12096            }
12097        }
12098
12099        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12100            text,
12101            clipboard_selections,
12102        ));
12103    }
12104
12105    pub fn do_paste(
12106        &mut self,
12107        text: &String,
12108        clipboard_selections: Option<Vec<ClipboardSelection>>,
12109        handle_entire_lines: bool,
12110        window: &mut Window,
12111        cx: &mut Context<Self>,
12112    ) {
12113        if self.read_only(cx) {
12114            return;
12115        }
12116
12117        let clipboard_text = Cow::Borrowed(text);
12118
12119        self.transact(window, cx, |this, window, cx| {
12120            if let Some(mut clipboard_selections) = clipboard_selections {
12121                let old_selections = this.selections.all::<usize>(cx);
12122                let all_selections_were_entire_line =
12123                    clipboard_selections.iter().all(|s| s.is_entire_line);
12124                let first_selection_indent_column =
12125                    clipboard_selections.first().map(|s| s.first_line_indent);
12126                if clipboard_selections.len() != old_selections.len() {
12127                    clipboard_selections.drain(..);
12128                }
12129                let cursor_offset = this.selections.last::<usize>(cx).head();
12130                let mut auto_indent_on_paste = true;
12131
12132                this.buffer.update(cx, |buffer, cx| {
12133                    let snapshot = buffer.read(cx);
12134                    auto_indent_on_paste = snapshot
12135                        .language_settings_at(cursor_offset, cx)
12136                        .auto_indent_on_paste;
12137
12138                    let mut start_offset = 0;
12139                    let mut edits = Vec::new();
12140                    let mut original_indent_columns = Vec::new();
12141                    for (ix, selection) in old_selections.iter().enumerate() {
12142                        let to_insert;
12143                        let entire_line;
12144                        let original_indent_column;
12145                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12146                            let end_offset = start_offset + clipboard_selection.len;
12147                            to_insert = &clipboard_text[start_offset..end_offset];
12148                            entire_line = clipboard_selection.is_entire_line;
12149                            start_offset = end_offset + 1;
12150                            original_indent_column = Some(clipboard_selection.first_line_indent);
12151                        } else {
12152                            to_insert = clipboard_text.as_str();
12153                            entire_line = all_selections_were_entire_line;
12154                            original_indent_column = first_selection_indent_column
12155                        }
12156
12157                        // If the corresponding selection was empty when this slice of the
12158                        // clipboard text was written, then the entire line containing the
12159                        // selection was copied. If this selection is also currently empty,
12160                        // then paste the line before the current line of the buffer.
12161                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12162                            let column = selection.start.to_point(&snapshot).column as usize;
12163                            let line_start = selection.start - column;
12164                            line_start..line_start
12165                        } else {
12166                            selection.range()
12167                        };
12168
12169                        edits.push((range, to_insert));
12170                        original_indent_columns.push(original_indent_column);
12171                    }
12172                    drop(snapshot);
12173
12174                    buffer.edit(
12175                        edits,
12176                        if auto_indent_on_paste {
12177                            Some(AutoindentMode::Block {
12178                                original_indent_columns,
12179                            })
12180                        } else {
12181                            None
12182                        },
12183                        cx,
12184                    );
12185                });
12186
12187                let selections = this.selections.all::<usize>(cx);
12188                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12189            } else {
12190                this.insert(&clipboard_text, window, cx);
12191            }
12192        });
12193    }
12194
12195    pub fn diff_clipboard_with_selection(
12196        &mut self,
12197        _: &DiffClipboardWithSelection,
12198        window: &mut Window,
12199        cx: &mut Context<Self>,
12200    ) {
12201        let selections = self.selections.all::<usize>(cx);
12202
12203        if selections.is_empty() {
12204            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12205            return;
12206        };
12207
12208        let clipboard_text = match cx.read_from_clipboard() {
12209            Some(item) => match item.entries().first() {
12210                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12211                _ => None,
12212            },
12213            None => None,
12214        };
12215
12216        let Some(clipboard_text) = clipboard_text else {
12217            log::warn!("Clipboard doesn't contain text.");
12218            return;
12219        };
12220
12221        window.dispatch_action(
12222            Box::new(DiffClipboardWithSelectionData {
12223                clipboard_text,
12224                editor: cx.entity(),
12225            }),
12226            cx,
12227        );
12228    }
12229
12230    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12232        if let Some(item) = cx.read_from_clipboard() {
12233            let entries = item.entries();
12234
12235            match entries.first() {
12236                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12237                // of all the pasted entries.
12238                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12239                    .do_paste(
12240                        clipboard_string.text(),
12241                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12242                        true,
12243                        window,
12244                        cx,
12245                    ),
12246                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12247            }
12248        }
12249    }
12250
12251    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12252        if self.read_only(cx) {
12253            return;
12254        }
12255
12256        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12257
12258        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12259            if let Some((selections, _)) =
12260                self.selection_history.transaction(transaction_id).cloned()
12261            {
12262                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12263                    s.select_anchors(selections.to_vec());
12264                });
12265            } else {
12266                log::error!(
12267                    "No entry in selection_history found for undo. \
12268                     This may correspond to a bug where undo does not update the selection. \
12269                     If this is occurring, please add details to \
12270                     https://github.com/zed-industries/zed/issues/22692"
12271                );
12272            }
12273            self.request_autoscroll(Autoscroll::fit(), cx);
12274            self.unmark_text(window, cx);
12275            self.refresh_edit_prediction(true, false, window, cx);
12276            cx.emit(EditorEvent::Edited { transaction_id });
12277            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12278        }
12279    }
12280
12281    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12282        if self.read_only(cx) {
12283            return;
12284        }
12285
12286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12287
12288        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12289            if let Some((_, Some(selections))) =
12290                self.selection_history.transaction(transaction_id).cloned()
12291            {
12292                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12293                    s.select_anchors(selections.to_vec());
12294                });
12295            } else {
12296                log::error!(
12297                    "No entry in selection_history found for redo. \
12298                     This may correspond to a bug where undo does not update the selection. \
12299                     If this is occurring, please add details to \
12300                     https://github.com/zed-industries/zed/issues/22692"
12301                );
12302            }
12303            self.request_autoscroll(Autoscroll::fit(), cx);
12304            self.unmark_text(window, cx);
12305            self.refresh_edit_prediction(true, false, window, cx);
12306            cx.emit(EditorEvent::Edited { transaction_id });
12307        }
12308    }
12309
12310    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12311        self.buffer
12312            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12313    }
12314
12315    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12316        self.buffer
12317            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12318    }
12319
12320    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12322        self.change_selections(Default::default(), window, cx, |s| {
12323            s.move_with(|map, selection| {
12324                let cursor = if selection.is_empty() {
12325                    movement::left(map, selection.start)
12326                } else {
12327                    selection.start
12328                };
12329                selection.collapse_to(cursor, SelectionGoal::None);
12330            });
12331        })
12332    }
12333
12334    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12336        self.change_selections(Default::default(), window, cx, |s| {
12337            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12338        })
12339    }
12340
12341    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12342        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12343        self.change_selections(Default::default(), window, cx, |s| {
12344            s.move_with(|map, selection| {
12345                let cursor = if selection.is_empty() {
12346                    movement::right(map, selection.end)
12347                } else {
12348                    selection.end
12349                };
12350                selection.collapse_to(cursor, SelectionGoal::None)
12351            });
12352        })
12353    }
12354
12355    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12357        self.change_selections(Default::default(), window, cx, |s| {
12358            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12359        })
12360    }
12361
12362    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12363        if self.take_rename(true, window, cx).is_some() {
12364            return;
12365        }
12366
12367        if self.mode.is_single_line() {
12368            cx.propagate();
12369            return;
12370        }
12371
12372        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12373
12374        let text_layout_details = &self.text_layout_details(window);
12375        let selection_count = self.selections.count();
12376        let first_selection = self.selections.first_anchor();
12377
12378        self.change_selections(Default::default(), window, cx, |s| {
12379            s.move_with(|map, selection| {
12380                if !selection.is_empty() {
12381                    selection.goal = SelectionGoal::None;
12382                }
12383                let (cursor, goal) = movement::up(
12384                    map,
12385                    selection.start,
12386                    selection.goal,
12387                    false,
12388                    text_layout_details,
12389                );
12390                selection.collapse_to(cursor, goal);
12391            });
12392        });
12393
12394        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12395        {
12396            cx.propagate();
12397        }
12398    }
12399
12400    pub fn move_up_by_lines(
12401        &mut self,
12402        action: &MoveUpByLines,
12403        window: &mut Window,
12404        cx: &mut Context<Self>,
12405    ) {
12406        if self.take_rename(true, window, cx).is_some() {
12407            return;
12408        }
12409
12410        if self.mode.is_single_line() {
12411            cx.propagate();
12412            return;
12413        }
12414
12415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12416
12417        let text_layout_details = &self.text_layout_details(window);
12418
12419        self.change_selections(Default::default(), window, cx, |s| {
12420            s.move_with(|map, selection| {
12421                if !selection.is_empty() {
12422                    selection.goal = SelectionGoal::None;
12423                }
12424                let (cursor, goal) = movement::up_by_rows(
12425                    map,
12426                    selection.start,
12427                    action.lines,
12428                    selection.goal,
12429                    false,
12430                    text_layout_details,
12431                );
12432                selection.collapse_to(cursor, goal);
12433            });
12434        })
12435    }
12436
12437    pub fn move_down_by_lines(
12438        &mut self,
12439        action: &MoveDownByLines,
12440        window: &mut Window,
12441        cx: &mut Context<Self>,
12442    ) {
12443        if self.take_rename(true, window, cx).is_some() {
12444            return;
12445        }
12446
12447        if self.mode.is_single_line() {
12448            cx.propagate();
12449            return;
12450        }
12451
12452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12453
12454        let text_layout_details = &self.text_layout_details(window);
12455
12456        self.change_selections(Default::default(), window, cx, |s| {
12457            s.move_with(|map, selection| {
12458                if !selection.is_empty() {
12459                    selection.goal = SelectionGoal::None;
12460                }
12461                let (cursor, goal) = movement::down_by_rows(
12462                    map,
12463                    selection.start,
12464                    action.lines,
12465                    selection.goal,
12466                    false,
12467                    text_layout_details,
12468                );
12469                selection.collapse_to(cursor, goal);
12470            });
12471        })
12472    }
12473
12474    pub fn select_down_by_lines(
12475        &mut self,
12476        action: &SelectDownByLines,
12477        window: &mut Window,
12478        cx: &mut Context<Self>,
12479    ) {
12480        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12481        let text_layout_details = &self.text_layout_details(window);
12482        self.change_selections(Default::default(), window, cx, |s| {
12483            s.move_heads_with(|map, head, goal| {
12484                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12485            })
12486        })
12487    }
12488
12489    pub fn select_up_by_lines(
12490        &mut self,
12491        action: &SelectUpByLines,
12492        window: &mut Window,
12493        cx: &mut Context<Self>,
12494    ) {
12495        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12496        let text_layout_details = &self.text_layout_details(window);
12497        self.change_selections(Default::default(), window, cx, |s| {
12498            s.move_heads_with(|map, head, goal| {
12499                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12500            })
12501        })
12502    }
12503
12504    pub fn select_page_up(
12505        &mut self,
12506        _: &SelectPageUp,
12507        window: &mut Window,
12508        cx: &mut Context<Self>,
12509    ) {
12510        let Some(row_count) = self.visible_row_count() else {
12511            return;
12512        };
12513
12514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12515
12516        let text_layout_details = &self.text_layout_details(window);
12517
12518        self.change_selections(Default::default(), window, cx, |s| {
12519            s.move_heads_with(|map, head, goal| {
12520                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12521            })
12522        })
12523    }
12524
12525    pub fn move_page_up(
12526        &mut self,
12527        action: &MovePageUp,
12528        window: &mut Window,
12529        cx: &mut Context<Self>,
12530    ) {
12531        if self.take_rename(true, window, cx).is_some() {
12532            return;
12533        }
12534
12535        if self
12536            .context_menu
12537            .borrow_mut()
12538            .as_mut()
12539            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12540            .unwrap_or(false)
12541        {
12542            return;
12543        }
12544
12545        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12546            cx.propagate();
12547            return;
12548        }
12549
12550        let Some(row_count) = self.visible_row_count() else {
12551            return;
12552        };
12553
12554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12555
12556        let effects = if action.center_cursor {
12557            SelectionEffects::scroll(Autoscroll::center())
12558        } else {
12559            SelectionEffects::default()
12560        };
12561
12562        let text_layout_details = &self.text_layout_details(window);
12563
12564        self.change_selections(effects, window, cx, |s| {
12565            s.move_with(|map, selection| {
12566                if !selection.is_empty() {
12567                    selection.goal = SelectionGoal::None;
12568                }
12569                let (cursor, goal) = movement::up_by_rows(
12570                    map,
12571                    selection.end,
12572                    row_count,
12573                    selection.goal,
12574                    false,
12575                    text_layout_details,
12576                );
12577                selection.collapse_to(cursor, goal);
12578            });
12579        });
12580    }
12581
12582    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12584        let text_layout_details = &self.text_layout_details(window);
12585        self.change_selections(Default::default(), window, cx, |s| {
12586            s.move_heads_with(|map, head, goal| {
12587                movement::up(map, head, goal, false, text_layout_details)
12588            })
12589        })
12590    }
12591
12592    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12593        self.take_rename(true, window, cx);
12594
12595        if self.mode.is_single_line() {
12596            cx.propagate();
12597            return;
12598        }
12599
12600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12601
12602        let text_layout_details = &self.text_layout_details(window);
12603        let selection_count = self.selections.count();
12604        let first_selection = self.selections.first_anchor();
12605
12606        self.change_selections(Default::default(), window, cx, |s| {
12607            s.move_with(|map, selection| {
12608                if !selection.is_empty() {
12609                    selection.goal = SelectionGoal::None;
12610                }
12611                let (cursor, goal) = movement::down(
12612                    map,
12613                    selection.end,
12614                    selection.goal,
12615                    false,
12616                    text_layout_details,
12617                );
12618                selection.collapse_to(cursor, goal);
12619            });
12620        });
12621
12622        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12623        {
12624            cx.propagate();
12625        }
12626    }
12627
12628    pub fn select_page_down(
12629        &mut self,
12630        _: &SelectPageDown,
12631        window: &mut Window,
12632        cx: &mut Context<Self>,
12633    ) {
12634        let Some(row_count) = self.visible_row_count() else {
12635            return;
12636        };
12637
12638        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12639
12640        let text_layout_details = &self.text_layout_details(window);
12641
12642        self.change_selections(Default::default(), window, cx, |s| {
12643            s.move_heads_with(|map, head, goal| {
12644                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12645            })
12646        })
12647    }
12648
12649    pub fn move_page_down(
12650        &mut self,
12651        action: &MovePageDown,
12652        window: &mut Window,
12653        cx: &mut Context<Self>,
12654    ) {
12655        if self.take_rename(true, window, cx).is_some() {
12656            return;
12657        }
12658
12659        if self
12660            .context_menu
12661            .borrow_mut()
12662            .as_mut()
12663            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12664            .unwrap_or(false)
12665        {
12666            return;
12667        }
12668
12669        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12670            cx.propagate();
12671            return;
12672        }
12673
12674        let Some(row_count) = self.visible_row_count() else {
12675            return;
12676        };
12677
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679
12680        let effects = if action.center_cursor {
12681            SelectionEffects::scroll(Autoscroll::center())
12682        } else {
12683            SelectionEffects::default()
12684        };
12685
12686        let text_layout_details = &self.text_layout_details(window);
12687        self.change_selections(effects, window, cx, |s| {
12688            s.move_with(|map, selection| {
12689                if !selection.is_empty() {
12690                    selection.goal = SelectionGoal::None;
12691                }
12692                let (cursor, goal) = movement::down_by_rows(
12693                    map,
12694                    selection.end,
12695                    row_count,
12696                    selection.goal,
12697                    false,
12698                    text_layout_details,
12699                );
12700                selection.collapse_to(cursor, goal);
12701            });
12702        });
12703    }
12704
12705    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12706        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12707        let text_layout_details = &self.text_layout_details(window);
12708        self.change_selections(Default::default(), window, cx, |s| {
12709            s.move_heads_with(|map, head, goal| {
12710                movement::down(map, head, goal, false, text_layout_details)
12711            })
12712        });
12713    }
12714
12715    pub fn context_menu_first(
12716        &mut self,
12717        _: &ContextMenuFirst,
12718        window: &mut Window,
12719        cx: &mut Context<Self>,
12720    ) {
12721        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12722            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12723        }
12724    }
12725
12726    pub fn context_menu_prev(
12727        &mut self,
12728        _: &ContextMenuPrevious,
12729        window: &mut Window,
12730        cx: &mut Context<Self>,
12731    ) {
12732        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12733            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12734        }
12735    }
12736
12737    pub fn context_menu_next(
12738        &mut self,
12739        _: &ContextMenuNext,
12740        window: &mut Window,
12741        cx: &mut Context<Self>,
12742    ) {
12743        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12744            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12745        }
12746    }
12747
12748    pub fn context_menu_last(
12749        &mut self,
12750        _: &ContextMenuLast,
12751        window: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12755            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12756        }
12757    }
12758
12759    pub fn signature_help_prev(
12760        &mut self,
12761        _: &SignatureHelpPrevious,
12762        _: &mut Window,
12763        cx: &mut Context<Self>,
12764    ) {
12765        if let Some(popover) = self.signature_help_state.popover_mut() {
12766            if popover.current_signature == 0 {
12767                popover.current_signature = popover.signatures.len() - 1;
12768            } else {
12769                popover.current_signature -= 1;
12770            }
12771            cx.notify();
12772        }
12773    }
12774
12775    pub fn signature_help_next(
12776        &mut self,
12777        _: &SignatureHelpNext,
12778        _: &mut Window,
12779        cx: &mut Context<Self>,
12780    ) {
12781        if let Some(popover) = self.signature_help_state.popover_mut() {
12782            if popover.current_signature + 1 == popover.signatures.len() {
12783                popover.current_signature = 0;
12784            } else {
12785                popover.current_signature += 1;
12786            }
12787            cx.notify();
12788        }
12789    }
12790
12791    pub fn move_to_previous_word_start(
12792        &mut self,
12793        _: &MoveToPreviousWordStart,
12794        window: &mut Window,
12795        cx: &mut Context<Self>,
12796    ) {
12797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12798        self.change_selections(Default::default(), window, cx, |s| {
12799            s.move_cursors_with(|map, head, _| {
12800                (
12801                    movement::previous_word_start(map, head),
12802                    SelectionGoal::None,
12803                )
12804            });
12805        })
12806    }
12807
12808    pub fn move_to_previous_subword_start(
12809        &mut self,
12810        _: &MoveToPreviousSubwordStart,
12811        window: &mut Window,
12812        cx: &mut Context<Self>,
12813    ) {
12814        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12815        self.change_selections(Default::default(), window, cx, |s| {
12816            s.move_cursors_with(|map, head, _| {
12817                (
12818                    movement::previous_subword_start(map, head),
12819                    SelectionGoal::None,
12820                )
12821            });
12822        })
12823    }
12824
12825    pub fn select_to_previous_word_start(
12826        &mut self,
12827        _: &SelectToPreviousWordStart,
12828        window: &mut Window,
12829        cx: &mut Context<Self>,
12830    ) {
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832        self.change_selections(Default::default(), window, cx, |s| {
12833            s.move_heads_with(|map, head, _| {
12834                (
12835                    movement::previous_word_start(map, head),
12836                    SelectionGoal::None,
12837                )
12838            });
12839        })
12840    }
12841
12842    pub fn select_to_previous_subword_start(
12843        &mut self,
12844        _: &SelectToPreviousSubwordStart,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12849        self.change_selections(Default::default(), window, cx, |s| {
12850            s.move_heads_with(|map, head, _| {
12851                (
12852                    movement::previous_subword_start(map, head),
12853                    SelectionGoal::None,
12854                )
12855            });
12856        })
12857    }
12858
12859    pub fn delete_to_previous_word_start(
12860        &mut self,
12861        action: &DeleteToPreviousWordStart,
12862        window: &mut Window,
12863        cx: &mut Context<Self>,
12864    ) {
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12866        self.transact(window, cx, |this, window, cx| {
12867            this.select_autoclose_pair(window, cx);
12868            this.change_selections(Default::default(), window, cx, |s| {
12869                s.move_with(|map, selection| {
12870                    if selection.is_empty() {
12871                        let cursor = if action.ignore_newlines {
12872                            movement::previous_word_start(map, selection.head())
12873                        } else {
12874                            movement::previous_word_start_or_newline(map, selection.head())
12875                        };
12876                        selection.set_head(cursor, SelectionGoal::None);
12877                    }
12878                });
12879            });
12880            this.insert("", window, cx);
12881        });
12882    }
12883
12884    pub fn delete_to_previous_subword_start(
12885        &mut self,
12886        _: &DeleteToPreviousSubwordStart,
12887        window: &mut Window,
12888        cx: &mut Context<Self>,
12889    ) {
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12891        self.transact(window, cx, |this, window, cx| {
12892            this.select_autoclose_pair(window, cx);
12893            this.change_selections(Default::default(), window, cx, |s| {
12894                s.move_with(|map, selection| {
12895                    if selection.is_empty() {
12896                        let cursor = movement::previous_subword_start(map, selection.head());
12897                        selection.set_head(cursor, SelectionGoal::None);
12898                    }
12899                });
12900            });
12901            this.insert("", window, cx);
12902        });
12903    }
12904
12905    pub fn move_to_next_word_end(
12906        &mut self,
12907        _: &MoveToNextWordEnd,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) {
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912        self.change_selections(Default::default(), window, cx, |s| {
12913            s.move_cursors_with(|map, head, _| {
12914                (movement::next_word_end(map, head), SelectionGoal::None)
12915            });
12916        })
12917    }
12918
12919    pub fn move_to_next_subword_end(
12920        &mut self,
12921        _: &MoveToNextSubwordEnd,
12922        window: &mut Window,
12923        cx: &mut Context<Self>,
12924    ) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        self.change_selections(Default::default(), window, cx, |s| {
12927            s.move_cursors_with(|map, head, _| {
12928                (movement::next_subword_end(map, head), SelectionGoal::None)
12929            });
12930        })
12931    }
12932
12933    pub fn select_to_next_word_end(
12934        &mut self,
12935        _: &SelectToNextWordEnd,
12936        window: &mut Window,
12937        cx: &mut Context<Self>,
12938    ) {
12939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12940        self.change_selections(Default::default(), window, cx, |s| {
12941            s.move_heads_with(|map, head, _| {
12942                (movement::next_word_end(map, head), SelectionGoal::None)
12943            });
12944        })
12945    }
12946
12947    pub fn select_to_next_subword_end(
12948        &mut self,
12949        _: &SelectToNextSubwordEnd,
12950        window: &mut Window,
12951        cx: &mut Context<Self>,
12952    ) {
12953        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12954        self.change_selections(Default::default(), window, cx, |s| {
12955            s.move_heads_with(|map, head, _| {
12956                (movement::next_subword_end(map, head), SelectionGoal::None)
12957            });
12958        })
12959    }
12960
12961    pub fn delete_to_next_word_end(
12962        &mut self,
12963        action: &DeleteToNextWordEnd,
12964        window: &mut Window,
12965        cx: &mut Context<Self>,
12966    ) {
12967        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12968        self.transact(window, cx, |this, window, cx| {
12969            this.change_selections(Default::default(), window, cx, |s| {
12970                s.move_with(|map, selection| {
12971                    if selection.is_empty() {
12972                        let cursor = if action.ignore_newlines {
12973                            movement::next_word_end(map, selection.head())
12974                        } else {
12975                            movement::next_word_end_or_newline(map, selection.head())
12976                        };
12977                        selection.set_head(cursor, SelectionGoal::None);
12978                    }
12979                });
12980            });
12981            this.insert("", window, cx);
12982        });
12983    }
12984
12985    pub fn delete_to_next_subword_end(
12986        &mut self,
12987        _: &DeleteToNextSubwordEnd,
12988        window: &mut Window,
12989        cx: &mut Context<Self>,
12990    ) {
12991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12992        self.transact(window, cx, |this, window, cx| {
12993            this.change_selections(Default::default(), window, cx, |s| {
12994                s.move_with(|map, selection| {
12995                    if selection.is_empty() {
12996                        let cursor = movement::next_subword_end(map, selection.head());
12997                        selection.set_head(cursor, SelectionGoal::None);
12998                    }
12999                });
13000            });
13001            this.insert("", window, cx);
13002        });
13003    }
13004
13005    pub fn move_to_beginning_of_line(
13006        &mut self,
13007        action: &MoveToBeginningOfLine,
13008        window: &mut Window,
13009        cx: &mut Context<Self>,
13010    ) {
13011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13012        self.change_selections(Default::default(), window, cx, |s| {
13013            s.move_cursors_with(|map, head, _| {
13014                (
13015                    movement::indented_line_beginning(
13016                        map,
13017                        head,
13018                        action.stop_at_soft_wraps,
13019                        action.stop_at_indent,
13020                    ),
13021                    SelectionGoal::None,
13022                )
13023            });
13024        })
13025    }
13026
13027    pub fn select_to_beginning_of_line(
13028        &mut self,
13029        action: &SelectToBeginningOfLine,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13034        self.change_selections(Default::default(), window, cx, |s| {
13035            s.move_heads_with(|map, head, _| {
13036                (
13037                    movement::indented_line_beginning(
13038                        map,
13039                        head,
13040                        action.stop_at_soft_wraps,
13041                        action.stop_at_indent,
13042                    ),
13043                    SelectionGoal::None,
13044                )
13045            });
13046        });
13047    }
13048
13049    pub fn delete_to_beginning_of_line(
13050        &mut self,
13051        action: &DeleteToBeginningOfLine,
13052        window: &mut Window,
13053        cx: &mut Context<Self>,
13054    ) {
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13056        self.transact(window, cx, |this, window, cx| {
13057            this.change_selections(Default::default(), window, cx, |s| {
13058                s.move_with(|_, selection| {
13059                    selection.reversed = true;
13060                });
13061            });
13062
13063            this.select_to_beginning_of_line(
13064                &SelectToBeginningOfLine {
13065                    stop_at_soft_wraps: false,
13066                    stop_at_indent: action.stop_at_indent,
13067                },
13068                window,
13069                cx,
13070            );
13071            this.backspace(&Backspace, window, cx);
13072        });
13073    }
13074
13075    pub fn move_to_end_of_line(
13076        &mut self,
13077        action: &MoveToEndOfLine,
13078        window: &mut Window,
13079        cx: &mut Context<Self>,
13080    ) {
13081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13082        self.change_selections(Default::default(), window, cx, |s| {
13083            s.move_cursors_with(|map, head, _| {
13084                (
13085                    movement::line_end(map, head, action.stop_at_soft_wraps),
13086                    SelectionGoal::None,
13087                )
13088            });
13089        })
13090    }
13091
13092    pub fn select_to_end_of_line(
13093        &mut self,
13094        action: &SelectToEndOfLine,
13095        window: &mut Window,
13096        cx: &mut Context<Self>,
13097    ) {
13098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13099        self.change_selections(Default::default(), window, cx, |s| {
13100            s.move_heads_with(|map, head, _| {
13101                (
13102                    movement::line_end(map, head, action.stop_at_soft_wraps),
13103                    SelectionGoal::None,
13104                )
13105            });
13106        })
13107    }
13108
13109    pub fn delete_to_end_of_line(
13110        &mut self,
13111        _: &DeleteToEndOfLine,
13112        window: &mut Window,
13113        cx: &mut Context<Self>,
13114    ) {
13115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13116        self.transact(window, cx, |this, window, cx| {
13117            this.select_to_end_of_line(
13118                &SelectToEndOfLine {
13119                    stop_at_soft_wraps: false,
13120                },
13121                window,
13122                cx,
13123            );
13124            this.delete(&Delete, window, cx);
13125        });
13126    }
13127
13128    pub fn cut_to_end_of_line(
13129        &mut self,
13130        _: &CutToEndOfLine,
13131        window: &mut Window,
13132        cx: &mut Context<Self>,
13133    ) {
13134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13135        self.transact(window, cx, |this, window, cx| {
13136            this.select_to_end_of_line(
13137                &SelectToEndOfLine {
13138                    stop_at_soft_wraps: false,
13139                },
13140                window,
13141                cx,
13142            );
13143            this.cut(&Cut, window, cx);
13144        });
13145    }
13146
13147    pub fn move_to_start_of_paragraph(
13148        &mut self,
13149        _: &MoveToStartOfParagraph,
13150        window: &mut Window,
13151        cx: &mut Context<Self>,
13152    ) {
13153        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13154            cx.propagate();
13155            return;
13156        }
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13158        self.change_selections(Default::default(), window, cx, |s| {
13159            s.move_with(|map, selection| {
13160                selection.collapse_to(
13161                    movement::start_of_paragraph(map, selection.head(), 1),
13162                    SelectionGoal::None,
13163                )
13164            });
13165        })
13166    }
13167
13168    pub fn move_to_end_of_paragraph(
13169        &mut self,
13170        _: &MoveToEndOfParagraph,
13171        window: &mut Window,
13172        cx: &mut Context<Self>,
13173    ) {
13174        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13175            cx.propagate();
13176            return;
13177        }
13178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13179        self.change_selections(Default::default(), window, cx, |s| {
13180            s.move_with(|map, selection| {
13181                selection.collapse_to(
13182                    movement::end_of_paragraph(map, selection.head(), 1),
13183                    SelectionGoal::None,
13184                )
13185            });
13186        })
13187    }
13188
13189    pub fn select_to_start_of_paragraph(
13190        &mut self,
13191        _: &SelectToStartOfParagraph,
13192        window: &mut Window,
13193        cx: &mut Context<Self>,
13194    ) {
13195        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13196            cx.propagate();
13197            return;
13198        }
13199        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13200        self.change_selections(Default::default(), window, cx, |s| {
13201            s.move_heads_with(|map, head, _| {
13202                (
13203                    movement::start_of_paragraph(map, head, 1),
13204                    SelectionGoal::None,
13205                )
13206            });
13207        })
13208    }
13209
13210    pub fn select_to_end_of_paragraph(
13211        &mut self,
13212        _: &SelectToEndOfParagraph,
13213        window: &mut Window,
13214        cx: &mut Context<Self>,
13215    ) {
13216        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13217            cx.propagate();
13218            return;
13219        }
13220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13221        self.change_selections(Default::default(), window, cx, |s| {
13222            s.move_heads_with(|map, head, _| {
13223                (
13224                    movement::end_of_paragraph(map, head, 1),
13225                    SelectionGoal::None,
13226                )
13227            });
13228        })
13229    }
13230
13231    pub fn move_to_start_of_excerpt(
13232        &mut self,
13233        _: &MoveToStartOfExcerpt,
13234        window: &mut Window,
13235        cx: &mut Context<Self>,
13236    ) {
13237        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13238            cx.propagate();
13239            return;
13240        }
13241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13242        self.change_selections(Default::default(), window, cx, |s| {
13243            s.move_with(|map, selection| {
13244                selection.collapse_to(
13245                    movement::start_of_excerpt(
13246                        map,
13247                        selection.head(),
13248                        workspace::searchable::Direction::Prev,
13249                    ),
13250                    SelectionGoal::None,
13251                )
13252            });
13253        })
13254    }
13255
13256    pub fn move_to_start_of_next_excerpt(
13257        &mut self,
13258        _: &MoveToStartOfNextExcerpt,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13263            cx.propagate();
13264            return;
13265        }
13266
13267        self.change_selections(Default::default(), window, cx, |s| {
13268            s.move_with(|map, selection| {
13269                selection.collapse_to(
13270                    movement::start_of_excerpt(
13271                        map,
13272                        selection.head(),
13273                        workspace::searchable::Direction::Next,
13274                    ),
13275                    SelectionGoal::None,
13276                )
13277            });
13278        })
13279    }
13280
13281    pub fn move_to_end_of_excerpt(
13282        &mut self,
13283        _: &MoveToEndOfExcerpt,
13284        window: &mut Window,
13285        cx: &mut Context<Self>,
13286    ) {
13287        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13288            cx.propagate();
13289            return;
13290        }
13291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13292        self.change_selections(Default::default(), window, cx, |s| {
13293            s.move_with(|map, selection| {
13294                selection.collapse_to(
13295                    movement::end_of_excerpt(
13296                        map,
13297                        selection.head(),
13298                        workspace::searchable::Direction::Next,
13299                    ),
13300                    SelectionGoal::None,
13301                )
13302            });
13303        })
13304    }
13305
13306    pub fn move_to_end_of_previous_excerpt(
13307        &mut self,
13308        _: &MoveToEndOfPreviousExcerpt,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13313            cx.propagate();
13314            return;
13315        }
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317        self.change_selections(Default::default(), window, cx, |s| {
13318            s.move_with(|map, selection| {
13319                selection.collapse_to(
13320                    movement::end_of_excerpt(
13321                        map,
13322                        selection.head(),
13323                        workspace::searchable::Direction::Prev,
13324                    ),
13325                    SelectionGoal::None,
13326                )
13327            });
13328        })
13329    }
13330
13331    pub fn select_to_start_of_excerpt(
13332        &mut self,
13333        _: &SelectToStartOfExcerpt,
13334        window: &mut Window,
13335        cx: &mut Context<Self>,
13336    ) {
13337        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13338            cx.propagate();
13339            return;
13340        }
13341        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13342        self.change_selections(Default::default(), window, cx, |s| {
13343            s.move_heads_with(|map, head, _| {
13344                (
13345                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13346                    SelectionGoal::None,
13347                )
13348            });
13349        })
13350    }
13351
13352    pub fn select_to_start_of_next_excerpt(
13353        &mut self,
13354        _: &SelectToStartOfNextExcerpt,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13359            cx.propagate();
13360            return;
13361        }
13362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13363        self.change_selections(Default::default(), window, cx, |s| {
13364            s.move_heads_with(|map, head, _| {
13365                (
13366                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13367                    SelectionGoal::None,
13368                )
13369            });
13370        })
13371    }
13372
13373    pub fn select_to_end_of_excerpt(
13374        &mut self,
13375        _: &SelectToEndOfExcerpt,
13376        window: &mut Window,
13377        cx: &mut Context<Self>,
13378    ) {
13379        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13380            cx.propagate();
13381            return;
13382        }
13383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13384        self.change_selections(Default::default(), window, cx, |s| {
13385            s.move_heads_with(|map, head, _| {
13386                (
13387                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13388                    SelectionGoal::None,
13389                )
13390            });
13391        })
13392    }
13393
13394    pub fn select_to_end_of_previous_excerpt(
13395        &mut self,
13396        _: &SelectToEndOfPreviousExcerpt,
13397        window: &mut Window,
13398        cx: &mut Context<Self>,
13399    ) {
13400        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13401            cx.propagate();
13402            return;
13403        }
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.move_heads_with(|map, head, _| {
13407                (
13408                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13409                    SelectionGoal::None,
13410                )
13411            });
13412        })
13413    }
13414
13415    pub fn move_to_beginning(
13416        &mut self,
13417        _: &MoveToBeginning,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13422            cx.propagate();
13423            return;
13424        }
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.select_ranges(vec![0..0]);
13428        });
13429    }
13430
13431    pub fn select_to_beginning(
13432        &mut self,
13433        _: &SelectToBeginning,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        let mut selection = self.selections.last::<Point>(cx);
13438        selection.set_head(Point::zero(), SelectionGoal::None);
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13440        self.change_selections(Default::default(), window, cx, |s| {
13441            s.select(vec![selection]);
13442        });
13443    }
13444
13445    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13446        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13447            cx.propagate();
13448            return;
13449        }
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13451        let cursor = self.buffer.read(cx).read(cx).len();
13452        self.change_selections(Default::default(), window, cx, |s| {
13453            s.select_ranges(vec![cursor..cursor])
13454        });
13455    }
13456
13457    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13458        self.nav_history = nav_history;
13459    }
13460
13461    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13462        self.nav_history.as_ref()
13463    }
13464
13465    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13466        self.push_to_nav_history(
13467            self.selections.newest_anchor().head(),
13468            None,
13469            false,
13470            true,
13471            cx,
13472        );
13473    }
13474
13475    fn push_to_nav_history(
13476        &mut self,
13477        cursor_anchor: Anchor,
13478        new_position: Option<Point>,
13479        is_deactivate: bool,
13480        always: bool,
13481        cx: &mut Context<Self>,
13482    ) {
13483        if let Some(nav_history) = self.nav_history.as_mut() {
13484            let buffer = self.buffer.read(cx).read(cx);
13485            let cursor_position = cursor_anchor.to_point(&buffer);
13486            let scroll_state = self.scroll_manager.anchor();
13487            let scroll_top_row = scroll_state.top_row(&buffer);
13488            drop(buffer);
13489
13490            if let Some(new_position) = new_position {
13491                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13492                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13493                    return;
13494                }
13495            }
13496
13497            nav_history.push(
13498                Some(NavigationData {
13499                    cursor_anchor,
13500                    cursor_position,
13501                    scroll_anchor: scroll_state,
13502                    scroll_top_row,
13503                }),
13504                cx,
13505            );
13506            cx.emit(EditorEvent::PushedToNavHistory {
13507                anchor: cursor_anchor,
13508                is_deactivate,
13509            })
13510        }
13511    }
13512
13513    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13515        let buffer = self.buffer.read(cx).snapshot(cx);
13516        let mut selection = self.selections.first::<usize>(cx);
13517        selection.set_head(buffer.len(), SelectionGoal::None);
13518        self.change_selections(Default::default(), window, cx, |s| {
13519            s.select(vec![selection]);
13520        });
13521    }
13522
13523    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13525        let end = self.buffer.read(cx).read(cx).len();
13526        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13527            s.select_ranges(vec![0..end]);
13528        });
13529    }
13530
13531    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13534        let mut selections = self.selections.all::<Point>(cx);
13535        let max_point = display_map.buffer_snapshot.max_point();
13536        for selection in &mut selections {
13537            let rows = selection.spanned_rows(true, &display_map);
13538            selection.start = Point::new(rows.start.0, 0);
13539            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13540            selection.reversed = false;
13541        }
13542        self.change_selections(Default::default(), window, cx, |s| {
13543            s.select(selections);
13544        });
13545    }
13546
13547    pub fn split_selection_into_lines(
13548        &mut self,
13549        _: &SplitSelectionIntoLines,
13550        window: &mut Window,
13551        cx: &mut Context<Self>,
13552    ) {
13553        let selections = self
13554            .selections
13555            .all::<Point>(cx)
13556            .into_iter()
13557            .map(|selection| selection.start..selection.end)
13558            .collect::<Vec<_>>();
13559        self.unfold_ranges(&selections, true, true, cx);
13560
13561        let mut new_selection_ranges = Vec::new();
13562        {
13563            let buffer = self.buffer.read(cx).read(cx);
13564            for selection in selections {
13565                for row in selection.start.row..selection.end.row {
13566                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13567                    new_selection_ranges.push(cursor..cursor);
13568                }
13569
13570                let is_multiline_selection = selection.start.row != selection.end.row;
13571                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13572                // so this action feels more ergonomic when paired with other selection operations
13573                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13574                if !should_skip_last {
13575                    new_selection_ranges.push(selection.end..selection.end);
13576                }
13577            }
13578        }
13579        self.change_selections(Default::default(), window, cx, |s| {
13580            s.select_ranges(new_selection_ranges);
13581        });
13582    }
13583
13584    pub fn add_selection_above(
13585        &mut self,
13586        _: &AddSelectionAbove,
13587        window: &mut Window,
13588        cx: &mut Context<Self>,
13589    ) {
13590        self.add_selection(true, window, cx);
13591    }
13592
13593    pub fn add_selection_below(
13594        &mut self,
13595        _: &AddSelectionBelow,
13596        window: &mut Window,
13597        cx: &mut Context<Self>,
13598    ) {
13599        self.add_selection(false, window, cx);
13600    }
13601
13602    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13604
13605        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13606        let all_selections = self.selections.all::<Point>(cx);
13607        let text_layout_details = self.text_layout_details(window);
13608
13609        let (mut columnar_selections, new_selections_to_columnarize) = {
13610            if let Some(state) = self.add_selections_state.as_ref() {
13611                let columnar_selection_ids: HashSet<_> = state
13612                    .groups
13613                    .iter()
13614                    .flat_map(|group| group.stack.iter())
13615                    .copied()
13616                    .collect();
13617
13618                all_selections
13619                    .into_iter()
13620                    .partition(|s| columnar_selection_ids.contains(&s.id))
13621            } else {
13622                (Vec::new(), all_selections)
13623            }
13624        };
13625
13626        let mut state = self
13627            .add_selections_state
13628            .take()
13629            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13630
13631        for selection in new_selections_to_columnarize {
13632            let range = selection.display_range(&display_map).sorted();
13633            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13634            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13635            let positions = start_x.min(end_x)..start_x.max(end_x);
13636            let mut stack = Vec::new();
13637            for row in range.start.row().0..=range.end.row().0 {
13638                if let Some(selection) = self.selections.build_columnar_selection(
13639                    &display_map,
13640                    DisplayRow(row),
13641                    &positions,
13642                    selection.reversed,
13643                    &text_layout_details,
13644                ) {
13645                    stack.push(selection.id);
13646                    columnar_selections.push(selection);
13647                }
13648            }
13649            if !stack.is_empty() {
13650                if above {
13651                    stack.reverse();
13652                }
13653                state.groups.push(AddSelectionsGroup { above, stack });
13654            }
13655        }
13656
13657        let mut final_selections = Vec::new();
13658        let end_row = if above {
13659            DisplayRow(0)
13660        } else {
13661            display_map.max_point().row()
13662        };
13663
13664        let mut last_added_item_per_group = HashMap::default();
13665        for group in state.groups.iter_mut() {
13666            if let Some(last_id) = group.stack.last() {
13667                last_added_item_per_group.insert(*last_id, group);
13668            }
13669        }
13670
13671        for selection in columnar_selections {
13672            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13673                if above == group.above {
13674                    let range = selection.display_range(&display_map).sorted();
13675                    debug_assert_eq!(range.start.row(), range.end.row());
13676                    let mut row = range.start.row();
13677                    let positions =
13678                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13679                            px(start)..px(end)
13680                        } else {
13681                            let start_x =
13682                                display_map.x_for_display_point(range.start, &text_layout_details);
13683                            let end_x =
13684                                display_map.x_for_display_point(range.end, &text_layout_details);
13685                            start_x.min(end_x)..start_x.max(end_x)
13686                        };
13687
13688                    let mut maybe_new_selection = None;
13689                    while row != end_row {
13690                        if above {
13691                            row.0 -= 1;
13692                        } else {
13693                            row.0 += 1;
13694                        }
13695                        if let Some(new_selection) = self.selections.build_columnar_selection(
13696                            &display_map,
13697                            row,
13698                            &positions,
13699                            selection.reversed,
13700                            &text_layout_details,
13701                        ) {
13702                            maybe_new_selection = Some(new_selection);
13703                            break;
13704                        }
13705                    }
13706
13707                    if let Some(new_selection) = maybe_new_selection {
13708                        group.stack.push(new_selection.id);
13709                        if above {
13710                            final_selections.push(new_selection);
13711                            final_selections.push(selection);
13712                        } else {
13713                            final_selections.push(selection);
13714                            final_selections.push(new_selection);
13715                        }
13716                    } else {
13717                        final_selections.push(selection);
13718                    }
13719                } else {
13720                    group.stack.pop();
13721                }
13722            } else {
13723                final_selections.push(selection);
13724            }
13725        }
13726
13727        self.change_selections(Default::default(), window, cx, |s| {
13728            s.select(final_selections);
13729        });
13730
13731        let final_selection_ids: HashSet<_> = self
13732            .selections
13733            .all::<Point>(cx)
13734            .iter()
13735            .map(|s| s.id)
13736            .collect();
13737        state.groups.retain_mut(|group| {
13738            // selections might get merged above so we remove invalid items from stacks
13739            group.stack.retain(|id| final_selection_ids.contains(id));
13740
13741            // single selection in stack can be treated as initial state
13742            group.stack.len() > 1
13743        });
13744
13745        if !state.groups.is_empty() {
13746            self.add_selections_state = Some(state);
13747        }
13748    }
13749
13750    fn select_match_ranges(
13751        &mut self,
13752        range: Range<usize>,
13753        reversed: bool,
13754        replace_newest: bool,
13755        auto_scroll: Option<Autoscroll>,
13756        window: &mut Window,
13757        cx: &mut Context<Editor>,
13758    ) {
13759        self.unfold_ranges(
13760            std::slice::from_ref(&range),
13761            false,
13762            auto_scroll.is_some(),
13763            cx,
13764        );
13765        let effects = if let Some(scroll) = auto_scroll {
13766            SelectionEffects::scroll(scroll)
13767        } else {
13768            SelectionEffects::no_scroll()
13769        };
13770        self.change_selections(effects, window, cx, |s| {
13771            if replace_newest {
13772                s.delete(s.newest_anchor().id);
13773            }
13774            if reversed {
13775                s.insert_range(range.end..range.start);
13776            } else {
13777                s.insert_range(range);
13778            }
13779        });
13780    }
13781
13782    pub fn select_next_match_internal(
13783        &mut self,
13784        display_map: &DisplaySnapshot,
13785        replace_newest: bool,
13786        autoscroll: Option<Autoscroll>,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) -> Result<()> {
13790        let buffer = &display_map.buffer_snapshot;
13791        let mut selections = self.selections.all::<usize>(cx);
13792        if let Some(mut select_next_state) = self.select_next_state.take() {
13793            let query = &select_next_state.query;
13794            if !select_next_state.done {
13795                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13796                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13797                let mut next_selected_range = None;
13798
13799                let bytes_after_last_selection =
13800                    buffer.bytes_in_range(last_selection.end..buffer.len());
13801                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13802                let query_matches = query
13803                    .stream_find_iter(bytes_after_last_selection)
13804                    .map(|result| (last_selection.end, result))
13805                    .chain(
13806                        query
13807                            .stream_find_iter(bytes_before_first_selection)
13808                            .map(|result| (0, result)),
13809                    );
13810
13811                for (start_offset, query_match) in query_matches {
13812                    let query_match = query_match.unwrap(); // can only fail due to I/O
13813                    let offset_range =
13814                        start_offset + query_match.start()..start_offset + query_match.end();
13815
13816                    if !select_next_state.wordwise
13817                        || (!buffer.is_inside_word(offset_range.start, false)
13818                            && !buffer.is_inside_word(offset_range.end, false))
13819                    {
13820                        // TODO: This is n^2, because we might check all the selections
13821                        if !selections
13822                            .iter()
13823                            .any(|selection| selection.range().overlaps(&offset_range))
13824                        {
13825                            next_selected_range = Some(offset_range);
13826                            break;
13827                        }
13828                    }
13829                }
13830
13831                if let Some(next_selected_range) = next_selected_range {
13832                    self.select_match_ranges(
13833                        next_selected_range,
13834                        last_selection.reversed,
13835                        replace_newest,
13836                        autoscroll,
13837                        window,
13838                        cx,
13839                    );
13840                } else {
13841                    select_next_state.done = true;
13842                }
13843            }
13844
13845            self.select_next_state = Some(select_next_state);
13846        } else {
13847            let mut only_carets = true;
13848            let mut same_text_selected = true;
13849            let mut selected_text = None;
13850
13851            let mut selections_iter = selections.iter().peekable();
13852            while let Some(selection) = selections_iter.next() {
13853                if selection.start != selection.end {
13854                    only_carets = false;
13855                }
13856
13857                if same_text_selected {
13858                    if selected_text.is_none() {
13859                        selected_text =
13860                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13861                    }
13862
13863                    if let Some(next_selection) = selections_iter.peek() {
13864                        if next_selection.range().len() == selection.range().len() {
13865                            let next_selected_text = buffer
13866                                .text_for_range(next_selection.range())
13867                                .collect::<String>();
13868                            if Some(next_selected_text) != selected_text {
13869                                same_text_selected = false;
13870                                selected_text = None;
13871                            }
13872                        } else {
13873                            same_text_selected = false;
13874                            selected_text = None;
13875                        }
13876                    }
13877                }
13878            }
13879
13880            if only_carets {
13881                for selection in &mut selections {
13882                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13883                    selection.start = word_range.start;
13884                    selection.end = word_range.end;
13885                    selection.goal = SelectionGoal::None;
13886                    selection.reversed = false;
13887                    self.select_match_ranges(
13888                        selection.start..selection.end,
13889                        selection.reversed,
13890                        replace_newest,
13891                        autoscroll,
13892                        window,
13893                        cx,
13894                    );
13895                }
13896
13897                if selections.len() == 1 {
13898                    let selection = selections
13899                        .last()
13900                        .expect("ensured that there's only one selection");
13901                    let query = buffer
13902                        .text_for_range(selection.start..selection.end)
13903                        .collect::<String>();
13904                    let is_empty = query.is_empty();
13905                    let select_state = SelectNextState {
13906                        query: AhoCorasick::new(&[query])?,
13907                        wordwise: true,
13908                        done: is_empty,
13909                    };
13910                    self.select_next_state = Some(select_state);
13911                } else {
13912                    self.select_next_state = None;
13913                }
13914            } else if let Some(selected_text) = selected_text {
13915                self.select_next_state = Some(SelectNextState {
13916                    query: AhoCorasick::new(&[selected_text])?,
13917                    wordwise: false,
13918                    done: false,
13919                });
13920                self.select_next_match_internal(
13921                    display_map,
13922                    replace_newest,
13923                    autoscroll,
13924                    window,
13925                    cx,
13926                )?;
13927            }
13928        }
13929        Ok(())
13930    }
13931
13932    pub fn select_all_matches(
13933        &mut self,
13934        _action: &SelectAllMatches,
13935        window: &mut Window,
13936        cx: &mut Context<Self>,
13937    ) -> Result<()> {
13938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13939
13940        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13941
13942        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13943        let Some(select_next_state) = self.select_next_state.as_mut() else {
13944            return Ok(());
13945        };
13946        if select_next_state.done {
13947            return Ok(());
13948        }
13949
13950        let mut new_selections = Vec::new();
13951
13952        let reversed = self.selections.oldest::<usize>(cx).reversed;
13953        let buffer = &display_map.buffer_snapshot;
13954        let query_matches = select_next_state
13955            .query
13956            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13957
13958        for query_match in query_matches.into_iter() {
13959            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13960            let offset_range = if reversed {
13961                query_match.end()..query_match.start()
13962            } else {
13963                query_match.start()..query_match.end()
13964            };
13965
13966            if !select_next_state.wordwise
13967                || (!buffer.is_inside_word(offset_range.start, false)
13968                    && !buffer.is_inside_word(offset_range.end, false))
13969            {
13970                new_selections.push(offset_range.start..offset_range.end);
13971            }
13972        }
13973
13974        select_next_state.done = true;
13975
13976        if new_selections.is_empty() {
13977            log::error!("bug: new_selections is empty in select_all_matches");
13978            return Ok(());
13979        }
13980
13981        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13982        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13983            selections.select_ranges(new_selections)
13984        });
13985
13986        Ok(())
13987    }
13988
13989    pub fn select_next(
13990        &mut self,
13991        action: &SelectNext,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) -> Result<()> {
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13997        self.select_next_match_internal(
13998            &display_map,
13999            action.replace_newest,
14000            Some(Autoscroll::newest()),
14001            window,
14002            cx,
14003        )?;
14004        Ok(())
14005    }
14006
14007    pub fn select_previous(
14008        &mut self,
14009        action: &SelectPrevious,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) -> Result<()> {
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14015        let buffer = &display_map.buffer_snapshot;
14016        let mut selections = self.selections.all::<usize>(cx);
14017        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14018            let query = &select_prev_state.query;
14019            if !select_prev_state.done {
14020                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14021                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14022                let mut next_selected_range = None;
14023                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14024                let bytes_before_last_selection =
14025                    buffer.reversed_bytes_in_range(0..last_selection.start);
14026                let bytes_after_first_selection =
14027                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14028                let query_matches = query
14029                    .stream_find_iter(bytes_before_last_selection)
14030                    .map(|result| (last_selection.start, result))
14031                    .chain(
14032                        query
14033                            .stream_find_iter(bytes_after_first_selection)
14034                            .map(|result| (buffer.len(), result)),
14035                    );
14036                for (end_offset, query_match) in query_matches {
14037                    let query_match = query_match.unwrap(); // can only fail due to I/O
14038                    let offset_range =
14039                        end_offset - query_match.end()..end_offset - query_match.start();
14040
14041                    if !select_prev_state.wordwise
14042                        || (!buffer.is_inside_word(offset_range.start, false)
14043                            && !buffer.is_inside_word(offset_range.end, false))
14044                    {
14045                        next_selected_range = Some(offset_range);
14046                        break;
14047                    }
14048                }
14049
14050                if let Some(next_selected_range) = next_selected_range {
14051                    self.select_match_ranges(
14052                        next_selected_range,
14053                        last_selection.reversed,
14054                        action.replace_newest,
14055                        Some(Autoscroll::newest()),
14056                        window,
14057                        cx,
14058                    );
14059                } else {
14060                    select_prev_state.done = true;
14061                }
14062            }
14063
14064            self.select_prev_state = Some(select_prev_state);
14065        } else {
14066            let mut only_carets = true;
14067            let mut same_text_selected = true;
14068            let mut selected_text = None;
14069
14070            let mut selections_iter = selections.iter().peekable();
14071            while let Some(selection) = selections_iter.next() {
14072                if selection.start != selection.end {
14073                    only_carets = false;
14074                }
14075
14076                if same_text_selected {
14077                    if selected_text.is_none() {
14078                        selected_text =
14079                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14080                    }
14081
14082                    if let Some(next_selection) = selections_iter.peek() {
14083                        if next_selection.range().len() == selection.range().len() {
14084                            let next_selected_text = buffer
14085                                .text_for_range(next_selection.range())
14086                                .collect::<String>();
14087                            if Some(next_selected_text) != selected_text {
14088                                same_text_selected = false;
14089                                selected_text = None;
14090                            }
14091                        } else {
14092                            same_text_selected = false;
14093                            selected_text = None;
14094                        }
14095                    }
14096                }
14097            }
14098
14099            if only_carets {
14100                for selection in &mut selections {
14101                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14102                    selection.start = word_range.start;
14103                    selection.end = word_range.end;
14104                    selection.goal = SelectionGoal::None;
14105                    selection.reversed = false;
14106                    self.select_match_ranges(
14107                        selection.start..selection.end,
14108                        selection.reversed,
14109                        action.replace_newest,
14110                        Some(Autoscroll::newest()),
14111                        window,
14112                        cx,
14113                    );
14114                }
14115                if selections.len() == 1 {
14116                    let selection = selections
14117                        .last()
14118                        .expect("ensured that there's only one selection");
14119                    let query = buffer
14120                        .text_for_range(selection.start..selection.end)
14121                        .collect::<String>();
14122                    let is_empty = query.is_empty();
14123                    let select_state = SelectNextState {
14124                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14125                        wordwise: true,
14126                        done: is_empty,
14127                    };
14128                    self.select_prev_state = Some(select_state);
14129                } else {
14130                    self.select_prev_state = None;
14131                }
14132            } else if let Some(selected_text) = selected_text {
14133                self.select_prev_state = Some(SelectNextState {
14134                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14135                    wordwise: false,
14136                    done: false,
14137                });
14138                self.select_previous(action, window, cx)?;
14139            }
14140        }
14141        Ok(())
14142    }
14143
14144    pub fn find_next_match(
14145        &mut self,
14146        _: &FindNextMatch,
14147        window: &mut Window,
14148        cx: &mut Context<Self>,
14149    ) -> Result<()> {
14150        let selections = self.selections.disjoint_anchors();
14151        match selections.first() {
14152            Some(first) if selections.len() >= 2 => {
14153                self.change_selections(Default::default(), window, cx, |s| {
14154                    s.select_ranges([first.range()]);
14155                });
14156            }
14157            _ => self.select_next(
14158                &SelectNext {
14159                    replace_newest: true,
14160                },
14161                window,
14162                cx,
14163            )?,
14164        }
14165        Ok(())
14166    }
14167
14168    pub fn find_previous_match(
14169        &mut self,
14170        _: &FindPreviousMatch,
14171        window: &mut Window,
14172        cx: &mut Context<Self>,
14173    ) -> Result<()> {
14174        let selections = self.selections.disjoint_anchors();
14175        match selections.last() {
14176            Some(last) if selections.len() >= 2 => {
14177                self.change_selections(Default::default(), window, cx, |s| {
14178                    s.select_ranges([last.range()]);
14179                });
14180            }
14181            _ => self.select_previous(
14182                &SelectPrevious {
14183                    replace_newest: true,
14184                },
14185                window,
14186                cx,
14187            )?,
14188        }
14189        Ok(())
14190    }
14191
14192    pub fn toggle_comments(
14193        &mut self,
14194        action: &ToggleComments,
14195        window: &mut Window,
14196        cx: &mut Context<Self>,
14197    ) {
14198        if self.read_only(cx) {
14199            return;
14200        }
14201        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14202        let text_layout_details = &self.text_layout_details(window);
14203        self.transact(window, cx, |this, window, cx| {
14204            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14205            let mut edits = Vec::new();
14206            let mut selection_edit_ranges = Vec::new();
14207            let mut last_toggled_row = None;
14208            let snapshot = this.buffer.read(cx).read(cx);
14209            let empty_str: Arc<str> = Arc::default();
14210            let mut suffixes_inserted = Vec::new();
14211            let ignore_indent = action.ignore_indent;
14212
14213            fn comment_prefix_range(
14214                snapshot: &MultiBufferSnapshot,
14215                row: MultiBufferRow,
14216                comment_prefix: &str,
14217                comment_prefix_whitespace: &str,
14218                ignore_indent: bool,
14219            ) -> Range<Point> {
14220                let indent_size = if ignore_indent {
14221                    0
14222                } else {
14223                    snapshot.indent_size_for_line(row).len
14224                };
14225
14226                let start = Point::new(row.0, indent_size);
14227
14228                let mut line_bytes = snapshot
14229                    .bytes_in_range(start..snapshot.max_point())
14230                    .flatten()
14231                    .copied();
14232
14233                // If this line currently begins with the line comment prefix, then record
14234                // the range containing the prefix.
14235                if line_bytes
14236                    .by_ref()
14237                    .take(comment_prefix.len())
14238                    .eq(comment_prefix.bytes())
14239                {
14240                    // Include any whitespace that matches the comment prefix.
14241                    let matching_whitespace_len = line_bytes
14242                        .zip(comment_prefix_whitespace.bytes())
14243                        .take_while(|(a, b)| a == b)
14244                        .count() as u32;
14245                    let end = Point::new(
14246                        start.row,
14247                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14248                    );
14249                    start..end
14250                } else {
14251                    start..start
14252                }
14253            }
14254
14255            fn comment_suffix_range(
14256                snapshot: &MultiBufferSnapshot,
14257                row: MultiBufferRow,
14258                comment_suffix: &str,
14259                comment_suffix_has_leading_space: bool,
14260            ) -> Range<Point> {
14261                let end = Point::new(row.0, snapshot.line_len(row));
14262                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14263
14264                let mut line_end_bytes = snapshot
14265                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14266                    .flatten()
14267                    .copied();
14268
14269                let leading_space_len = if suffix_start_column > 0
14270                    && line_end_bytes.next() == Some(b' ')
14271                    && comment_suffix_has_leading_space
14272                {
14273                    1
14274                } else {
14275                    0
14276                };
14277
14278                // If this line currently begins with the line comment prefix, then record
14279                // the range containing the prefix.
14280                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14281                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14282                    start..end
14283                } else {
14284                    end..end
14285                }
14286            }
14287
14288            // TODO: Handle selections that cross excerpts
14289            for selection in &mut selections {
14290                let start_column = snapshot
14291                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14292                    .len;
14293                let language = if let Some(language) =
14294                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14295                {
14296                    language
14297                } else {
14298                    continue;
14299                };
14300
14301                selection_edit_ranges.clear();
14302
14303                // If multiple selections contain a given row, avoid processing that
14304                // row more than once.
14305                let mut start_row = MultiBufferRow(selection.start.row);
14306                if last_toggled_row == Some(start_row) {
14307                    start_row = start_row.next_row();
14308                }
14309                let end_row =
14310                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14311                        MultiBufferRow(selection.end.row - 1)
14312                    } else {
14313                        MultiBufferRow(selection.end.row)
14314                    };
14315                last_toggled_row = Some(end_row);
14316
14317                if start_row > end_row {
14318                    continue;
14319                }
14320
14321                // If the language has line comments, toggle those.
14322                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14323
14324                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14325                if ignore_indent {
14326                    full_comment_prefixes = full_comment_prefixes
14327                        .into_iter()
14328                        .map(|s| Arc::from(s.trim_end()))
14329                        .collect();
14330                }
14331
14332                if !full_comment_prefixes.is_empty() {
14333                    let first_prefix = full_comment_prefixes
14334                        .first()
14335                        .expect("prefixes is non-empty");
14336                    let prefix_trimmed_lengths = full_comment_prefixes
14337                        .iter()
14338                        .map(|p| p.trim_end_matches(' ').len())
14339                        .collect::<SmallVec<[usize; 4]>>();
14340
14341                    let mut all_selection_lines_are_comments = true;
14342
14343                    for row in start_row.0..=end_row.0 {
14344                        let row = MultiBufferRow(row);
14345                        if start_row < end_row && snapshot.is_line_blank(row) {
14346                            continue;
14347                        }
14348
14349                        let prefix_range = full_comment_prefixes
14350                            .iter()
14351                            .zip(prefix_trimmed_lengths.iter().copied())
14352                            .map(|(prefix, trimmed_prefix_len)| {
14353                                comment_prefix_range(
14354                                    snapshot.deref(),
14355                                    row,
14356                                    &prefix[..trimmed_prefix_len],
14357                                    &prefix[trimmed_prefix_len..],
14358                                    ignore_indent,
14359                                )
14360                            })
14361                            .max_by_key(|range| range.end.column - range.start.column)
14362                            .expect("prefixes is non-empty");
14363
14364                        if prefix_range.is_empty() {
14365                            all_selection_lines_are_comments = false;
14366                        }
14367
14368                        selection_edit_ranges.push(prefix_range);
14369                    }
14370
14371                    if all_selection_lines_are_comments {
14372                        edits.extend(
14373                            selection_edit_ranges
14374                                .iter()
14375                                .cloned()
14376                                .map(|range| (range, empty_str.clone())),
14377                        );
14378                    } else {
14379                        let min_column = selection_edit_ranges
14380                            .iter()
14381                            .map(|range| range.start.column)
14382                            .min()
14383                            .unwrap_or(0);
14384                        edits.extend(selection_edit_ranges.iter().map(|range| {
14385                            let position = Point::new(range.start.row, min_column);
14386                            (position..position, first_prefix.clone())
14387                        }));
14388                    }
14389                } else if let Some(BlockCommentConfig {
14390                    start: full_comment_prefix,
14391                    end: comment_suffix,
14392                    ..
14393                }) = language.block_comment()
14394                {
14395                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14396                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14397                    let prefix_range = comment_prefix_range(
14398                        snapshot.deref(),
14399                        start_row,
14400                        comment_prefix,
14401                        comment_prefix_whitespace,
14402                        ignore_indent,
14403                    );
14404                    let suffix_range = comment_suffix_range(
14405                        snapshot.deref(),
14406                        end_row,
14407                        comment_suffix.trim_start_matches(' '),
14408                        comment_suffix.starts_with(' '),
14409                    );
14410
14411                    if prefix_range.is_empty() || suffix_range.is_empty() {
14412                        edits.push((
14413                            prefix_range.start..prefix_range.start,
14414                            full_comment_prefix.clone(),
14415                        ));
14416                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14417                        suffixes_inserted.push((end_row, comment_suffix.len()));
14418                    } else {
14419                        edits.push((prefix_range, empty_str.clone()));
14420                        edits.push((suffix_range, empty_str.clone()));
14421                    }
14422                } else {
14423                    continue;
14424                }
14425            }
14426
14427            drop(snapshot);
14428            this.buffer.update(cx, |buffer, cx| {
14429                buffer.edit(edits, None, cx);
14430            });
14431
14432            // Adjust selections so that they end before any comment suffixes that
14433            // were inserted.
14434            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14435            let mut selections = this.selections.all::<Point>(cx);
14436            let snapshot = this.buffer.read(cx).read(cx);
14437            for selection in &mut selections {
14438                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14439                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14440                        Ordering::Less => {
14441                            suffixes_inserted.next();
14442                            continue;
14443                        }
14444                        Ordering::Greater => break,
14445                        Ordering::Equal => {
14446                            if selection.end.column == snapshot.line_len(row) {
14447                                if selection.is_empty() {
14448                                    selection.start.column -= suffix_len as u32;
14449                                }
14450                                selection.end.column -= suffix_len as u32;
14451                            }
14452                            break;
14453                        }
14454                    }
14455                }
14456            }
14457
14458            drop(snapshot);
14459            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14460
14461            let selections = this.selections.all::<Point>(cx);
14462            let selections_on_single_row = selections.windows(2).all(|selections| {
14463                selections[0].start.row == selections[1].start.row
14464                    && selections[0].end.row == selections[1].end.row
14465                    && selections[0].start.row == selections[0].end.row
14466            });
14467            let selections_selecting = selections
14468                .iter()
14469                .any(|selection| selection.start != selection.end);
14470            let advance_downwards = action.advance_downwards
14471                && selections_on_single_row
14472                && !selections_selecting
14473                && !matches!(this.mode, EditorMode::SingleLine { .. });
14474
14475            if advance_downwards {
14476                let snapshot = this.buffer.read(cx).snapshot(cx);
14477
14478                this.change_selections(Default::default(), window, cx, |s| {
14479                    s.move_cursors_with(|display_snapshot, display_point, _| {
14480                        let mut point = display_point.to_point(display_snapshot);
14481                        point.row += 1;
14482                        point = snapshot.clip_point(point, Bias::Left);
14483                        let display_point = point.to_display_point(display_snapshot);
14484                        let goal = SelectionGoal::HorizontalPosition(
14485                            display_snapshot
14486                                .x_for_display_point(display_point, text_layout_details)
14487                                .into(),
14488                        );
14489                        (display_point, goal)
14490                    })
14491                });
14492            }
14493        });
14494    }
14495
14496    pub fn select_enclosing_symbol(
14497        &mut self,
14498        _: &SelectEnclosingSymbol,
14499        window: &mut Window,
14500        cx: &mut Context<Self>,
14501    ) {
14502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14503
14504        let buffer = self.buffer.read(cx).snapshot(cx);
14505        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14506
14507        fn update_selection(
14508            selection: &Selection<usize>,
14509            buffer_snap: &MultiBufferSnapshot,
14510        ) -> Option<Selection<usize>> {
14511            let cursor = selection.head();
14512            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14513            for symbol in symbols.iter().rev() {
14514                let start = symbol.range.start.to_offset(buffer_snap);
14515                let end = symbol.range.end.to_offset(buffer_snap);
14516                let new_range = start..end;
14517                if start < selection.start || end > selection.end {
14518                    return Some(Selection {
14519                        id: selection.id,
14520                        start: new_range.start,
14521                        end: new_range.end,
14522                        goal: SelectionGoal::None,
14523                        reversed: selection.reversed,
14524                    });
14525                }
14526            }
14527            None
14528        }
14529
14530        let mut selected_larger_symbol = false;
14531        let new_selections = old_selections
14532            .iter()
14533            .map(|selection| match update_selection(selection, &buffer) {
14534                Some(new_selection) => {
14535                    if new_selection.range() != selection.range() {
14536                        selected_larger_symbol = true;
14537                    }
14538                    new_selection
14539                }
14540                None => selection.clone(),
14541            })
14542            .collect::<Vec<_>>();
14543
14544        if selected_larger_symbol {
14545            self.change_selections(Default::default(), window, cx, |s| {
14546                s.select(new_selections);
14547            });
14548        }
14549    }
14550
14551    pub fn select_larger_syntax_node(
14552        &mut self,
14553        _: &SelectLargerSyntaxNode,
14554        window: &mut Window,
14555        cx: &mut Context<Self>,
14556    ) {
14557        let Some(visible_row_count) = self.visible_row_count() else {
14558            return;
14559        };
14560        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14561        if old_selections.is_empty() {
14562            return;
14563        }
14564
14565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14566
14567        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14568        let buffer = self.buffer.read(cx).snapshot(cx);
14569
14570        let mut selected_larger_node = false;
14571        let mut new_selections = old_selections
14572            .iter()
14573            .map(|selection| {
14574                let old_range = selection.start..selection.end;
14575
14576                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14577                    // manually select word at selection
14578                    if ["string_content", "inline"].contains(&node.kind()) {
14579                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14580                        // ignore if word is already selected
14581                        if !word_range.is_empty() && old_range != word_range {
14582                            let (last_word_range, _) =
14583                                buffer.surrounding_word(old_range.end, false);
14584                            // only select word if start and end point belongs to same word
14585                            if word_range == last_word_range {
14586                                selected_larger_node = true;
14587                                return Selection {
14588                                    id: selection.id,
14589                                    start: word_range.start,
14590                                    end: word_range.end,
14591                                    goal: SelectionGoal::None,
14592                                    reversed: selection.reversed,
14593                                };
14594                            }
14595                        }
14596                    }
14597                }
14598
14599                let mut new_range = old_range.clone();
14600                while let Some((_node, containing_range)) =
14601                    buffer.syntax_ancestor(new_range.clone())
14602                {
14603                    new_range = match containing_range {
14604                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14605                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14606                    };
14607                    if !display_map.intersects_fold(new_range.start)
14608                        && !display_map.intersects_fold(new_range.end)
14609                    {
14610                        break;
14611                    }
14612                }
14613
14614                selected_larger_node |= new_range != old_range;
14615                Selection {
14616                    id: selection.id,
14617                    start: new_range.start,
14618                    end: new_range.end,
14619                    goal: SelectionGoal::None,
14620                    reversed: selection.reversed,
14621                }
14622            })
14623            .collect::<Vec<_>>();
14624
14625        if !selected_larger_node {
14626            return; // don't put this call in the history
14627        }
14628
14629        // scroll based on transformation done to the last selection created by the user
14630        let (last_old, last_new) = old_selections
14631            .last()
14632            .zip(new_selections.last().cloned())
14633            .expect("old_selections isn't empty");
14634
14635        // revert selection
14636        let is_selection_reversed = {
14637            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14638            new_selections.last_mut().expect("checked above").reversed =
14639                should_newest_selection_be_reversed;
14640            should_newest_selection_be_reversed
14641        };
14642
14643        if selected_larger_node {
14644            self.select_syntax_node_history.disable_clearing = true;
14645            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14646                s.select(new_selections.clone());
14647            });
14648            self.select_syntax_node_history.disable_clearing = false;
14649        }
14650
14651        let start_row = last_new.start.to_display_point(&display_map).row().0;
14652        let end_row = last_new.end.to_display_point(&display_map).row().0;
14653        let selection_height = end_row - start_row + 1;
14654        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14655
14656        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14657        let scroll_behavior = if fits_on_the_screen {
14658            self.request_autoscroll(Autoscroll::fit(), cx);
14659            SelectSyntaxNodeScrollBehavior::FitSelection
14660        } else if is_selection_reversed {
14661            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14662            SelectSyntaxNodeScrollBehavior::CursorTop
14663        } else {
14664            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14665            SelectSyntaxNodeScrollBehavior::CursorBottom
14666        };
14667
14668        self.select_syntax_node_history.push((
14669            old_selections,
14670            scroll_behavior,
14671            is_selection_reversed,
14672        ));
14673    }
14674
14675    pub fn select_smaller_syntax_node(
14676        &mut self,
14677        _: &SelectSmallerSyntaxNode,
14678        window: &mut Window,
14679        cx: &mut Context<Self>,
14680    ) {
14681        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14682
14683        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14684            self.select_syntax_node_history.pop()
14685        {
14686            if let Some(selection) = selections.last_mut() {
14687                selection.reversed = is_selection_reversed;
14688            }
14689
14690            self.select_syntax_node_history.disable_clearing = true;
14691            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14692                s.select(selections.to_vec());
14693            });
14694            self.select_syntax_node_history.disable_clearing = false;
14695
14696            match scroll_behavior {
14697                SelectSyntaxNodeScrollBehavior::CursorTop => {
14698                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14699                }
14700                SelectSyntaxNodeScrollBehavior::FitSelection => {
14701                    self.request_autoscroll(Autoscroll::fit(), cx);
14702                }
14703                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14704                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14705                }
14706            }
14707        }
14708    }
14709
14710    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14711        if !EditorSettings::get_global(cx).gutter.runnables {
14712            self.clear_tasks();
14713            return Task::ready(());
14714        }
14715        let project = self.project.as_ref().map(Entity::downgrade);
14716        let task_sources = self.lsp_task_sources(cx);
14717        let multi_buffer = self.buffer.downgrade();
14718        cx.spawn_in(window, async move |editor, cx| {
14719            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14720            let Some(project) = project.and_then(|p| p.upgrade()) else {
14721                return;
14722            };
14723            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14724                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14725            }) else {
14726                return;
14727            };
14728
14729            let hide_runnables = project
14730                .update(cx, |project, cx| {
14731                    // Do not display any test indicators in non-dev server remote projects.
14732                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14733                })
14734                .unwrap_or(true);
14735            if hide_runnables {
14736                return;
14737            }
14738            let new_rows =
14739                cx.background_spawn({
14740                    let snapshot = display_snapshot.clone();
14741                    async move {
14742                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14743                    }
14744                })
14745                    .await;
14746            let Ok(lsp_tasks) =
14747                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14748            else {
14749                return;
14750            };
14751            let lsp_tasks = lsp_tasks.await;
14752
14753            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14754                lsp_tasks
14755                    .into_iter()
14756                    .flat_map(|(kind, tasks)| {
14757                        tasks.into_iter().filter_map(move |(location, task)| {
14758                            Some((kind.clone(), location?, task))
14759                        })
14760                    })
14761                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14762                        let buffer = location.target.buffer;
14763                        let buffer_snapshot = buffer.read(cx).snapshot();
14764                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14765                            |(excerpt_id, snapshot, _)| {
14766                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14767                                    display_snapshot
14768                                        .buffer_snapshot
14769                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14770                                } else {
14771                                    None
14772                                }
14773                            },
14774                        );
14775                        if let Some(offset) = offset {
14776                            let task_buffer_range =
14777                                location.target.range.to_point(&buffer_snapshot);
14778                            let context_buffer_range =
14779                                task_buffer_range.to_offset(&buffer_snapshot);
14780                            let context_range = BufferOffset(context_buffer_range.start)
14781                                ..BufferOffset(context_buffer_range.end);
14782
14783                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14784                                .or_insert_with(|| RunnableTasks {
14785                                    templates: Vec::new(),
14786                                    offset,
14787                                    column: task_buffer_range.start.column,
14788                                    extra_variables: HashMap::default(),
14789                                    context_range,
14790                                })
14791                                .templates
14792                                .push((kind, task.original_task().clone()));
14793                        }
14794
14795                        acc
14796                    })
14797            }) else {
14798                return;
14799            };
14800
14801            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14802                buffer.language_settings(cx).tasks.prefer_lsp
14803            }) else {
14804                return;
14805            };
14806
14807            let rows = Self::runnable_rows(
14808                project,
14809                display_snapshot,
14810                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14811                new_rows,
14812                cx.clone(),
14813            )
14814            .await;
14815            editor
14816                .update(cx, |editor, _| {
14817                    editor.clear_tasks();
14818                    for (key, mut value) in rows {
14819                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14820                            value.templates.extend(lsp_tasks.templates);
14821                        }
14822
14823                        editor.insert_tasks(key, value);
14824                    }
14825                    for (key, value) in lsp_tasks_by_rows {
14826                        editor.insert_tasks(key, value);
14827                    }
14828                })
14829                .ok();
14830        })
14831    }
14832    fn fetch_runnable_ranges(
14833        snapshot: &DisplaySnapshot,
14834        range: Range<Anchor>,
14835    ) -> Vec<language::RunnableRange> {
14836        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14837    }
14838
14839    fn runnable_rows(
14840        project: Entity<Project>,
14841        snapshot: DisplaySnapshot,
14842        prefer_lsp: bool,
14843        runnable_ranges: Vec<RunnableRange>,
14844        cx: AsyncWindowContext,
14845    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14846        cx.spawn(async move |cx| {
14847            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14848            for mut runnable in runnable_ranges {
14849                let Some(tasks) = cx
14850                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14851                    .ok()
14852                else {
14853                    continue;
14854                };
14855                let mut tasks = tasks.await;
14856
14857                if prefer_lsp {
14858                    tasks.retain(|(task_kind, _)| {
14859                        !matches!(task_kind, TaskSourceKind::Language { .. })
14860                    });
14861                }
14862                if tasks.is_empty() {
14863                    continue;
14864                }
14865
14866                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14867                let Some(row) = snapshot
14868                    .buffer_snapshot
14869                    .buffer_line_for_row(MultiBufferRow(point.row))
14870                    .map(|(_, range)| range.start.row)
14871                else {
14872                    continue;
14873                };
14874
14875                let context_range =
14876                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14877                runnable_rows.push((
14878                    (runnable.buffer_id, row),
14879                    RunnableTasks {
14880                        templates: tasks,
14881                        offset: snapshot
14882                            .buffer_snapshot
14883                            .anchor_before(runnable.run_range.start),
14884                        context_range,
14885                        column: point.column,
14886                        extra_variables: runnable.extra_captures,
14887                    },
14888                ));
14889            }
14890            runnable_rows
14891        })
14892    }
14893
14894    fn templates_with_tags(
14895        project: &Entity<Project>,
14896        runnable: &mut Runnable,
14897        cx: &mut App,
14898    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14899        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14900            let (worktree_id, file) = project
14901                .buffer_for_id(runnable.buffer, cx)
14902                .and_then(|buffer| buffer.read(cx).file())
14903                .map(|file| (file.worktree_id(cx), file.clone()))
14904                .unzip();
14905
14906            (
14907                project.task_store().read(cx).task_inventory().cloned(),
14908                worktree_id,
14909                file,
14910            )
14911        });
14912
14913        let tags = mem::take(&mut runnable.tags);
14914        let language = runnable.language.clone();
14915        cx.spawn(async move |cx| {
14916            let mut templates_with_tags = Vec::new();
14917            if let Some(inventory) = inventory {
14918                for RunnableTag(tag) in tags {
14919                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14920                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14921                    }) else {
14922                        return templates_with_tags;
14923                    };
14924                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14925                        move |(_, template)| {
14926                            template.tags.iter().any(|source_tag| source_tag == &tag)
14927                        },
14928                    ));
14929                }
14930            }
14931            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14932
14933            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14934                // Strongest source wins; if we have worktree tag binding, prefer that to
14935                // global and language bindings;
14936                // if we have a global binding, prefer that to language binding.
14937                let first_mismatch = templates_with_tags
14938                    .iter()
14939                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14940                if let Some(index) = first_mismatch {
14941                    templates_with_tags.truncate(index);
14942                }
14943            }
14944
14945            templates_with_tags
14946        })
14947    }
14948
14949    pub fn move_to_enclosing_bracket(
14950        &mut self,
14951        _: &MoveToEnclosingBracket,
14952        window: &mut Window,
14953        cx: &mut Context<Self>,
14954    ) {
14955        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14956        self.change_selections(Default::default(), window, cx, |s| {
14957            s.move_offsets_with(|snapshot, selection| {
14958                let Some(enclosing_bracket_ranges) =
14959                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14960                else {
14961                    return;
14962                };
14963
14964                let mut best_length = usize::MAX;
14965                let mut best_inside = false;
14966                let mut best_in_bracket_range = false;
14967                let mut best_destination = None;
14968                for (open, close) in enclosing_bracket_ranges {
14969                    let close = close.to_inclusive();
14970                    let length = close.end() - open.start;
14971                    let inside = selection.start >= open.end && selection.end <= *close.start();
14972                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14973                        || close.contains(&selection.head());
14974
14975                    // If best is next to a bracket and current isn't, skip
14976                    if !in_bracket_range && best_in_bracket_range {
14977                        continue;
14978                    }
14979
14980                    // Prefer smaller lengths unless best is inside and current isn't
14981                    if length > best_length && (best_inside || !inside) {
14982                        continue;
14983                    }
14984
14985                    best_length = length;
14986                    best_inside = inside;
14987                    best_in_bracket_range = in_bracket_range;
14988                    best_destination = Some(
14989                        if close.contains(&selection.start) && close.contains(&selection.end) {
14990                            if inside { open.end } else { open.start }
14991                        } else if inside {
14992                            *close.start()
14993                        } else {
14994                            *close.end()
14995                        },
14996                    );
14997                }
14998
14999                if let Some(destination) = best_destination {
15000                    selection.collapse_to(destination, SelectionGoal::None);
15001                }
15002            })
15003        });
15004    }
15005
15006    pub fn undo_selection(
15007        &mut self,
15008        _: &UndoSelection,
15009        window: &mut Window,
15010        cx: &mut Context<Self>,
15011    ) {
15012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15013        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15014            self.selection_history.mode = SelectionHistoryMode::Undoing;
15015            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15016                this.end_selection(window, cx);
15017                this.change_selections(
15018                    SelectionEffects::scroll(Autoscroll::newest()),
15019                    window,
15020                    cx,
15021                    |s| s.select_anchors(entry.selections.to_vec()),
15022                );
15023            });
15024            self.selection_history.mode = SelectionHistoryMode::Normal;
15025
15026            self.select_next_state = entry.select_next_state;
15027            self.select_prev_state = entry.select_prev_state;
15028            self.add_selections_state = entry.add_selections_state;
15029        }
15030    }
15031
15032    pub fn redo_selection(
15033        &mut self,
15034        _: &RedoSelection,
15035        window: &mut Window,
15036        cx: &mut Context<Self>,
15037    ) {
15038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15039        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15040            self.selection_history.mode = SelectionHistoryMode::Redoing;
15041            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15042                this.end_selection(window, cx);
15043                this.change_selections(
15044                    SelectionEffects::scroll(Autoscroll::newest()),
15045                    window,
15046                    cx,
15047                    |s| s.select_anchors(entry.selections.to_vec()),
15048                );
15049            });
15050            self.selection_history.mode = SelectionHistoryMode::Normal;
15051
15052            self.select_next_state = entry.select_next_state;
15053            self.select_prev_state = entry.select_prev_state;
15054            self.add_selections_state = entry.add_selections_state;
15055        }
15056    }
15057
15058    pub fn expand_excerpts(
15059        &mut self,
15060        action: &ExpandExcerpts,
15061        _: &mut Window,
15062        cx: &mut Context<Self>,
15063    ) {
15064        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15065    }
15066
15067    pub fn expand_excerpts_down(
15068        &mut self,
15069        action: &ExpandExcerptsDown,
15070        _: &mut Window,
15071        cx: &mut Context<Self>,
15072    ) {
15073        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15074    }
15075
15076    pub fn expand_excerpts_up(
15077        &mut self,
15078        action: &ExpandExcerptsUp,
15079        _: &mut Window,
15080        cx: &mut Context<Self>,
15081    ) {
15082        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15083    }
15084
15085    pub fn expand_excerpts_for_direction(
15086        &mut self,
15087        lines: u32,
15088        direction: ExpandExcerptDirection,
15089
15090        cx: &mut Context<Self>,
15091    ) {
15092        let selections = self.selections.disjoint_anchors();
15093
15094        let lines = if lines == 0 {
15095            EditorSettings::get_global(cx).expand_excerpt_lines
15096        } else {
15097            lines
15098        };
15099
15100        self.buffer.update(cx, |buffer, cx| {
15101            let snapshot = buffer.snapshot(cx);
15102            let mut excerpt_ids = selections
15103                .iter()
15104                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15105                .collect::<Vec<_>>();
15106            excerpt_ids.sort();
15107            excerpt_ids.dedup();
15108            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15109        })
15110    }
15111
15112    pub fn expand_excerpt(
15113        &mut self,
15114        excerpt: ExcerptId,
15115        direction: ExpandExcerptDirection,
15116        window: &mut Window,
15117        cx: &mut Context<Self>,
15118    ) {
15119        let current_scroll_position = self.scroll_position(cx);
15120        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15121        let mut should_scroll_up = false;
15122
15123        if direction == ExpandExcerptDirection::Down {
15124            let multi_buffer = self.buffer.read(cx);
15125            let snapshot = multi_buffer.snapshot(cx);
15126            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15127                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15128                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15129                        let buffer_snapshot = buffer.read(cx).snapshot();
15130                        let excerpt_end_row =
15131                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15132                        let last_row = buffer_snapshot.max_point().row;
15133                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15134                        should_scroll_up = lines_below >= lines_to_expand;
15135                    }
15136                }
15137            }
15138        }
15139
15140        self.buffer.update(cx, |buffer, cx| {
15141            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15142        });
15143
15144        if should_scroll_up {
15145            let new_scroll_position =
15146                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15147            self.set_scroll_position(new_scroll_position, window, cx);
15148        }
15149    }
15150
15151    pub fn go_to_singleton_buffer_point(
15152        &mut self,
15153        point: Point,
15154        window: &mut Window,
15155        cx: &mut Context<Self>,
15156    ) {
15157        self.go_to_singleton_buffer_range(point..point, window, cx);
15158    }
15159
15160    pub fn go_to_singleton_buffer_range(
15161        &mut self,
15162        range: Range<Point>,
15163        window: &mut Window,
15164        cx: &mut Context<Self>,
15165    ) {
15166        let multibuffer = self.buffer().read(cx);
15167        let Some(buffer) = multibuffer.as_singleton() else {
15168            return;
15169        };
15170        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15171            return;
15172        };
15173        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15174            return;
15175        };
15176        self.change_selections(
15177            SelectionEffects::default().nav_history(true),
15178            window,
15179            cx,
15180            |s| s.select_anchor_ranges([start..end]),
15181        );
15182    }
15183
15184    pub fn go_to_diagnostic(
15185        &mut self,
15186        action: &GoToDiagnostic,
15187        window: &mut Window,
15188        cx: &mut Context<Self>,
15189    ) {
15190        if !self.diagnostics_enabled() {
15191            return;
15192        }
15193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15194        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15195    }
15196
15197    pub fn go_to_prev_diagnostic(
15198        &mut self,
15199        action: &GoToPreviousDiagnostic,
15200        window: &mut Window,
15201        cx: &mut Context<Self>,
15202    ) {
15203        if !self.diagnostics_enabled() {
15204            return;
15205        }
15206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15207        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15208    }
15209
15210    pub fn go_to_diagnostic_impl(
15211        &mut self,
15212        direction: Direction,
15213        severity: GoToDiagnosticSeverityFilter,
15214        window: &mut Window,
15215        cx: &mut Context<Self>,
15216    ) {
15217        let buffer = self.buffer.read(cx).snapshot(cx);
15218        let selection = self.selections.newest::<usize>(cx);
15219
15220        let mut active_group_id = None;
15221        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15222            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15223                active_group_id = Some(active_group.group_id);
15224            }
15225        }
15226
15227        fn filtered(
15228            snapshot: EditorSnapshot,
15229            severity: GoToDiagnosticSeverityFilter,
15230            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15231        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15232            diagnostics
15233                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15234                .filter(|entry| entry.range.start != entry.range.end)
15235                .filter(|entry| !entry.diagnostic.is_unnecessary)
15236                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15237        }
15238
15239        let snapshot = self.snapshot(window, cx);
15240        let before = filtered(
15241            snapshot.clone(),
15242            severity,
15243            buffer
15244                .diagnostics_in_range(0..selection.start)
15245                .filter(|entry| entry.range.start <= selection.start),
15246        );
15247        let after = filtered(
15248            snapshot,
15249            severity,
15250            buffer
15251                .diagnostics_in_range(selection.start..buffer.len())
15252                .filter(|entry| entry.range.start >= selection.start),
15253        );
15254
15255        let mut found: Option<DiagnosticEntry<usize>> = None;
15256        if direction == Direction::Prev {
15257            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15258            {
15259                for diagnostic in prev_diagnostics.into_iter().rev() {
15260                    if diagnostic.range.start != selection.start
15261                        || active_group_id
15262                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15263                    {
15264                        found = Some(diagnostic);
15265                        break 'outer;
15266                    }
15267                }
15268            }
15269        } else {
15270            for diagnostic in after.chain(before) {
15271                if diagnostic.range.start != selection.start
15272                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15273                {
15274                    found = Some(diagnostic);
15275                    break;
15276                }
15277            }
15278        }
15279        let Some(next_diagnostic) = found else {
15280            return;
15281        };
15282
15283        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15284            return;
15285        };
15286        self.change_selections(Default::default(), window, cx, |s| {
15287            s.select_ranges(vec![
15288                next_diagnostic.range.start..next_diagnostic.range.start,
15289            ])
15290        });
15291        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15292        self.refresh_edit_prediction(false, true, window, cx);
15293    }
15294
15295    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15296        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15297        let snapshot = self.snapshot(window, cx);
15298        let selection = self.selections.newest::<Point>(cx);
15299        self.go_to_hunk_before_or_after_position(
15300            &snapshot,
15301            selection.head(),
15302            Direction::Next,
15303            window,
15304            cx,
15305        );
15306    }
15307
15308    pub fn go_to_hunk_before_or_after_position(
15309        &mut self,
15310        snapshot: &EditorSnapshot,
15311        position: Point,
15312        direction: Direction,
15313        window: &mut Window,
15314        cx: &mut Context<Editor>,
15315    ) {
15316        let row = if direction == Direction::Next {
15317            self.hunk_after_position(snapshot, position)
15318                .map(|hunk| hunk.row_range.start)
15319        } else {
15320            self.hunk_before_position(snapshot, position)
15321        };
15322
15323        if let Some(row) = row {
15324            let destination = Point::new(row.0, 0);
15325            let autoscroll = Autoscroll::center();
15326
15327            self.unfold_ranges(&[destination..destination], false, false, cx);
15328            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15329                s.select_ranges([destination..destination]);
15330            });
15331        }
15332    }
15333
15334    fn hunk_after_position(
15335        &mut self,
15336        snapshot: &EditorSnapshot,
15337        position: Point,
15338    ) -> Option<MultiBufferDiffHunk> {
15339        snapshot
15340            .buffer_snapshot
15341            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15342            .find(|hunk| hunk.row_range.start.0 > position.row)
15343            .or_else(|| {
15344                snapshot
15345                    .buffer_snapshot
15346                    .diff_hunks_in_range(Point::zero()..position)
15347                    .find(|hunk| hunk.row_range.end.0 < position.row)
15348            })
15349    }
15350
15351    fn go_to_prev_hunk(
15352        &mut self,
15353        _: &GoToPreviousHunk,
15354        window: &mut Window,
15355        cx: &mut Context<Self>,
15356    ) {
15357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15358        let snapshot = self.snapshot(window, cx);
15359        let selection = self.selections.newest::<Point>(cx);
15360        self.go_to_hunk_before_or_after_position(
15361            &snapshot,
15362            selection.head(),
15363            Direction::Prev,
15364            window,
15365            cx,
15366        );
15367    }
15368
15369    fn hunk_before_position(
15370        &mut self,
15371        snapshot: &EditorSnapshot,
15372        position: Point,
15373    ) -> Option<MultiBufferRow> {
15374        snapshot
15375            .buffer_snapshot
15376            .diff_hunk_before(position)
15377            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15378    }
15379
15380    fn go_to_next_change(
15381        &mut self,
15382        _: &GoToNextChange,
15383        window: &mut Window,
15384        cx: &mut Context<Self>,
15385    ) {
15386        if let Some(selections) = self
15387            .change_list
15388            .next_change(1, Direction::Next)
15389            .map(|s| s.to_vec())
15390        {
15391            self.change_selections(Default::default(), window, cx, |s| {
15392                let map = s.display_map();
15393                s.select_display_ranges(selections.iter().map(|a| {
15394                    let point = a.to_display_point(&map);
15395                    point..point
15396                }))
15397            })
15398        }
15399    }
15400
15401    fn go_to_previous_change(
15402        &mut self,
15403        _: &GoToPreviousChange,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) {
15407        if let Some(selections) = self
15408            .change_list
15409            .next_change(1, Direction::Prev)
15410            .map(|s| s.to_vec())
15411        {
15412            self.change_selections(Default::default(), window, cx, |s| {
15413                let map = s.display_map();
15414                s.select_display_ranges(selections.iter().map(|a| {
15415                    let point = a.to_display_point(&map);
15416                    point..point
15417                }))
15418            })
15419        }
15420    }
15421
15422    fn go_to_line<T: 'static>(
15423        &mut self,
15424        position: Anchor,
15425        highlight_color: Option<Hsla>,
15426        window: &mut Window,
15427        cx: &mut Context<Self>,
15428    ) {
15429        let snapshot = self.snapshot(window, cx).display_snapshot;
15430        let position = position.to_point(&snapshot.buffer_snapshot);
15431        let start = snapshot
15432            .buffer_snapshot
15433            .clip_point(Point::new(position.row, 0), Bias::Left);
15434        let end = start + Point::new(1, 0);
15435        let start = snapshot.buffer_snapshot.anchor_before(start);
15436        let end = snapshot.buffer_snapshot.anchor_before(end);
15437
15438        self.highlight_rows::<T>(
15439            start..end,
15440            highlight_color
15441                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15442            Default::default(),
15443            cx,
15444        );
15445
15446        if self.buffer.read(cx).is_singleton() {
15447            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15448        }
15449    }
15450
15451    pub fn go_to_definition(
15452        &mut self,
15453        _: &GoToDefinition,
15454        window: &mut Window,
15455        cx: &mut Context<Self>,
15456    ) -> Task<Result<Navigated>> {
15457        let definition =
15458            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15459        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15460        cx.spawn_in(window, async move |editor, cx| {
15461            if definition.await? == Navigated::Yes {
15462                return Ok(Navigated::Yes);
15463            }
15464            match fallback_strategy {
15465                GoToDefinitionFallback::None => Ok(Navigated::No),
15466                GoToDefinitionFallback::FindAllReferences => {
15467                    match editor.update_in(cx, |editor, window, cx| {
15468                        editor.find_all_references(&FindAllReferences, window, cx)
15469                    })? {
15470                        Some(references) => references.await,
15471                        None => Ok(Navigated::No),
15472                    }
15473                }
15474            }
15475        })
15476    }
15477
15478    pub fn go_to_declaration(
15479        &mut self,
15480        _: &GoToDeclaration,
15481        window: &mut Window,
15482        cx: &mut Context<Self>,
15483    ) -> Task<Result<Navigated>> {
15484        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15485    }
15486
15487    pub fn go_to_declaration_split(
15488        &mut self,
15489        _: &GoToDeclaration,
15490        window: &mut Window,
15491        cx: &mut Context<Self>,
15492    ) -> Task<Result<Navigated>> {
15493        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15494    }
15495
15496    pub fn go_to_implementation(
15497        &mut self,
15498        _: &GoToImplementation,
15499        window: &mut Window,
15500        cx: &mut Context<Self>,
15501    ) -> Task<Result<Navigated>> {
15502        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15503    }
15504
15505    pub fn go_to_implementation_split(
15506        &mut self,
15507        _: &GoToImplementationSplit,
15508        window: &mut Window,
15509        cx: &mut Context<Self>,
15510    ) -> Task<Result<Navigated>> {
15511        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15512    }
15513
15514    pub fn go_to_type_definition(
15515        &mut self,
15516        _: &GoToTypeDefinition,
15517        window: &mut Window,
15518        cx: &mut Context<Self>,
15519    ) -> Task<Result<Navigated>> {
15520        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15521    }
15522
15523    pub fn go_to_definition_split(
15524        &mut self,
15525        _: &GoToDefinitionSplit,
15526        window: &mut Window,
15527        cx: &mut Context<Self>,
15528    ) -> Task<Result<Navigated>> {
15529        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15530    }
15531
15532    pub fn go_to_type_definition_split(
15533        &mut self,
15534        _: &GoToTypeDefinitionSplit,
15535        window: &mut Window,
15536        cx: &mut Context<Self>,
15537    ) -> Task<Result<Navigated>> {
15538        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15539    }
15540
15541    fn go_to_definition_of_kind(
15542        &mut self,
15543        kind: GotoDefinitionKind,
15544        split: bool,
15545        window: &mut Window,
15546        cx: &mut Context<Self>,
15547    ) -> Task<Result<Navigated>> {
15548        let Some(provider) = self.semantics_provider.clone() else {
15549            return Task::ready(Ok(Navigated::No));
15550        };
15551        let head = self.selections.newest::<usize>(cx).head();
15552        let buffer = self.buffer.read(cx);
15553        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15554            text_anchor
15555        } else {
15556            return Task::ready(Ok(Navigated::No));
15557        };
15558
15559        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15560            return Task::ready(Ok(Navigated::No));
15561        };
15562
15563        cx.spawn_in(window, async move |editor, cx| {
15564            let definitions = definitions.await?;
15565            let navigated = editor
15566                .update_in(cx, |editor, window, cx| {
15567                    editor.navigate_to_hover_links(
15568                        Some(kind),
15569                        definitions
15570                            .into_iter()
15571                            .filter(|location| {
15572                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15573                            })
15574                            .map(HoverLink::Text)
15575                            .collect::<Vec<_>>(),
15576                        split,
15577                        window,
15578                        cx,
15579                    )
15580                })?
15581                .await?;
15582            anyhow::Ok(navigated)
15583        })
15584    }
15585
15586    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15587        let selection = self.selections.newest_anchor();
15588        let head = selection.head();
15589        let tail = selection.tail();
15590
15591        let Some((buffer, start_position)) =
15592            self.buffer.read(cx).text_anchor_for_position(head, cx)
15593        else {
15594            return;
15595        };
15596
15597        let end_position = if head != tail {
15598            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15599                return;
15600            };
15601            Some(pos)
15602        } else {
15603            None
15604        };
15605
15606        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15607            let url = if let Some(end_pos) = end_position {
15608                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15609            } else {
15610                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15611            };
15612
15613            if let Some(url) = url {
15614                editor.update(cx, |_, cx| {
15615                    cx.open_url(&url);
15616                })
15617            } else {
15618                Ok(())
15619            }
15620        });
15621
15622        url_finder.detach();
15623    }
15624
15625    pub fn open_selected_filename(
15626        &mut self,
15627        _: &OpenSelectedFilename,
15628        window: &mut Window,
15629        cx: &mut Context<Self>,
15630    ) {
15631        let Some(workspace) = self.workspace() else {
15632            return;
15633        };
15634
15635        let position = self.selections.newest_anchor().head();
15636
15637        let Some((buffer, buffer_position)) =
15638            self.buffer.read(cx).text_anchor_for_position(position, cx)
15639        else {
15640            return;
15641        };
15642
15643        let project = self.project.clone();
15644
15645        cx.spawn_in(window, async move |_, cx| {
15646            let result = find_file(&buffer, project, buffer_position, cx).await;
15647
15648            if let Some((_, path)) = result {
15649                workspace
15650                    .update_in(cx, |workspace, window, cx| {
15651                        workspace.open_resolved_path(path, window, cx)
15652                    })?
15653                    .await?;
15654            }
15655            anyhow::Ok(())
15656        })
15657        .detach();
15658    }
15659
15660    pub(crate) fn navigate_to_hover_links(
15661        &mut self,
15662        kind: Option<GotoDefinitionKind>,
15663        mut definitions: Vec<HoverLink>,
15664        split: bool,
15665        window: &mut Window,
15666        cx: &mut Context<Editor>,
15667    ) -> Task<Result<Navigated>> {
15668        // If there is one definition, just open it directly
15669        if definitions.len() == 1 {
15670            let definition = definitions.pop().unwrap();
15671
15672            enum TargetTaskResult {
15673                Location(Option<Location>),
15674                AlreadyNavigated,
15675            }
15676
15677            let target_task = match definition {
15678                HoverLink::Text(link) => {
15679                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15680                }
15681                HoverLink::InlayHint(lsp_location, server_id) => {
15682                    let computation =
15683                        self.compute_target_location(lsp_location, server_id, window, cx);
15684                    cx.background_spawn(async move {
15685                        let location = computation.await?;
15686                        Ok(TargetTaskResult::Location(location))
15687                    })
15688                }
15689                HoverLink::Url(url) => {
15690                    cx.open_url(&url);
15691                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15692                }
15693                HoverLink::File(path) => {
15694                    if let Some(workspace) = self.workspace() {
15695                        cx.spawn_in(window, async move |_, cx| {
15696                            workspace
15697                                .update_in(cx, |workspace, window, cx| {
15698                                    workspace.open_resolved_path(path, window, cx)
15699                                })?
15700                                .await
15701                                .map(|_| TargetTaskResult::AlreadyNavigated)
15702                        })
15703                    } else {
15704                        Task::ready(Ok(TargetTaskResult::Location(None)))
15705                    }
15706                }
15707            };
15708            cx.spawn_in(window, async move |editor, cx| {
15709                let target = match target_task.await.context("target resolution task")? {
15710                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15711                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15712                    TargetTaskResult::Location(Some(target)) => target,
15713                };
15714
15715                editor.update_in(cx, |editor, window, cx| {
15716                    let Some(workspace) = editor.workspace() else {
15717                        return Navigated::No;
15718                    };
15719                    let pane = workspace.read(cx).active_pane().clone();
15720
15721                    let range = target.range.to_point(target.buffer.read(cx));
15722                    let range = editor.range_for_match(&range);
15723                    let range = collapse_multiline_range(range);
15724
15725                    if !split
15726                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15727                    {
15728                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15729                    } else {
15730                        window.defer(cx, move |window, cx| {
15731                            let target_editor: Entity<Self> =
15732                                workspace.update(cx, |workspace, cx| {
15733                                    let pane = if split {
15734                                        workspace.adjacent_pane(window, cx)
15735                                    } else {
15736                                        workspace.active_pane().clone()
15737                                    };
15738
15739                                    workspace.open_project_item(
15740                                        pane,
15741                                        target.buffer.clone(),
15742                                        true,
15743                                        true,
15744                                        window,
15745                                        cx,
15746                                    )
15747                                });
15748                            target_editor.update(cx, |target_editor, cx| {
15749                                // When selecting a definition in a different buffer, disable the nav history
15750                                // to avoid creating a history entry at the previous cursor location.
15751                                pane.update(cx, |pane, _| pane.disable_history());
15752                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15753                                pane.update(cx, |pane, _| pane.enable_history());
15754                            });
15755                        });
15756                    }
15757                    Navigated::Yes
15758                })
15759            })
15760        } else if !definitions.is_empty() {
15761            cx.spawn_in(window, async move |editor, cx| {
15762                let (title, location_tasks, workspace) = editor
15763                    .update_in(cx, |editor, window, cx| {
15764                        let tab_kind = match kind {
15765                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15766                            _ => "Definitions",
15767                        };
15768                        let title = definitions
15769                            .iter()
15770                            .find_map(|definition| match definition {
15771                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15772                                    let buffer = origin.buffer.read(cx);
15773                                    format!(
15774                                        "{} for {}",
15775                                        tab_kind,
15776                                        buffer
15777                                            .text_for_range(origin.range.clone())
15778                                            .collect::<String>()
15779                                    )
15780                                }),
15781                                HoverLink::InlayHint(_, _) => None,
15782                                HoverLink::Url(_) => None,
15783                                HoverLink::File(_) => None,
15784                            })
15785                            .unwrap_or(tab_kind.to_string());
15786                        let location_tasks = definitions
15787                            .into_iter()
15788                            .map(|definition| match definition {
15789                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15790                                HoverLink::InlayHint(lsp_location, server_id) => editor
15791                                    .compute_target_location(lsp_location, server_id, window, cx),
15792                                HoverLink::Url(_) => Task::ready(Ok(None)),
15793                                HoverLink::File(_) => Task::ready(Ok(None)),
15794                            })
15795                            .collect::<Vec<_>>();
15796                        (title, location_tasks, editor.workspace().clone())
15797                    })
15798                    .context("location tasks preparation")?;
15799
15800                let locations: Vec<Location> = future::join_all(location_tasks)
15801                    .await
15802                    .into_iter()
15803                    .filter_map(|location| location.transpose())
15804                    .collect::<Result<_>>()
15805                    .context("location tasks")?;
15806
15807                if locations.is_empty() {
15808                    return Ok(Navigated::No);
15809                }
15810
15811                let Some(workspace) = workspace else {
15812                    return Ok(Navigated::No);
15813                };
15814
15815                let opened = workspace
15816                    .update_in(cx, |workspace, window, cx| {
15817                        Self::open_locations_in_multibuffer(
15818                            workspace,
15819                            locations,
15820                            title,
15821                            split,
15822                            MultibufferSelectionMode::First,
15823                            window,
15824                            cx,
15825                        )
15826                    })
15827                    .ok();
15828
15829                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15830            })
15831        } else {
15832            Task::ready(Ok(Navigated::No))
15833        }
15834    }
15835
15836    fn compute_target_location(
15837        &self,
15838        lsp_location: lsp::Location,
15839        server_id: LanguageServerId,
15840        window: &mut Window,
15841        cx: &mut Context<Self>,
15842    ) -> Task<anyhow::Result<Option<Location>>> {
15843        let Some(project) = self.project.clone() else {
15844            return Task::ready(Ok(None));
15845        };
15846
15847        cx.spawn_in(window, async move |editor, cx| {
15848            let location_task = editor.update(cx, |_, cx| {
15849                project.update(cx, |project, cx| {
15850                    let language_server_name = project
15851                        .language_server_statuses(cx)
15852                        .find(|(id, _)| server_id == *id)
15853                        .map(|(_, status)| status.name.clone());
15854                    language_server_name.map(|language_server_name| {
15855                        project.open_local_buffer_via_lsp(
15856                            lsp_location.uri.clone(),
15857                            server_id,
15858                            language_server_name,
15859                            cx,
15860                        )
15861                    })
15862                })
15863            })?;
15864            let location = match location_task {
15865                Some(task) => Some({
15866                    let target_buffer_handle = task.await.context("open local buffer")?;
15867                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15868                        let target_start = target_buffer
15869                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15870                        let target_end = target_buffer
15871                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15872                        target_buffer.anchor_after(target_start)
15873                            ..target_buffer.anchor_before(target_end)
15874                    })?;
15875                    Location {
15876                        buffer: target_buffer_handle,
15877                        range,
15878                    }
15879                }),
15880                None => None,
15881            };
15882            Ok(location)
15883        })
15884    }
15885
15886    pub fn find_all_references(
15887        &mut self,
15888        _: &FindAllReferences,
15889        window: &mut Window,
15890        cx: &mut Context<Self>,
15891    ) -> Option<Task<Result<Navigated>>> {
15892        let selection = self.selections.newest::<usize>(cx);
15893        let multi_buffer = self.buffer.read(cx);
15894        let head = selection.head();
15895
15896        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15897        let head_anchor = multi_buffer_snapshot.anchor_at(
15898            head,
15899            if head < selection.tail() {
15900                Bias::Right
15901            } else {
15902                Bias::Left
15903            },
15904        );
15905
15906        match self
15907            .find_all_references_task_sources
15908            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15909        {
15910            Ok(_) => {
15911                log::info!(
15912                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15913                );
15914                return None;
15915            }
15916            Err(i) => {
15917                self.find_all_references_task_sources.insert(i, head_anchor);
15918            }
15919        }
15920
15921        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15922        let workspace = self.workspace()?;
15923        let project = workspace.read(cx).project().clone();
15924        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15925        Some(cx.spawn_in(window, async move |editor, cx| {
15926            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15927                if let Ok(i) = editor
15928                    .find_all_references_task_sources
15929                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15930                {
15931                    editor.find_all_references_task_sources.remove(i);
15932                }
15933            });
15934
15935            let locations = references.await?;
15936            if locations.is_empty() {
15937                return anyhow::Ok(Navigated::No);
15938            }
15939
15940            workspace.update_in(cx, |workspace, window, cx| {
15941                let title = locations
15942                    .first()
15943                    .as_ref()
15944                    .map(|location| {
15945                        let buffer = location.buffer.read(cx);
15946                        format!(
15947                            "References to `{}`",
15948                            buffer
15949                                .text_for_range(location.range.clone())
15950                                .collect::<String>()
15951                        )
15952                    })
15953                    .unwrap();
15954                Self::open_locations_in_multibuffer(
15955                    workspace,
15956                    locations,
15957                    title,
15958                    false,
15959                    MultibufferSelectionMode::First,
15960                    window,
15961                    cx,
15962                );
15963                Navigated::Yes
15964            })
15965        }))
15966    }
15967
15968    /// Opens a multibuffer with the given project locations in it
15969    pub fn open_locations_in_multibuffer(
15970        workspace: &mut Workspace,
15971        mut locations: Vec<Location>,
15972        title: String,
15973        split: bool,
15974        multibuffer_selection_mode: MultibufferSelectionMode,
15975        window: &mut Window,
15976        cx: &mut Context<Workspace>,
15977    ) {
15978        if locations.is_empty() {
15979            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15980            return;
15981        }
15982
15983        // If there are multiple definitions, open them in a multibuffer
15984        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15985        let mut locations = locations.into_iter().peekable();
15986        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15987        let capability = workspace.project().read(cx).capability();
15988
15989        let excerpt_buffer = cx.new(|cx| {
15990            let mut multibuffer = MultiBuffer::new(capability);
15991            while let Some(location) = locations.next() {
15992                let buffer = location.buffer.read(cx);
15993                let mut ranges_for_buffer = Vec::new();
15994                let range = location.range.to_point(buffer);
15995                ranges_for_buffer.push(range.clone());
15996
15997                while let Some(next_location) = locations.peek() {
15998                    if next_location.buffer == location.buffer {
15999                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16000                        locations.next();
16001                    } else {
16002                        break;
16003                    }
16004                }
16005
16006                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16007                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16008                    PathKey::for_buffer(&location.buffer, cx),
16009                    location.buffer.clone(),
16010                    ranges_for_buffer,
16011                    DEFAULT_MULTIBUFFER_CONTEXT,
16012                    cx,
16013                );
16014                ranges.extend(new_ranges)
16015            }
16016
16017            multibuffer.with_title(title)
16018        });
16019
16020        let editor = cx.new(|cx| {
16021            Editor::for_multibuffer(
16022                excerpt_buffer,
16023                Some(workspace.project().clone()),
16024                window,
16025                cx,
16026            )
16027        });
16028        editor.update(cx, |editor, cx| {
16029            match multibuffer_selection_mode {
16030                MultibufferSelectionMode::First => {
16031                    if let Some(first_range) = ranges.first() {
16032                        editor.change_selections(
16033                            SelectionEffects::no_scroll(),
16034                            window,
16035                            cx,
16036                            |selections| {
16037                                selections.clear_disjoint();
16038                                selections
16039                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16040                            },
16041                        );
16042                    }
16043                    editor.highlight_background::<Self>(
16044                        &ranges,
16045                        |theme| theme.colors().editor_highlighted_line_background,
16046                        cx,
16047                    );
16048                }
16049                MultibufferSelectionMode::All => {
16050                    editor.change_selections(
16051                        SelectionEffects::no_scroll(),
16052                        window,
16053                        cx,
16054                        |selections| {
16055                            selections.clear_disjoint();
16056                            selections.select_anchor_ranges(ranges);
16057                        },
16058                    );
16059                }
16060            }
16061            editor.register_buffers_with_language_servers(cx);
16062        });
16063
16064        let item = Box::new(editor);
16065        let item_id = item.item_id();
16066
16067        if split {
16068            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16069        } else {
16070            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16071                let (preview_item_id, preview_item_idx) =
16072                    workspace.active_pane().read_with(cx, |pane, _| {
16073                        (pane.preview_item_id(), pane.preview_item_idx())
16074                    });
16075
16076                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16077
16078                if let Some(preview_item_id) = preview_item_id {
16079                    workspace.active_pane().update(cx, |pane, cx| {
16080                        pane.remove_item(preview_item_id, false, false, window, cx);
16081                    });
16082                }
16083            } else {
16084                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16085            }
16086        }
16087        workspace.active_pane().update(cx, |pane, cx| {
16088            pane.set_preview_item_id(Some(item_id), cx);
16089        });
16090    }
16091
16092    pub fn rename(
16093        &mut self,
16094        _: &Rename,
16095        window: &mut Window,
16096        cx: &mut Context<Self>,
16097    ) -> Option<Task<Result<()>>> {
16098        use language::ToOffset as _;
16099
16100        let provider = self.semantics_provider.clone()?;
16101        let selection = self.selections.newest_anchor().clone();
16102        let (cursor_buffer, cursor_buffer_position) = self
16103            .buffer
16104            .read(cx)
16105            .text_anchor_for_position(selection.head(), cx)?;
16106        let (tail_buffer, cursor_buffer_position_end) = self
16107            .buffer
16108            .read(cx)
16109            .text_anchor_for_position(selection.tail(), cx)?;
16110        if tail_buffer != cursor_buffer {
16111            return None;
16112        }
16113
16114        let snapshot = cursor_buffer.read(cx).snapshot();
16115        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16116        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16117        let prepare_rename = provider
16118            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16119            .unwrap_or_else(|| Task::ready(Ok(None)));
16120        drop(snapshot);
16121
16122        Some(cx.spawn_in(window, async move |this, cx| {
16123            let rename_range = if let Some(range) = prepare_rename.await? {
16124                Some(range)
16125            } else {
16126                this.update(cx, |this, cx| {
16127                    let buffer = this.buffer.read(cx).snapshot(cx);
16128                    let mut buffer_highlights = this
16129                        .document_highlights_for_position(selection.head(), &buffer)
16130                        .filter(|highlight| {
16131                            highlight.start.excerpt_id == selection.head().excerpt_id
16132                                && highlight.end.excerpt_id == selection.head().excerpt_id
16133                        });
16134                    buffer_highlights
16135                        .next()
16136                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16137                })?
16138            };
16139            if let Some(rename_range) = rename_range {
16140                this.update_in(cx, |this, window, cx| {
16141                    let snapshot = cursor_buffer.read(cx).snapshot();
16142                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16143                    let cursor_offset_in_rename_range =
16144                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16145                    let cursor_offset_in_rename_range_end =
16146                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16147
16148                    this.take_rename(false, window, cx);
16149                    let buffer = this.buffer.read(cx).read(cx);
16150                    let cursor_offset = selection.head().to_offset(&buffer);
16151                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16152                    let rename_end = rename_start + rename_buffer_range.len();
16153                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16154                    let mut old_highlight_id = None;
16155                    let old_name: Arc<str> = buffer
16156                        .chunks(rename_start..rename_end, true)
16157                        .map(|chunk| {
16158                            if old_highlight_id.is_none() {
16159                                old_highlight_id = chunk.syntax_highlight_id;
16160                            }
16161                            chunk.text
16162                        })
16163                        .collect::<String>()
16164                        .into();
16165
16166                    drop(buffer);
16167
16168                    // Position the selection in the rename editor so that it matches the current selection.
16169                    this.show_local_selections = false;
16170                    let rename_editor = cx.new(|cx| {
16171                        let mut editor = Editor::single_line(window, cx);
16172                        editor.buffer.update(cx, |buffer, cx| {
16173                            buffer.edit([(0..0, old_name.clone())], None, cx)
16174                        });
16175                        let rename_selection_range = match cursor_offset_in_rename_range
16176                            .cmp(&cursor_offset_in_rename_range_end)
16177                        {
16178                            Ordering::Equal => {
16179                                editor.select_all(&SelectAll, window, cx);
16180                                return editor;
16181                            }
16182                            Ordering::Less => {
16183                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16184                            }
16185                            Ordering::Greater => {
16186                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16187                            }
16188                        };
16189                        if rename_selection_range.end > old_name.len() {
16190                            editor.select_all(&SelectAll, window, cx);
16191                        } else {
16192                            editor.change_selections(Default::default(), window, cx, |s| {
16193                                s.select_ranges([rename_selection_range]);
16194                            });
16195                        }
16196                        editor
16197                    });
16198                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16199                        if e == &EditorEvent::Focused {
16200                            cx.emit(EditorEvent::FocusedIn)
16201                        }
16202                    })
16203                    .detach();
16204
16205                    let write_highlights =
16206                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16207                    let read_highlights =
16208                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16209                    let ranges = write_highlights
16210                        .iter()
16211                        .flat_map(|(_, ranges)| ranges.iter())
16212                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16213                        .cloned()
16214                        .collect();
16215
16216                    this.highlight_text::<Rename>(
16217                        ranges,
16218                        HighlightStyle {
16219                            fade_out: Some(0.6),
16220                            ..Default::default()
16221                        },
16222                        cx,
16223                    );
16224                    let rename_focus_handle = rename_editor.focus_handle(cx);
16225                    window.focus(&rename_focus_handle);
16226                    let block_id = this.insert_blocks(
16227                        [BlockProperties {
16228                            style: BlockStyle::Flex,
16229                            placement: BlockPlacement::Below(range.start),
16230                            height: Some(1),
16231                            render: Arc::new({
16232                                let rename_editor = rename_editor.clone();
16233                                move |cx: &mut BlockContext| {
16234                                    let mut text_style = cx.editor_style.text.clone();
16235                                    if let Some(highlight_style) = old_highlight_id
16236                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16237                                    {
16238                                        text_style = text_style.highlight(highlight_style);
16239                                    }
16240                                    div()
16241                                        .block_mouse_except_scroll()
16242                                        .pl(cx.anchor_x)
16243                                        .child(EditorElement::new(
16244                                            &rename_editor,
16245                                            EditorStyle {
16246                                                background: cx.theme().system().transparent,
16247                                                local_player: cx.editor_style.local_player,
16248                                                text: text_style,
16249                                                scrollbar_width: cx.editor_style.scrollbar_width,
16250                                                syntax: cx.editor_style.syntax.clone(),
16251                                                status: cx.editor_style.status.clone(),
16252                                                inlay_hints_style: HighlightStyle {
16253                                                    font_weight: Some(FontWeight::BOLD),
16254                                                    ..make_inlay_hints_style(cx.app)
16255                                                },
16256                                                edit_prediction_styles: make_suggestion_styles(
16257                                                    cx.app,
16258                                                ),
16259                                                ..EditorStyle::default()
16260                                            },
16261                                        ))
16262                                        .into_any_element()
16263                                }
16264                            }),
16265                            priority: 0,
16266                        }],
16267                        Some(Autoscroll::fit()),
16268                        cx,
16269                    )[0];
16270                    this.pending_rename = Some(RenameState {
16271                        range,
16272                        old_name,
16273                        editor: rename_editor,
16274                        block_id,
16275                    });
16276                })?;
16277            }
16278
16279            Ok(())
16280        }))
16281    }
16282
16283    pub fn confirm_rename(
16284        &mut self,
16285        _: &ConfirmRename,
16286        window: &mut Window,
16287        cx: &mut Context<Self>,
16288    ) -> Option<Task<Result<()>>> {
16289        let rename = self.take_rename(false, window, cx)?;
16290        let workspace = self.workspace()?.downgrade();
16291        let (buffer, start) = self
16292            .buffer
16293            .read(cx)
16294            .text_anchor_for_position(rename.range.start, cx)?;
16295        let (end_buffer, _) = self
16296            .buffer
16297            .read(cx)
16298            .text_anchor_for_position(rename.range.end, cx)?;
16299        if buffer != end_buffer {
16300            return None;
16301        }
16302
16303        let old_name = rename.old_name;
16304        let new_name = rename.editor.read(cx).text(cx);
16305
16306        let rename = self.semantics_provider.as_ref()?.perform_rename(
16307            &buffer,
16308            start,
16309            new_name.clone(),
16310            cx,
16311        )?;
16312
16313        Some(cx.spawn_in(window, async move |editor, cx| {
16314            let project_transaction = rename.await?;
16315            Self::open_project_transaction(
16316                &editor,
16317                workspace,
16318                project_transaction,
16319                format!("Rename: {}{}", old_name, new_name),
16320                cx,
16321            )
16322            .await?;
16323
16324            editor.update(cx, |editor, cx| {
16325                editor.refresh_document_highlights(cx);
16326            })?;
16327            Ok(())
16328        }))
16329    }
16330
16331    fn take_rename(
16332        &mut self,
16333        moving_cursor: bool,
16334        window: &mut Window,
16335        cx: &mut Context<Self>,
16336    ) -> Option<RenameState> {
16337        let rename = self.pending_rename.take()?;
16338        if rename.editor.focus_handle(cx).is_focused(window) {
16339            window.focus(&self.focus_handle);
16340        }
16341
16342        self.remove_blocks(
16343            [rename.block_id].into_iter().collect(),
16344            Some(Autoscroll::fit()),
16345            cx,
16346        );
16347        self.clear_highlights::<Rename>(cx);
16348        self.show_local_selections = true;
16349
16350        if moving_cursor {
16351            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16352                editor.selections.newest::<usize>(cx).head()
16353            });
16354
16355            // Update the selection to match the position of the selection inside
16356            // the rename editor.
16357            let snapshot = self.buffer.read(cx).read(cx);
16358            let rename_range = rename.range.to_offset(&snapshot);
16359            let cursor_in_editor = snapshot
16360                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16361                .min(rename_range.end);
16362            drop(snapshot);
16363
16364            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16365                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16366            });
16367        } else {
16368            self.refresh_document_highlights(cx);
16369        }
16370
16371        Some(rename)
16372    }
16373
16374    pub fn pending_rename(&self) -> Option<&RenameState> {
16375        self.pending_rename.as_ref()
16376    }
16377
16378    fn format(
16379        &mut self,
16380        _: &Format,
16381        window: &mut Window,
16382        cx: &mut Context<Self>,
16383    ) -> Option<Task<Result<()>>> {
16384        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16385
16386        let project = match &self.project {
16387            Some(project) => project.clone(),
16388            None => return None,
16389        };
16390
16391        Some(self.perform_format(
16392            project,
16393            FormatTrigger::Manual,
16394            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16395            window,
16396            cx,
16397        ))
16398    }
16399
16400    fn format_selections(
16401        &mut self,
16402        _: &FormatSelections,
16403        window: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) -> Option<Task<Result<()>>> {
16406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16407
16408        let project = match &self.project {
16409            Some(project) => project.clone(),
16410            None => return None,
16411        };
16412
16413        let ranges = self
16414            .selections
16415            .all_adjusted(cx)
16416            .into_iter()
16417            .map(|selection| selection.range())
16418            .collect_vec();
16419
16420        Some(self.perform_format(
16421            project,
16422            FormatTrigger::Manual,
16423            FormatTarget::Ranges(ranges),
16424            window,
16425            cx,
16426        ))
16427    }
16428
16429    fn perform_format(
16430        &mut self,
16431        project: Entity<Project>,
16432        trigger: FormatTrigger,
16433        target: FormatTarget,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) -> Task<Result<()>> {
16437        let buffer = self.buffer.clone();
16438        let (buffers, target) = match target {
16439            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16440            FormatTarget::Ranges(selection_ranges) => {
16441                let multi_buffer = buffer.read(cx);
16442                let snapshot = multi_buffer.read(cx);
16443                let mut buffers = HashSet::default();
16444                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16445                    BTreeMap::new();
16446                for selection_range in selection_ranges {
16447                    for (buffer, buffer_range, _) in
16448                        snapshot.range_to_buffer_ranges(selection_range)
16449                    {
16450                        let buffer_id = buffer.remote_id();
16451                        let start = buffer.anchor_before(buffer_range.start);
16452                        let end = buffer.anchor_after(buffer_range.end);
16453                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16454                        buffer_id_to_ranges
16455                            .entry(buffer_id)
16456                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16457                            .or_insert_with(|| vec![start..end]);
16458                    }
16459                }
16460                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16461            }
16462        };
16463
16464        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16465        let selections_prev = transaction_id_prev
16466            .and_then(|transaction_id_prev| {
16467                // default to selections as they were after the last edit, if we have them,
16468                // instead of how they are now.
16469                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16470                // will take you back to where you made the last edit, instead of staying where you scrolled
16471                self.selection_history
16472                    .transaction(transaction_id_prev)
16473                    .map(|t| t.0.clone())
16474            })
16475            .unwrap_or_else(|| {
16476                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16477                self.selections.disjoint_anchors()
16478            });
16479
16480        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16481        let format = project.update(cx, |project, cx| {
16482            project.format(buffers, target, true, trigger, cx)
16483        });
16484
16485        cx.spawn_in(window, async move |editor, cx| {
16486            let transaction = futures::select_biased! {
16487                transaction = format.log_err().fuse() => transaction,
16488                () = timeout => {
16489                    log::warn!("timed out waiting for formatting");
16490                    None
16491                }
16492            };
16493
16494            buffer
16495                .update(cx, |buffer, cx| {
16496                    if let Some(transaction) = transaction {
16497                        if !buffer.is_singleton() {
16498                            buffer.push_transaction(&transaction.0, cx);
16499                        }
16500                    }
16501                    cx.notify();
16502                })
16503                .ok();
16504
16505            if let Some(transaction_id_now) =
16506                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16507            {
16508                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16509                if has_new_transaction {
16510                    _ = editor.update(cx, |editor, _| {
16511                        editor
16512                            .selection_history
16513                            .insert_transaction(transaction_id_now, selections_prev);
16514                    });
16515                }
16516            }
16517
16518            Ok(())
16519        })
16520    }
16521
16522    fn organize_imports(
16523        &mut self,
16524        _: &OrganizeImports,
16525        window: &mut Window,
16526        cx: &mut Context<Self>,
16527    ) -> Option<Task<Result<()>>> {
16528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16529        let project = match &self.project {
16530            Some(project) => project.clone(),
16531            None => return None,
16532        };
16533        Some(self.perform_code_action_kind(
16534            project,
16535            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16536            window,
16537            cx,
16538        ))
16539    }
16540
16541    fn perform_code_action_kind(
16542        &mut self,
16543        project: Entity<Project>,
16544        kind: CodeActionKind,
16545        window: &mut Window,
16546        cx: &mut Context<Self>,
16547    ) -> Task<Result<()>> {
16548        let buffer = self.buffer.clone();
16549        let buffers = buffer.read(cx).all_buffers();
16550        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16551        let apply_action = project.update(cx, |project, cx| {
16552            project.apply_code_action_kind(buffers, kind, true, cx)
16553        });
16554        cx.spawn_in(window, async move |_, cx| {
16555            let transaction = futures::select_biased! {
16556                () = timeout => {
16557                    log::warn!("timed out waiting for executing code action");
16558                    None
16559                }
16560                transaction = apply_action.log_err().fuse() => transaction,
16561            };
16562            buffer
16563                .update(cx, |buffer, cx| {
16564                    // check if we need this
16565                    if let Some(transaction) = transaction {
16566                        if !buffer.is_singleton() {
16567                            buffer.push_transaction(&transaction.0, cx);
16568                        }
16569                    }
16570                    cx.notify();
16571                })
16572                .ok();
16573            Ok(())
16574        })
16575    }
16576
16577    pub fn restart_language_server(
16578        &mut self,
16579        _: &RestartLanguageServer,
16580        _: &mut Window,
16581        cx: &mut Context<Self>,
16582    ) {
16583        if let Some(project) = self.project.clone() {
16584            self.buffer.update(cx, |multi_buffer, cx| {
16585                project.update(cx, |project, cx| {
16586                    project.restart_language_servers_for_buffers(
16587                        multi_buffer.all_buffers().into_iter().collect(),
16588                        HashSet::default(),
16589                        cx,
16590                    );
16591                });
16592            })
16593        }
16594    }
16595
16596    pub fn stop_language_server(
16597        &mut self,
16598        _: &StopLanguageServer,
16599        _: &mut Window,
16600        cx: &mut Context<Self>,
16601    ) {
16602        if let Some(project) = self.project.clone() {
16603            self.buffer.update(cx, |multi_buffer, cx| {
16604                project.update(cx, |project, cx| {
16605                    project.stop_language_servers_for_buffers(
16606                        multi_buffer.all_buffers().into_iter().collect(),
16607                        HashSet::default(),
16608                        cx,
16609                    );
16610                    cx.emit(project::Event::RefreshInlayHints);
16611                });
16612            });
16613        }
16614    }
16615
16616    fn cancel_language_server_work(
16617        workspace: &mut Workspace,
16618        _: &actions::CancelLanguageServerWork,
16619        _: &mut Window,
16620        cx: &mut Context<Workspace>,
16621    ) {
16622        let project = workspace.project();
16623        let buffers = workspace
16624            .active_item(cx)
16625            .and_then(|item| item.act_as::<Editor>(cx))
16626            .map_or(HashSet::default(), |editor| {
16627                editor.read(cx).buffer.read(cx).all_buffers()
16628            });
16629        project.update(cx, |project, cx| {
16630            project.cancel_language_server_work_for_buffers(buffers, cx);
16631        });
16632    }
16633
16634    fn show_character_palette(
16635        &mut self,
16636        _: &ShowCharacterPalette,
16637        window: &mut Window,
16638        _: &mut Context<Self>,
16639    ) {
16640        window.show_character_palette();
16641    }
16642
16643    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16644        if !self.diagnostics_enabled() {
16645            return;
16646        }
16647
16648        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16649            let buffer = self.buffer.read(cx).snapshot(cx);
16650            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16651            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16652            let is_valid = buffer
16653                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16654                .any(|entry| {
16655                    entry.diagnostic.is_primary
16656                        && !entry.range.is_empty()
16657                        && entry.range.start == primary_range_start
16658                        && entry.diagnostic.message == active_diagnostics.active_message
16659                });
16660
16661            if !is_valid {
16662                self.dismiss_diagnostics(cx);
16663            }
16664        }
16665    }
16666
16667    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16668        match &self.active_diagnostics {
16669            ActiveDiagnostic::Group(group) => Some(group),
16670            _ => None,
16671        }
16672    }
16673
16674    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16675        if !self.diagnostics_enabled() {
16676            return;
16677        }
16678        self.dismiss_diagnostics(cx);
16679        self.active_diagnostics = ActiveDiagnostic::All;
16680    }
16681
16682    fn activate_diagnostics(
16683        &mut self,
16684        buffer_id: BufferId,
16685        diagnostic: DiagnosticEntry<usize>,
16686        window: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16690            return;
16691        }
16692        self.dismiss_diagnostics(cx);
16693        let snapshot = self.snapshot(window, cx);
16694        let buffer = self.buffer.read(cx).snapshot(cx);
16695        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16696            return;
16697        };
16698
16699        let diagnostic_group = buffer
16700            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16701            .collect::<Vec<_>>();
16702
16703        let blocks =
16704            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16705
16706        let blocks = self.display_map.update(cx, |display_map, cx| {
16707            display_map.insert_blocks(blocks, cx).into_iter().collect()
16708        });
16709        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16710            active_range: buffer.anchor_before(diagnostic.range.start)
16711                ..buffer.anchor_after(diagnostic.range.end),
16712            active_message: diagnostic.diagnostic.message.clone(),
16713            group_id: diagnostic.diagnostic.group_id,
16714            blocks,
16715        });
16716        cx.notify();
16717    }
16718
16719    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16720        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16721            return;
16722        };
16723
16724        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16725        if let ActiveDiagnostic::Group(group) = prev {
16726            self.display_map.update(cx, |display_map, cx| {
16727                display_map.remove_blocks(group.blocks, cx);
16728            });
16729            cx.notify();
16730        }
16731    }
16732
16733    /// Disable inline diagnostics rendering for this editor.
16734    pub fn disable_inline_diagnostics(&mut self) {
16735        self.inline_diagnostics_enabled = false;
16736        self.inline_diagnostics_update = Task::ready(());
16737        self.inline_diagnostics.clear();
16738    }
16739
16740    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16741        self.diagnostics_enabled = false;
16742        self.dismiss_diagnostics(cx);
16743        self.inline_diagnostics_update = Task::ready(());
16744        self.inline_diagnostics.clear();
16745    }
16746
16747    pub fn diagnostics_enabled(&self) -> bool {
16748        self.diagnostics_enabled && self.mode.is_full()
16749    }
16750
16751    pub fn inline_diagnostics_enabled(&self) -> bool {
16752        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16753    }
16754
16755    pub fn show_inline_diagnostics(&self) -> bool {
16756        self.show_inline_diagnostics
16757    }
16758
16759    pub fn toggle_inline_diagnostics(
16760        &mut self,
16761        _: &ToggleInlineDiagnostics,
16762        window: &mut Window,
16763        cx: &mut Context<Editor>,
16764    ) {
16765        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16766        self.refresh_inline_diagnostics(false, window, cx);
16767    }
16768
16769    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16770        self.diagnostics_max_severity = severity;
16771        self.display_map.update(cx, |display_map, _| {
16772            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16773        });
16774    }
16775
16776    pub fn toggle_diagnostics(
16777        &mut self,
16778        _: &ToggleDiagnostics,
16779        window: &mut Window,
16780        cx: &mut Context<Editor>,
16781    ) {
16782        if !self.diagnostics_enabled() {
16783            return;
16784        }
16785
16786        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16787            EditorSettings::get_global(cx)
16788                .diagnostics_max_severity
16789                .filter(|severity| severity != &DiagnosticSeverity::Off)
16790                .unwrap_or(DiagnosticSeverity::Hint)
16791        } else {
16792            DiagnosticSeverity::Off
16793        };
16794        self.set_max_diagnostics_severity(new_severity, cx);
16795        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16796            self.active_diagnostics = ActiveDiagnostic::None;
16797            self.inline_diagnostics_update = Task::ready(());
16798            self.inline_diagnostics.clear();
16799        } else {
16800            self.refresh_inline_diagnostics(false, window, cx);
16801        }
16802
16803        cx.notify();
16804    }
16805
16806    pub fn toggle_minimap(
16807        &mut self,
16808        _: &ToggleMinimap,
16809        window: &mut Window,
16810        cx: &mut Context<Editor>,
16811    ) {
16812        if self.supports_minimap(cx) {
16813            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16814        }
16815    }
16816
16817    fn refresh_inline_diagnostics(
16818        &mut self,
16819        debounce: bool,
16820        window: &mut Window,
16821        cx: &mut Context<Self>,
16822    ) {
16823        let max_severity = ProjectSettings::get_global(cx)
16824            .diagnostics
16825            .inline
16826            .max_severity
16827            .unwrap_or(self.diagnostics_max_severity);
16828
16829        if !self.inline_diagnostics_enabled()
16830            || !self.show_inline_diagnostics
16831            || max_severity == DiagnosticSeverity::Off
16832        {
16833            self.inline_diagnostics_update = Task::ready(());
16834            self.inline_diagnostics.clear();
16835            return;
16836        }
16837
16838        let debounce_ms = ProjectSettings::get_global(cx)
16839            .diagnostics
16840            .inline
16841            .update_debounce_ms;
16842        let debounce = if debounce && debounce_ms > 0 {
16843            Some(Duration::from_millis(debounce_ms))
16844        } else {
16845            None
16846        };
16847        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16848            if let Some(debounce) = debounce {
16849                cx.background_executor().timer(debounce).await;
16850            }
16851            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16852                editor
16853                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16854                    .ok()
16855            }) else {
16856                return;
16857            };
16858
16859            let new_inline_diagnostics = cx
16860                .background_spawn(async move {
16861                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16862                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16863                        let message = diagnostic_entry
16864                            .diagnostic
16865                            .message
16866                            .split_once('\n')
16867                            .map(|(line, _)| line)
16868                            .map(SharedString::new)
16869                            .unwrap_or_else(|| {
16870                                SharedString::from(diagnostic_entry.diagnostic.message)
16871                            });
16872                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16873                        let (Ok(i) | Err(i)) = inline_diagnostics
16874                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16875                        inline_diagnostics.insert(
16876                            i,
16877                            (
16878                                start_anchor,
16879                                InlineDiagnostic {
16880                                    message,
16881                                    group_id: diagnostic_entry.diagnostic.group_id,
16882                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16883                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16884                                    severity: diagnostic_entry.diagnostic.severity,
16885                                },
16886                            ),
16887                        );
16888                    }
16889                    inline_diagnostics
16890                })
16891                .await;
16892
16893            editor
16894                .update(cx, |editor, cx| {
16895                    editor.inline_diagnostics = new_inline_diagnostics;
16896                    cx.notify();
16897                })
16898                .ok();
16899        });
16900    }
16901
16902    fn pull_diagnostics(
16903        &mut self,
16904        buffer_id: Option<BufferId>,
16905        window: &Window,
16906        cx: &mut Context<Self>,
16907    ) -> Option<()> {
16908        if !self.mode().is_full() {
16909            return None;
16910        }
16911        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16912            .diagnostics
16913            .lsp_pull_diagnostics;
16914        if !pull_diagnostics_settings.enabled {
16915            return None;
16916        }
16917        let project = self.project.as_ref()?.downgrade();
16918        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16919        let mut buffers = self.buffer.read(cx).all_buffers();
16920        if let Some(buffer_id) = buffer_id {
16921            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16922        }
16923
16924        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16925            cx.background_executor().timer(debounce).await;
16926
16927            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16928                buffers
16929                    .into_iter()
16930                    .filter_map(|buffer| {
16931                        project
16932                            .update(cx, |project, cx| {
16933                                project.lsp_store().update(cx, |lsp_store, cx| {
16934                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16935                                })
16936                            })
16937                            .ok()
16938                    })
16939                    .collect::<FuturesUnordered<_>>()
16940            }) else {
16941                return;
16942            };
16943
16944            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16945                match pull_task {
16946                    Ok(()) => {
16947                        if editor
16948                            .update_in(cx, |editor, window, cx| {
16949                                editor.update_diagnostics_state(window, cx);
16950                            })
16951                            .is_err()
16952                        {
16953                            return;
16954                        }
16955                    }
16956                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16957                }
16958            }
16959        });
16960
16961        Some(())
16962    }
16963
16964    pub fn set_selections_from_remote(
16965        &mut self,
16966        selections: Vec<Selection<Anchor>>,
16967        pending_selection: Option<Selection<Anchor>>,
16968        window: &mut Window,
16969        cx: &mut Context<Self>,
16970    ) {
16971        let old_cursor_position = self.selections.newest_anchor().head();
16972        self.selections.change_with(cx, |s| {
16973            s.select_anchors(selections);
16974            if let Some(pending_selection) = pending_selection {
16975                s.set_pending(pending_selection, SelectMode::Character);
16976            } else {
16977                s.clear_pending();
16978            }
16979        });
16980        self.selections_did_change(
16981            false,
16982            &old_cursor_position,
16983            SelectionEffects::default(),
16984            window,
16985            cx,
16986        );
16987    }
16988
16989    pub fn transact(
16990        &mut self,
16991        window: &mut Window,
16992        cx: &mut Context<Self>,
16993        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16994    ) -> Option<TransactionId> {
16995        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16996            this.start_transaction_at(Instant::now(), window, cx);
16997            update(this, window, cx);
16998            this.end_transaction_at(Instant::now(), cx)
16999        })
17000    }
17001
17002    pub fn start_transaction_at(
17003        &mut self,
17004        now: Instant,
17005        window: &mut Window,
17006        cx: &mut Context<Self>,
17007    ) -> Option<TransactionId> {
17008        self.end_selection(window, cx);
17009        if let Some(tx_id) = self
17010            .buffer
17011            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17012        {
17013            self.selection_history
17014                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17015            cx.emit(EditorEvent::TransactionBegun {
17016                transaction_id: tx_id,
17017            });
17018            Some(tx_id)
17019        } else {
17020            None
17021        }
17022    }
17023
17024    pub fn end_transaction_at(
17025        &mut self,
17026        now: Instant,
17027        cx: &mut Context<Self>,
17028    ) -> Option<TransactionId> {
17029        if let Some(transaction_id) = self
17030            .buffer
17031            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17032        {
17033            if let Some((_, end_selections)) =
17034                self.selection_history.transaction_mut(transaction_id)
17035            {
17036                *end_selections = Some(self.selections.disjoint_anchors());
17037            } else {
17038                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17039            }
17040
17041            cx.emit(EditorEvent::Edited { transaction_id });
17042            Some(transaction_id)
17043        } else {
17044            None
17045        }
17046    }
17047
17048    pub fn modify_transaction_selection_history(
17049        &mut self,
17050        transaction_id: TransactionId,
17051        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17052    ) -> bool {
17053        self.selection_history
17054            .transaction_mut(transaction_id)
17055            .map(modify)
17056            .is_some()
17057    }
17058
17059    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17060        if self.selection_mark_mode {
17061            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17062                s.move_with(|_, sel| {
17063                    sel.collapse_to(sel.head(), SelectionGoal::None);
17064                });
17065            })
17066        }
17067        self.selection_mark_mode = true;
17068        cx.notify();
17069    }
17070
17071    pub fn swap_selection_ends(
17072        &mut self,
17073        _: &actions::SwapSelectionEnds,
17074        window: &mut Window,
17075        cx: &mut Context<Self>,
17076    ) {
17077        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17078            s.move_with(|_, sel| {
17079                if sel.start != sel.end {
17080                    sel.reversed = !sel.reversed
17081                }
17082            });
17083        });
17084        self.request_autoscroll(Autoscroll::newest(), cx);
17085        cx.notify();
17086    }
17087
17088    pub fn toggle_focus(
17089        workspace: &mut Workspace,
17090        _: &actions::ToggleFocus,
17091        window: &mut Window,
17092        cx: &mut Context<Workspace>,
17093    ) {
17094        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17095            return;
17096        };
17097        workspace.activate_item(&item, true, true, window, cx);
17098    }
17099
17100    pub fn toggle_fold(
17101        &mut self,
17102        _: &actions::ToggleFold,
17103        window: &mut Window,
17104        cx: &mut Context<Self>,
17105    ) {
17106        if self.is_singleton(cx) {
17107            let selection = self.selections.newest::<Point>(cx);
17108
17109            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17110            let range = if selection.is_empty() {
17111                let point = selection.head().to_display_point(&display_map);
17112                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17113                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17114                    .to_point(&display_map);
17115                start..end
17116            } else {
17117                selection.range()
17118            };
17119            if display_map.folds_in_range(range).next().is_some() {
17120                self.unfold_lines(&Default::default(), window, cx)
17121            } else {
17122                self.fold(&Default::default(), window, cx)
17123            }
17124        } else {
17125            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17126            let buffer_ids: HashSet<_> = self
17127                .selections
17128                .disjoint_anchor_ranges()
17129                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17130                .collect();
17131
17132            let should_unfold = buffer_ids
17133                .iter()
17134                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17135
17136            for buffer_id in buffer_ids {
17137                if should_unfold {
17138                    self.unfold_buffer(buffer_id, cx);
17139                } else {
17140                    self.fold_buffer(buffer_id, cx);
17141                }
17142            }
17143        }
17144    }
17145
17146    pub fn toggle_fold_recursive(
17147        &mut self,
17148        _: &actions::ToggleFoldRecursive,
17149        window: &mut Window,
17150        cx: &mut Context<Self>,
17151    ) {
17152        let selection = self.selections.newest::<Point>(cx);
17153
17154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17155        let range = if selection.is_empty() {
17156            let point = selection.head().to_display_point(&display_map);
17157            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17158            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17159                .to_point(&display_map);
17160            start..end
17161        } else {
17162            selection.range()
17163        };
17164        if display_map.folds_in_range(range).next().is_some() {
17165            self.unfold_recursive(&Default::default(), window, cx)
17166        } else {
17167            self.fold_recursive(&Default::default(), window, cx)
17168        }
17169    }
17170
17171    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17172        if self.is_singleton(cx) {
17173            let mut to_fold = Vec::new();
17174            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17175            let selections = self.selections.all_adjusted(cx);
17176
17177            for selection in selections {
17178                let range = selection.range().sorted();
17179                let buffer_start_row = range.start.row;
17180
17181                if range.start.row != range.end.row {
17182                    let mut found = false;
17183                    let mut row = range.start.row;
17184                    while row <= range.end.row {
17185                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17186                        {
17187                            found = true;
17188                            row = crease.range().end.row + 1;
17189                            to_fold.push(crease);
17190                        } else {
17191                            row += 1
17192                        }
17193                    }
17194                    if found {
17195                        continue;
17196                    }
17197                }
17198
17199                for row in (0..=range.start.row).rev() {
17200                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17201                        if crease.range().end.row >= buffer_start_row {
17202                            to_fold.push(crease);
17203                            if row <= range.start.row {
17204                                break;
17205                            }
17206                        }
17207                    }
17208                }
17209            }
17210
17211            self.fold_creases(to_fold, true, window, cx);
17212        } else {
17213            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17214            let buffer_ids = self
17215                .selections
17216                .disjoint_anchor_ranges()
17217                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17218                .collect::<HashSet<_>>();
17219            for buffer_id in buffer_ids {
17220                self.fold_buffer(buffer_id, cx);
17221            }
17222        }
17223    }
17224
17225    pub fn toggle_fold_all(
17226        &mut self,
17227        _: &actions::ToggleFoldAll,
17228        window: &mut Window,
17229        cx: &mut Context<Self>,
17230    ) {
17231        if self.buffer.read(cx).is_singleton() {
17232            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17233            let has_folds = display_map
17234                .folds_in_range(0..display_map.buffer_snapshot.len())
17235                .next()
17236                .is_some();
17237
17238            if has_folds {
17239                self.unfold_all(&actions::UnfoldAll, window, cx);
17240            } else {
17241                self.fold_all(&actions::FoldAll, window, cx);
17242            }
17243        } else {
17244            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17245            let should_unfold = buffer_ids
17246                .iter()
17247                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17248
17249            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17250                editor
17251                    .update_in(cx, |editor, _, cx| {
17252                        for buffer_id in buffer_ids {
17253                            if should_unfold {
17254                                editor.unfold_buffer(buffer_id, cx);
17255                            } else {
17256                                editor.fold_buffer(buffer_id, cx);
17257                            }
17258                        }
17259                    })
17260                    .ok();
17261            });
17262        }
17263    }
17264
17265    fn fold_at_level(
17266        &mut self,
17267        fold_at: &FoldAtLevel,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270    ) {
17271        if !self.buffer.read(cx).is_singleton() {
17272            return;
17273        }
17274
17275        let fold_at_level = fold_at.0;
17276        let snapshot = self.buffer.read(cx).snapshot(cx);
17277        let mut to_fold = Vec::new();
17278        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17279
17280        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17281            while start_row < end_row {
17282                match self
17283                    .snapshot(window, cx)
17284                    .crease_for_buffer_row(MultiBufferRow(start_row))
17285                {
17286                    Some(crease) => {
17287                        let nested_start_row = crease.range().start.row + 1;
17288                        let nested_end_row = crease.range().end.row;
17289
17290                        if current_level < fold_at_level {
17291                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17292                        } else if current_level == fold_at_level {
17293                            to_fold.push(crease);
17294                        }
17295
17296                        start_row = nested_end_row + 1;
17297                    }
17298                    None => start_row += 1,
17299                }
17300            }
17301        }
17302
17303        self.fold_creases(to_fold, true, window, cx);
17304    }
17305
17306    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17307        if self.buffer.read(cx).is_singleton() {
17308            let mut fold_ranges = Vec::new();
17309            let snapshot = self.buffer.read(cx).snapshot(cx);
17310
17311            for row in 0..snapshot.max_row().0 {
17312                if let Some(foldable_range) = self
17313                    .snapshot(window, cx)
17314                    .crease_for_buffer_row(MultiBufferRow(row))
17315                {
17316                    fold_ranges.push(foldable_range);
17317                }
17318            }
17319
17320            self.fold_creases(fold_ranges, true, window, cx);
17321        } else {
17322            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17323                editor
17324                    .update_in(cx, |editor, _, cx| {
17325                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17326                            editor.fold_buffer(buffer_id, cx);
17327                        }
17328                    })
17329                    .ok();
17330            });
17331        }
17332    }
17333
17334    pub fn fold_function_bodies(
17335        &mut self,
17336        _: &actions::FoldFunctionBodies,
17337        window: &mut Window,
17338        cx: &mut Context<Self>,
17339    ) {
17340        let snapshot = self.buffer.read(cx).snapshot(cx);
17341
17342        let ranges = snapshot
17343            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17344            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17345            .collect::<Vec<_>>();
17346
17347        let creases = ranges
17348            .into_iter()
17349            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17350            .collect();
17351
17352        self.fold_creases(creases, true, window, cx);
17353    }
17354
17355    pub fn fold_recursive(
17356        &mut self,
17357        _: &actions::FoldRecursive,
17358        window: &mut Window,
17359        cx: &mut Context<Self>,
17360    ) {
17361        let mut to_fold = Vec::new();
17362        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17363        let selections = self.selections.all_adjusted(cx);
17364
17365        for selection in selections {
17366            let range = selection.range().sorted();
17367            let buffer_start_row = range.start.row;
17368
17369            if range.start.row != range.end.row {
17370                let mut found = false;
17371                for row in range.start.row..=range.end.row {
17372                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17373                        found = true;
17374                        to_fold.push(crease);
17375                    }
17376                }
17377                if found {
17378                    continue;
17379                }
17380            }
17381
17382            for row in (0..=range.start.row).rev() {
17383                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17384                    if crease.range().end.row >= buffer_start_row {
17385                        to_fold.push(crease);
17386                    } else {
17387                        break;
17388                    }
17389                }
17390            }
17391        }
17392
17393        self.fold_creases(to_fold, true, window, cx);
17394    }
17395
17396    pub fn fold_at(
17397        &mut self,
17398        buffer_row: MultiBufferRow,
17399        window: &mut Window,
17400        cx: &mut Context<Self>,
17401    ) {
17402        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17403
17404        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17405            let autoscroll = self
17406                .selections
17407                .all::<Point>(cx)
17408                .iter()
17409                .any(|selection| crease.range().overlaps(&selection.range()));
17410
17411            self.fold_creases(vec![crease], autoscroll, window, cx);
17412        }
17413    }
17414
17415    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17416        if self.is_singleton(cx) {
17417            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17418            let buffer = &display_map.buffer_snapshot;
17419            let selections = self.selections.all::<Point>(cx);
17420            let ranges = selections
17421                .iter()
17422                .map(|s| {
17423                    let range = s.display_range(&display_map).sorted();
17424                    let mut start = range.start.to_point(&display_map);
17425                    let mut end = range.end.to_point(&display_map);
17426                    start.column = 0;
17427                    end.column = buffer.line_len(MultiBufferRow(end.row));
17428                    start..end
17429                })
17430                .collect::<Vec<_>>();
17431
17432            self.unfold_ranges(&ranges, true, true, cx);
17433        } else {
17434            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17435            let buffer_ids = self
17436                .selections
17437                .disjoint_anchor_ranges()
17438                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17439                .collect::<HashSet<_>>();
17440            for buffer_id in buffer_ids {
17441                self.unfold_buffer(buffer_id, cx);
17442            }
17443        }
17444    }
17445
17446    pub fn unfold_recursive(
17447        &mut self,
17448        _: &UnfoldRecursive,
17449        _window: &mut Window,
17450        cx: &mut Context<Self>,
17451    ) {
17452        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17453        let selections = self.selections.all::<Point>(cx);
17454        let ranges = selections
17455            .iter()
17456            .map(|s| {
17457                let mut range = s.display_range(&display_map).sorted();
17458                *range.start.column_mut() = 0;
17459                *range.end.column_mut() = display_map.line_len(range.end.row());
17460                let start = range.start.to_point(&display_map);
17461                let end = range.end.to_point(&display_map);
17462                start..end
17463            })
17464            .collect::<Vec<_>>();
17465
17466        self.unfold_ranges(&ranges, true, true, cx);
17467    }
17468
17469    pub fn unfold_at(
17470        &mut self,
17471        buffer_row: MultiBufferRow,
17472        _window: &mut Window,
17473        cx: &mut Context<Self>,
17474    ) {
17475        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17476
17477        let intersection_range = Point::new(buffer_row.0, 0)
17478            ..Point::new(
17479                buffer_row.0,
17480                display_map.buffer_snapshot.line_len(buffer_row),
17481            );
17482
17483        let autoscroll = self
17484            .selections
17485            .all::<Point>(cx)
17486            .iter()
17487            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17488
17489        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17490    }
17491
17492    pub fn unfold_all(
17493        &mut self,
17494        _: &actions::UnfoldAll,
17495        _window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) {
17498        if self.buffer.read(cx).is_singleton() {
17499            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17500            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17501        } else {
17502            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17503                editor
17504                    .update(cx, |editor, cx| {
17505                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17506                            editor.unfold_buffer(buffer_id, cx);
17507                        }
17508                    })
17509                    .ok();
17510            });
17511        }
17512    }
17513
17514    pub fn fold_selected_ranges(
17515        &mut self,
17516        _: &FoldSelectedRanges,
17517        window: &mut Window,
17518        cx: &mut Context<Self>,
17519    ) {
17520        let selections = self.selections.all_adjusted(cx);
17521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17522        let ranges = selections
17523            .into_iter()
17524            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17525            .collect::<Vec<_>>();
17526        self.fold_creases(ranges, true, window, cx);
17527    }
17528
17529    pub fn fold_ranges<T: ToOffset + Clone>(
17530        &mut self,
17531        ranges: Vec<Range<T>>,
17532        auto_scroll: bool,
17533        window: &mut Window,
17534        cx: &mut Context<Self>,
17535    ) {
17536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17537        let ranges = ranges
17538            .into_iter()
17539            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17540            .collect::<Vec<_>>();
17541        self.fold_creases(ranges, auto_scroll, window, cx);
17542    }
17543
17544    pub fn fold_creases<T: ToOffset + Clone>(
17545        &mut self,
17546        creases: Vec<Crease<T>>,
17547        auto_scroll: bool,
17548        _window: &mut Window,
17549        cx: &mut Context<Self>,
17550    ) {
17551        if creases.is_empty() {
17552            return;
17553        }
17554
17555        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17556
17557        if auto_scroll {
17558            self.request_autoscroll(Autoscroll::fit(), cx);
17559        }
17560
17561        cx.notify();
17562
17563        self.scrollbar_marker_state.dirty = true;
17564        self.folds_did_change(cx);
17565    }
17566
17567    /// Removes any folds whose ranges intersect any of the given ranges.
17568    pub fn unfold_ranges<T: ToOffset + Clone>(
17569        &mut self,
17570        ranges: &[Range<T>],
17571        inclusive: bool,
17572        auto_scroll: bool,
17573        cx: &mut Context<Self>,
17574    ) {
17575        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17576            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17577        });
17578        self.folds_did_change(cx);
17579    }
17580
17581    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17582        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17583            return;
17584        }
17585        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17586        self.display_map.update(cx, |display_map, cx| {
17587            display_map.fold_buffers([buffer_id], cx)
17588        });
17589        cx.emit(EditorEvent::BufferFoldToggled {
17590            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17591            folded: true,
17592        });
17593        cx.notify();
17594    }
17595
17596    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17597        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17598            return;
17599        }
17600        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17601        self.display_map.update(cx, |display_map, cx| {
17602            display_map.unfold_buffers([buffer_id], cx);
17603        });
17604        cx.emit(EditorEvent::BufferFoldToggled {
17605            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17606            folded: false,
17607        });
17608        cx.notify();
17609    }
17610
17611    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17612        self.display_map.read(cx).is_buffer_folded(buffer)
17613    }
17614
17615    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17616        self.display_map.read(cx).folded_buffers()
17617    }
17618
17619    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17620        self.display_map.update(cx, |display_map, cx| {
17621            display_map.disable_header_for_buffer(buffer_id, cx);
17622        });
17623        cx.notify();
17624    }
17625
17626    /// Removes any folds with the given ranges.
17627    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17628        &mut self,
17629        ranges: &[Range<T>],
17630        type_id: TypeId,
17631        auto_scroll: bool,
17632        cx: &mut Context<Self>,
17633    ) {
17634        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17635            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17636        });
17637        self.folds_did_change(cx);
17638    }
17639
17640    fn remove_folds_with<T: ToOffset + Clone>(
17641        &mut self,
17642        ranges: &[Range<T>],
17643        auto_scroll: bool,
17644        cx: &mut Context<Self>,
17645        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17646    ) {
17647        if ranges.is_empty() {
17648            return;
17649        }
17650
17651        let mut buffers_affected = HashSet::default();
17652        let multi_buffer = self.buffer().read(cx);
17653        for range in ranges {
17654            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17655                buffers_affected.insert(buffer.read(cx).remote_id());
17656            };
17657        }
17658
17659        self.display_map.update(cx, update);
17660
17661        if auto_scroll {
17662            self.request_autoscroll(Autoscroll::fit(), cx);
17663        }
17664
17665        cx.notify();
17666        self.scrollbar_marker_state.dirty = true;
17667        self.active_indent_guides_state.dirty = true;
17668    }
17669
17670    pub fn update_renderer_widths(
17671        &mut self,
17672        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17673        cx: &mut Context<Self>,
17674    ) -> bool {
17675        self.display_map
17676            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17677    }
17678
17679    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17680        self.display_map.read(cx).fold_placeholder.clone()
17681    }
17682
17683    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17684        self.buffer.update(cx, |buffer, cx| {
17685            buffer.set_all_diff_hunks_expanded(cx);
17686        });
17687    }
17688
17689    pub fn expand_all_diff_hunks(
17690        &mut self,
17691        _: &ExpandAllDiffHunks,
17692        _window: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        self.buffer.update(cx, |buffer, cx| {
17696            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17697        });
17698    }
17699
17700    pub fn toggle_selected_diff_hunks(
17701        &mut self,
17702        _: &ToggleSelectedDiffHunks,
17703        _window: &mut Window,
17704        cx: &mut Context<Self>,
17705    ) {
17706        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17707        self.toggle_diff_hunks_in_ranges(ranges, cx);
17708    }
17709
17710    pub fn diff_hunks_in_ranges<'a>(
17711        &'a self,
17712        ranges: &'a [Range<Anchor>],
17713        buffer: &'a MultiBufferSnapshot,
17714    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17715        ranges.iter().flat_map(move |range| {
17716            let end_excerpt_id = range.end.excerpt_id;
17717            let range = range.to_point(buffer);
17718            let mut peek_end = range.end;
17719            if range.end.row < buffer.max_row().0 {
17720                peek_end = Point::new(range.end.row + 1, 0);
17721            }
17722            buffer
17723                .diff_hunks_in_range(range.start..peek_end)
17724                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17725        })
17726    }
17727
17728    pub fn has_stageable_diff_hunks_in_ranges(
17729        &self,
17730        ranges: &[Range<Anchor>],
17731        snapshot: &MultiBufferSnapshot,
17732    ) -> bool {
17733        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17734        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17735    }
17736
17737    pub fn toggle_staged_selected_diff_hunks(
17738        &mut self,
17739        _: &::git::ToggleStaged,
17740        _: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) {
17743        let snapshot = self.buffer.read(cx).snapshot(cx);
17744        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17745        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17746        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17747    }
17748
17749    pub fn set_render_diff_hunk_controls(
17750        &mut self,
17751        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17752        cx: &mut Context<Self>,
17753    ) {
17754        self.render_diff_hunk_controls = render_diff_hunk_controls;
17755        cx.notify();
17756    }
17757
17758    pub fn stage_and_next(
17759        &mut self,
17760        _: &::git::StageAndNext,
17761        window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        self.do_stage_or_unstage_and_next(true, window, cx);
17765    }
17766
17767    pub fn unstage_and_next(
17768        &mut self,
17769        _: &::git::UnstageAndNext,
17770        window: &mut Window,
17771        cx: &mut Context<Self>,
17772    ) {
17773        self.do_stage_or_unstage_and_next(false, window, cx);
17774    }
17775
17776    pub fn stage_or_unstage_diff_hunks(
17777        &mut self,
17778        stage: bool,
17779        ranges: Vec<Range<Anchor>>,
17780        cx: &mut Context<Self>,
17781    ) {
17782        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17783        cx.spawn(async move |this, cx| {
17784            task.await?;
17785            this.update(cx, |this, cx| {
17786                let snapshot = this.buffer.read(cx).snapshot(cx);
17787                let chunk_by = this
17788                    .diff_hunks_in_ranges(&ranges, &snapshot)
17789                    .chunk_by(|hunk| hunk.buffer_id);
17790                for (buffer_id, hunks) in &chunk_by {
17791                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17792                }
17793            })
17794        })
17795        .detach_and_log_err(cx);
17796    }
17797
17798    fn save_buffers_for_ranges_if_needed(
17799        &mut self,
17800        ranges: &[Range<Anchor>],
17801        cx: &mut Context<Editor>,
17802    ) -> Task<Result<()>> {
17803        let multibuffer = self.buffer.read(cx);
17804        let snapshot = multibuffer.read(cx);
17805        let buffer_ids: HashSet<_> = ranges
17806            .iter()
17807            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17808            .collect();
17809        drop(snapshot);
17810
17811        let mut buffers = HashSet::default();
17812        for buffer_id in buffer_ids {
17813            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17814                let buffer = buffer_entity.read(cx);
17815                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17816                {
17817                    buffers.insert(buffer_entity);
17818                }
17819            }
17820        }
17821
17822        if let Some(project) = &self.project {
17823            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17824        } else {
17825            Task::ready(Ok(()))
17826        }
17827    }
17828
17829    fn do_stage_or_unstage_and_next(
17830        &mut self,
17831        stage: bool,
17832        window: &mut Window,
17833        cx: &mut Context<Self>,
17834    ) {
17835        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17836
17837        if ranges.iter().any(|range| range.start != range.end) {
17838            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17839            return;
17840        }
17841
17842        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17843        let snapshot = self.snapshot(window, cx);
17844        let position = self.selections.newest::<Point>(cx).head();
17845        let mut row = snapshot
17846            .buffer_snapshot
17847            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17848            .find(|hunk| hunk.row_range.start.0 > position.row)
17849            .map(|hunk| hunk.row_range.start);
17850
17851        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17852        // Outside of the project diff editor, wrap around to the beginning.
17853        if !all_diff_hunks_expanded {
17854            row = row.or_else(|| {
17855                snapshot
17856                    .buffer_snapshot
17857                    .diff_hunks_in_range(Point::zero()..position)
17858                    .find(|hunk| hunk.row_range.end.0 < position.row)
17859                    .map(|hunk| hunk.row_range.start)
17860            });
17861        }
17862
17863        if let Some(row) = row {
17864            let destination = Point::new(row.0, 0);
17865            let autoscroll = Autoscroll::center();
17866
17867            self.unfold_ranges(&[destination..destination], false, false, cx);
17868            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17869                s.select_ranges([destination..destination]);
17870            });
17871        }
17872    }
17873
17874    fn do_stage_or_unstage(
17875        &self,
17876        stage: bool,
17877        buffer_id: BufferId,
17878        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17879        cx: &mut App,
17880    ) -> Option<()> {
17881        let project = self.project.as_ref()?;
17882        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17883        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17884        let buffer_snapshot = buffer.read(cx).snapshot();
17885        let file_exists = buffer_snapshot
17886            .file()
17887            .is_some_and(|file| file.disk_state().exists());
17888        diff.update(cx, |diff, cx| {
17889            diff.stage_or_unstage_hunks(
17890                stage,
17891                &hunks
17892                    .map(|hunk| buffer_diff::DiffHunk {
17893                        buffer_range: hunk.buffer_range,
17894                        diff_base_byte_range: hunk.diff_base_byte_range,
17895                        secondary_status: hunk.secondary_status,
17896                        range: Point::zero()..Point::zero(), // unused
17897                    })
17898                    .collect::<Vec<_>>(),
17899                &buffer_snapshot,
17900                file_exists,
17901                cx,
17902            )
17903        });
17904        None
17905    }
17906
17907    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17908        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17909        self.buffer
17910            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17911    }
17912
17913    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17914        self.buffer.update(cx, |buffer, cx| {
17915            let ranges = vec![Anchor::min()..Anchor::max()];
17916            if !buffer.all_diff_hunks_expanded()
17917                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17918            {
17919                buffer.collapse_diff_hunks(ranges, cx);
17920                true
17921            } else {
17922                false
17923            }
17924        })
17925    }
17926
17927    fn toggle_diff_hunks_in_ranges(
17928        &mut self,
17929        ranges: Vec<Range<Anchor>>,
17930        cx: &mut Context<Editor>,
17931    ) {
17932        self.buffer.update(cx, |buffer, cx| {
17933            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17934            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17935        })
17936    }
17937
17938    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17939        self.buffer.update(cx, |buffer, cx| {
17940            let snapshot = buffer.snapshot(cx);
17941            let excerpt_id = range.end.excerpt_id;
17942            let point_range = range.to_point(&snapshot);
17943            let expand = !buffer.single_hunk_is_expanded(range, cx);
17944            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17945        })
17946    }
17947
17948    pub(crate) fn apply_all_diff_hunks(
17949        &mut self,
17950        _: &ApplyAllDiffHunks,
17951        window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17955
17956        let buffers = self.buffer.read(cx).all_buffers();
17957        for branch_buffer in buffers {
17958            branch_buffer.update(cx, |branch_buffer, cx| {
17959                branch_buffer.merge_into_base(Vec::new(), cx);
17960            });
17961        }
17962
17963        if let Some(project) = self.project.clone() {
17964            self.save(
17965                SaveOptions {
17966                    format: true,
17967                    autosave: false,
17968                },
17969                project,
17970                window,
17971                cx,
17972            )
17973            .detach_and_log_err(cx);
17974        }
17975    }
17976
17977    pub(crate) fn apply_selected_diff_hunks(
17978        &mut self,
17979        _: &ApplyDiffHunk,
17980        window: &mut Window,
17981        cx: &mut Context<Self>,
17982    ) {
17983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17984        let snapshot = self.snapshot(window, cx);
17985        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17986        let mut ranges_by_buffer = HashMap::default();
17987        self.transact(window, cx, |editor, _window, cx| {
17988            for hunk in hunks {
17989                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17990                    ranges_by_buffer
17991                        .entry(buffer.clone())
17992                        .or_insert_with(Vec::new)
17993                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17994                }
17995            }
17996
17997            for (buffer, ranges) in ranges_by_buffer {
17998                buffer.update(cx, |buffer, cx| {
17999                    buffer.merge_into_base(ranges, cx);
18000                });
18001            }
18002        });
18003
18004        if let Some(project) = self.project.clone() {
18005            self.save(
18006                SaveOptions {
18007                    format: true,
18008                    autosave: false,
18009                },
18010                project,
18011                window,
18012                cx,
18013            )
18014            .detach_and_log_err(cx);
18015        }
18016    }
18017
18018    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18019        if hovered != self.gutter_hovered {
18020            self.gutter_hovered = hovered;
18021            cx.notify();
18022        }
18023    }
18024
18025    pub fn insert_blocks(
18026        &mut self,
18027        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18028        autoscroll: Option<Autoscroll>,
18029        cx: &mut Context<Self>,
18030    ) -> Vec<CustomBlockId> {
18031        let blocks = self
18032            .display_map
18033            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18034        if let Some(autoscroll) = autoscroll {
18035            self.request_autoscroll(autoscroll, cx);
18036        }
18037        cx.notify();
18038        blocks
18039    }
18040
18041    pub fn resize_blocks(
18042        &mut self,
18043        heights: HashMap<CustomBlockId, u32>,
18044        autoscroll: Option<Autoscroll>,
18045        cx: &mut Context<Self>,
18046    ) {
18047        self.display_map
18048            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18049        if let Some(autoscroll) = autoscroll {
18050            self.request_autoscroll(autoscroll, cx);
18051        }
18052        cx.notify();
18053    }
18054
18055    pub fn replace_blocks(
18056        &mut self,
18057        renderers: HashMap<CustomBlockId, RenderBlock>,
18058        autoscroll: Option<Autoscroll>,
18059        cx: &mut Context<Self>,
18060    ) {
18061        self.display_map
18062            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18063        if let Some(autoscroll) = autoscroll {
18064            self.request_autoscroll(autoscroll, cx);
18065        }
18066        cx.notify();
18067    }
18068
18069    pub fn remove_blocks(
18070        &mut self,
18071        block_ids: HashSet<CustomBlockId>,
18072        autoscroll: Option<Autoscroll>,
18073        cx: &mut Context<Self>,
18074    ) {
18075        self.display_map.update(cx, |display_map, cx| {
18076            display_map.remove_blocks(block_ids, cx)
18077        });
18078        if let Some(autoscroll) = autoscroll {
18079            self.request_autoscroll(autoscroll, cx);
18080        }
18081        cx.notify();
18082    }
18083
18084    pub fn row_for_block(
18085        &self,
18086        block_id: CustomBlockId,
18087        cx: &mut Context<Self>,
18088    ) -> Option<DisplayRow> {
18089        self.display_map
18090            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18091    }
18092
18093    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18094        self.focused_block = Some(focused_block);
18095    }
18096
18097    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18098        self.focused_block.take()
18099    }
18100
18101    pub fn insert_creases(
18102        &mut self,
18103        creases: impl IntoIterator<Item = Crease<Anchor>>,
18104        cx: &mut Context<Self>,
18105    ) -> Vec<CreaseId> {
18106        self.display_map
18107            .update(cx, |map, cx| map.insert_creases(creases, cx))
18108    }
18109
18110    pub fn remove_creases(
18111        &mut self,
18112        ids: impl IntoIterator<Item = CreaseId>,
18113        cx: &mut Context<Self>,
18114    ) -> Vec<(CreaseId, Range<Anchor>)> {
18115        self.display_map
18116            .update(cx, |map, cx| map.remove_creases(ids, cx))
18117    }
18118
18119    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18120        self.display_map
18121            .update(cx, |map, cx| map.snapshot(cx))
18122            .longest_row()
18123    }
18124
18125    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18126        self.display_map
18127            .update(cx, |map, cx| map.snapshot(cx))
18128            .max_point()
18129    }
18130
18131    pub fn text(&self, cx: &App) -> String {
18132        self.buffer.read(cx).read(cx).text()
18133    }
18134
18135    pub fn is_empty(&self, cx: &App) -> bool {
18136        self.buffer.read(cx).read(cx).is_empty()
18137    }
18138
18139    pub fn text_option(&self, cx: &App) -> Option<String> {
18140        let text = self.text(cx);
18141        let text = text.trim();
18142
18143        if text.is_empty() {
18144            return None;
18145        }
18146
18147        Some(text.to_string())
18148    }
18149
18150    pub fn set_text(
18151        &mut self,
18152        text: impl Into<Arc<str>>,
18153        window: &mut Window,
18154        cx: &mut Context<Self>,
18155    ) {
18156        self.transact(window, cx, |this, _, cx| {
18157            this.buffer
18158                .read(cx)
18159                .as_singleton()
18160                .expect("you can only call set_text on editors for singleton buffers")
18161                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18162        });
18163    }
18164
18165    pub fn display_text(&self, cx: &mut App) -> String {
18166        self.display_map
18167            .update(cx, |map, cx| map.snapshot(cx))
18168            .text()
18169    }
18170
18171    fn create_minimap(
18172        &self,
18173        minimap_settings: MinimapSettings,
18174        window: &mut Window,
18175        cx: &mut Context<Self>,
18176    ) -> Option<Entity<Self>> {
18177        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18178            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18179    }
18180
18181    fn initialize_new_minimap(
18182        &self,
18183        minimap_settings: MinimapSettings,
18184        window: &mut Window,
18185        cx: &mut Context<Self>,
18186    ) -> Entity<Self> {
18187        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18188
18189        let mut minimap = Editor::new_internal(
18190            EditorMode::Minimap {
18191                parent: cx.weak_entity(),
18192            },
18193            self.buffer.clone(),
18194            None,
18195            Some(self.display_map.clone()),
18196            window,
18197            cx,
18198        );
18199        minimap.scroll_manager.clone_state(&self.scroll_manager);
18200        minimap.set_text_style_refinement(TextStyleRefinement {
18201            font_size: Some(MINIMAP_FONT_SIZE),
18202            font_weight: Some(MINIMAP_FONT_WEIGHT),
18203            ..Default::default()
18204        });
18205        minimap.update_minimap_configuration(minimap_settings, cx);
18206        cx.new(|_| minimap)
18207    }
18208
18209    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18210        let current_line_highlight = minimap_settings
18211            .current_line_highlight
18212            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18213        self.set_current_line_highlight(Some(current_line_highlight));
18214    }
18215
18216    pub fn minimap(&self) -> Option<&Entity<Self>> {
18217        self.minimap
18218            .as_ref()
18219            .filter(|_| self.minimap_visibility.visible())
18220    }
18221
18222    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18223        let mut wrap_guides = smallvec![];
18224
18225        if self.show_wrap_guides == Some(false) {
18226            return wrap_guides;
18227        }
18228
18229        let settings = self.buffer.read(cx).language_settings(cx);
18230        if settings.show_wrap_guides {
18231            match self.soft_wrap_mode(cx) {
18232                SoftWrap::Column(soft_wrap) => {
18233                    wrap_guides.push((soft_wrap as usize, true));
18234                }
18235                SoftWrap::Bounded(soft_wrap) => {
18236                    wrap_guides.push((soft_wrap as usize, true));
18237                }
18238                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18239            }
18240            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18241        }
18242
18243        wrap_guides
18244    }
18245
18246    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18247        let settings = self.buffer.read(cx).language_settings(cx);
18248        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18249        match mode {
18250            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18251                SoftWrap::None
18252            }
18253            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18254            language_settings::SoftWrap::PreferredLineLength => {
18255                SoftWrap::Column(settings.preferred_line_length)
18256            }
18257            language_settings::SoftWrap::Bounded => {
18258                SoftWrap::Bounded(settings.preferred_line_length)
18259            }
18260        }
18261    }
18262
18263    pub fn set_soft_wrap_mode(
18264        &mut self,
18265        mode: language_settings::SoftWrap,
18266
18267        cx: &mut Context<Self>,
18268    ) {
18269        self.soft_wrap_mode_override = Some(mode);
18270        cx.notify();
18271    }
18272
18273    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18274        self.hard_wrap = hard_wrap;
18275        cx.notify();
18276    }
18277
18278    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18279        self.text_style_refinement = Some(style);
18280    }
18281
18282    /// called by the Element so we know what style we were most recently rendered with.
18283    pub(crate) fn set_style(
18284        &mut self,
18285        style: EditorStyle,
18286        window: &mut Window,
18287        cx: &mut Context<Self>,
18288    ) {
18289        // We intentionally do not inform the display map about the minimap style
18290        // so that wrapping is not recalculated and stays consistent for the editor
18291        // and its linked minimap.
18292        if !self.mode.is_minimap() {
18293            let rem_size = window.rem_size();
18294            self.display_map.update(cx, |map, cx| {
18295                map.set_font(
18296                    style.text.font(),
18297                    style.text.font_size.to_pixels(rem_size),
18298                    cx,
18299                )
18300            });
18301        }
18302        self.style = Some(style);
18303    }
18304
18305    pub fn style(&self) -> Option<&EditorStyle> {
18306        self.style.as_ref()
18307    }
18308
18309    // Called by the element. This method is not designed to be called outside of the editor
18310    // element's layout code because it does not notify when rewrapping is computed synchronously.
18311    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18312        self.display_map
18313            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18314    }
18315
18316    pub fn set_soft_wrap(&mut self) {
18317        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18318    }
18319
18320    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18321        if self.soft_wrap_mode_override.is_some() {
18322            self.soft_wrap_mode_override.take();
18323        } else {
18324            let soft_wrap = match self.soft_wrap_mode(cx) {
18325                SoftWrap::GitDiff => return,
18326                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18327                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18328                    language_settings::SoftWrap::None
18329                }
18330            };
18331            self.soft_wrap_mode_override = Some(soft_wrap);
18332        }
18333        cx.notify();
18334    }
18335
18336    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18337        let Some(workspace) = self.workspace() else {
18338            return;
18339        };
18340        let fs = workspace.read(cx).app_state().fs.clone();
18341        let current_show = TabBarSettings::get_global(cx).show;
18342        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18343            setting.show = Some(!current_show);
18344        });
18345    }
18346
18347    pub fn toggle_indent_guides(
18348        &mut self,
18349        _: &ToggleIndentGuides,
18350        _: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18354            self.buffer
18355                .read(cx)
18356                .language_settings(cx)
18357                .indent_guides
18358                .enabled
18359        });
18360        self.show_indent_guides = Some(!currently_enabled);
18361        cx.notify();
18362    }
18363
18364    fn should_show_indent_guides(&self) -> Option<bool> {
18365        self.show_indent_guides
18366    }
18367
18368    pub fn toggle_line_numbers(
18369        &mut self,
18370        _: &ToggleLineNumbers,
18371        _: &mut Window,
18372        cx: &mut Context<Self>,
18373    ) {
18374        let mut editor_settings = EditorSettings::get_global(cx).clone();
18375        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18376        EditorSettings::override_global(editor_settings, cx);
18377    }
18378
18379    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18380        if let Some(show_line_numbers) = self.show_line_numbers {
18381            return show_line_numbers;
18382        }
18383        EditorSettings::get_global(cx).gutter.line_numbers
18384    }
18385
18386    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18387        self.use_relative_line_numbers
18388            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18389    }
18390
18391    pub fn toggle_relative_line_numbers(
18392        &mut self,
18393        _: &ToggleRelativeLineNumbers,
18394        _: &mut Window,
18395        cx: &mut Context<Self>,
18396    ) {
18397        let is_relative = self.should_use_relative_line_numbers(cx);
18398        self.set_relative_line_number(Some(!is_relative), cx)
18399    }
18400
18401    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18402        self.use_relative_line_numbers = is_relative;
18403        cx.notify();
18404    }
18405
18406    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18407        self.show_gutter = show_gutter;
18408        cx.notify();
18409    }
18410
18411    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18412        self.show_scrollbars = ScrollbarAxes {
18413            horizontal: show,
18414            vertical: show,
18415        };
18416        cx.notify();
18417    }
18418
18419    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18420        self.show_scrollbars.vertical = show;
18421        cx.notify();
18422    }
18423
18424    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18425        self.show_scrollbars.horizontal = show;
18426        cx.notify();
18427    }
18428
18429    pub fn set_minimap_visibility(
18430        &mut self,
18431        minimap_visibility: MinimapVisibility,
18432        window: &mut Window,
18433        cx: &mut Context<Self>,
18434    ) {
18435        if self.minimap_visibility != minimap_visibility {
18436            if minimap_visibility.visible() && self.minimap.is_none() {
18437                let minimap_settings = EditorSettings::get_global(cx).minimap;
18438                self.minimap =
18439                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18440            }
18441            self.minimap_visibility = minimap_visibility;
18442            cx.notify();
18443        }
18444    }
18445
18446    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18447        self.set_show_scrollbars(false, cx);
18448        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18449    }
18450
18451    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18452        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18453    }
18454
18455    /// Normally the text in full mode and auto height editors is padded on the
18456    /// left side by roughly half a character width for improved hit testing.
18457    ///
18458    /// Use this method to disable this for cases where this is not wanted (e.g.
18459    /// if you want to align the editor text with some other text above or below)
18460    /// or if you want to add this padding to single-line editors.
18461    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18462        self.offset_content = offset_content;
18463        cx.notify();
18464    }
18465
18466    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18467        self.show_line_numbers = Some(show_line_numbers);
18468        cx.notify();
18469    }
18470
18471    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18472        self.disable_expand_excerpt_buttons = true;
18473        cx.notify();
18474    }
18475
18476    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18477        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18478        cx.notify();
18479    }
18480
18481    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18482        self.show_code_actions = Some(show_code_actions);
18483        cx.notify();
18484    }
18485
18486    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18487        self.show_runnables = Some(show_runnables);
18488        cx.notify();
18489    }
18490
18491    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18492        self.show_breakpoints = Some(show_breakpoints);
18493        cx.notify();
18494    }
18495
18496    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18497        if self.display_map.read(cx).masked != masked {
18498            self.display_map.update(cx, |map, _| map.masked = masked);
18499        }
18500        cx.notify()
18501    }
18502
18503    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18504        self.show_wrap_guides = Some(show_wrap_guides);
18505        cx.notify();
18506    }
18507
18508    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18509        self.show_indent_guides = Some(show_indent_guides);
18510        cx.notify();
18511    }
18512
18513    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18514        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18515            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18516                if let Some(dir) = file.abs_path(cx).parent() {
18517                    return Some(dir.to_owned());
18518                }
18519            }
18520
18521            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18522                return Some(project_path.path.to_path_buf());
18523            }
18524        }
18525
18526        None
18527    }
18528
18529    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18530        self.active_excerpt(cx)?
18531            .1
18532            .read(cx)
18533            .file()
18534            .and_then(|f| f.as_local())
18535    }
18536
18537    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18538        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18539            let buffer = buffer.read(cx);
18540            if let Some(project_path) = buffer.project_path(cx) {
18541                let project = self.project.as_ref()?.read(cx);
18542                project.absolute_path(&project_path, cx)
18543            } else {
18544                buffer
18545                    .file()
18546                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18547            }
18548        })
18549    }
18550
18551    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18552        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18553            let project_path = buffer.read(cx).project_path(cx)?;
18554            let project = self.project.as_ref()?.read(cx);
18555            let entry = project.entry_for_path(&project_path, cx)?;
18556            let path = entry.path.to_path_buf();
18557            Some(path)
18558        })
18559    }
18560
18561    pub fn reveal_in_finder(
18562        &mut self,
18563        _: &RevealInFileManager,
18564        _window: &mut Window,
18565        cx: &mut Context<Self>,
18566    ) {
18567        if let Some(target) = self.target_file(cx) {
18568            cx.reveal_path(&target.abs_path(cx));
18569        }
18570    }
18571
18572    pub fn copy_path(
18573        &mut self,
18574        _: &zed_actions::workspace::CopyPath,
18575        _window: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) {
18578        if let Some(path) = self.target_file_abs_path(cx) {
18579            if let Some(path) = path.to_str() {
18580                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18581            }
18582        }
18583    }
18584
18585    pub fn copy_relative_path(
18586        &mut self,
18587        _: &zed_actions::workspace::CopyRelativePath,
18588        _window: &mut Window,
18589        cx: &mut Context<Self>,
18590    ) {
18591        if let Some(path) = self.target_file_path(cx) {
18592            if let Some(path) = path.to_str() {
18593                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18594            }
18595        }
18596    }
18597
18598    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18599        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18600            buffer.read(cx).project_path(cx)
18601        } else {
18602            None
18603        }
18604    }
18605
18606    // Returns true if the editor handled a go-to-line request
18607    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18608        maybe!({
18609            let breakpoint_store = self.breakpoint_store.as_ref()?;
18610
18611            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18612            else {
18613                self.clear_row_highlights::<ActiveDebugLine>();
18614                return None;
18615            };
18616
18617            let position = active_stack_frame.position;
18618            let buffer_id = position.buffer_id?;
18619            let snapshot = self
18620                .project
18621                .as_ref()?
18622                .read(cx)
18623                .buffer_for_id(buffer_id, cx)?
18624                .read(cx)
18625                .snapshot();
18626
18627            let mut handled = false;
18628            for (id, ExcerptRange { context, .. }) in
18629                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18630            {
18631                if context.start.cmp(&position, &snapshot).is_ge()
18632                    || context.end.cmp(&position, &snapshot).is_lt()
18633                {
18634                    continue;
18635                }
18636                let snapshot = self.buffer.read(cx).snapshot(cx);
18637                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18638
18639                handled = true;
18640                self.clear_row_highlights::<ActiveDebugLine>();
18641
18642                self.go_to_line::<ActiveDebugLine>(
18643                    multibuffer_anchor,
18644                    Some(cx.theme().colors().editor_debugger_active_line_background),
18645                    window,
18646                    cx,
18647                );
18648
18649                cx.notify();
18650            }
18651
18652            handled.then_some(())
18653        })
18654        .is_some()
18655    }
18656
18657    pub fn copy_file_name_without_extension(
18658        &mut self,
18659        _: &CopyFileNameWithoutExtension,
18660        _: &mut Window,
18661        cx: &mut Context<Self>,
18662    ) {
18663        if let Some(file) = self.target_file(cx) {
18664            if let Some(file_stem) = file.path().file_stem() {
18665                if let Some(name) = file_stem.to_str() {
18666                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18667                }
18668            }
18669        }
18670    }
18671
18672    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18673        if let Some(file) = self.target_file(cx) {
18674            if let Some(file_name) = file.path().file_name() {
18675                if let Some(name) = file_name.to_str() {
18676                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18677                }
18678            }
18679        }
18680    }
18681
18682    pub fn toggle_git_blame(
18683        &mut self,
18684        _: &::git::Blame,
18685        window: &mut Window,
18686        cx: &mut Context<Self>,
18687    ) {
18688        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18689
18690        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18691            self.start_git_blame(true, window, cx);
18692        }
18693
18694        cx.notify();
18695    }
18696
18697    pub fn toggle_git_blame_inline(
18698        &mut self,
18699        _: &ToggleGitBlameInline,
18700        window: &mut Window,
18701        cx: &mut Context<Self>,
18702    ) {
18703        self.toggle_git_blame_inline_internal(true, window, cx);
18704        cx.notify();
18705    }
18706
18707    pub fn open_git_blame_commit(
18708        &mut self,
18709        _: &OpenGitBlameCommit,
18710        window: &mut Window,
18711        cx: &mut Context<Self>,
18712    ) {
18713        self.open_git_blame_commit_internal(window, cx);
18714    }
18715
18716    fn open_git_blame_commit_internal(
18717        &mut self,
18718        window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) -> Option<()> {
18721        let blame = self.blame.as_ref()?;
18722        let snapshot = self.snapshot(window, cx);
18723        let cursor = self.selections.newest::<Point>(cx).head();
18724        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18725        let blame_entry = blame
18726            .update(cx, |blame, cx| {
18727                blame
18728                    .blame_for_rows(
18729                        &[RowInfo {
18730                            buffer_id: Some(buffer.remote_id()),
18731                            buffer_row: Some(point.row),
18732                            ..Default::default()
18733                        }],
18734                        cx,
18735                    )
18736                    .next()
18737            })
18738            .flatten()?;
18739        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18740        let repo = blame.read(cx).repository(cx)?;
18741        let workspace = self.workspace()?.downgrade();
18742        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18743        None
18744    }
18745
18746    pub fn git_blame_inline_enabled(&self) -> bool {
18747        self.git_blame_inline_enabled
18748    }
18749
18750    pub fn toggle_selection_menu(
18751        &mut self,
18752        _: &ToggleSelectionMenu,
18753        _: &mut Window,
18754        cx: &mut Context<Self>,
18755    ) {
18756        self.show_selection_menu = self
18757            .show_selection_menu
18758            .map(|show_selections_menu| !show_selections_menu)
18759            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18760
18761        cx.notify();
18762    }
18763
18764    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18765        self.show_selection_menu
18766            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18767    }
18768
18769    fn start_git_blame(
18770        &mut self,
18771        user_triggered: bool,
18772        window: &mut Window,
18773        cx: &mut Context<Self>,
18774    ) {
18775        if let Some(project) = self.project.as_ref() {
18776            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18777                return;
18778            };
18779
18780            if buffer.read(cx).file().is_none() {
18781                return;
18782            }
18783
18784            let focused = self.focus_handle(cx).contains_focused(window, cx);
18785
18786            let project = project.clone();
18787            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18788            self.blame_subscription =
18789                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18790            self.blame = Some(blame);
18791        }
18792    }
18793
18794    fn toggle_git_blame_inline_internal(
18795        &mut self,
18796        user_triggered: bool,
18797        window: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        if self.git_blame_inline_enabled {
18801            self.git_blame_inline_enabled = false;
18802            self.show_git_blame_inline = false;
18803            self.show_git_blame_inline_delay_task.take();
18804        } else {
18805            self.git_blame_inline_enabled = true;
18806            self.start_git_blame_inline(user_triggered, window, cx);
18807        }
18808
18809        cx.notify();
18810    }
18811
18812    fn start_git_blame_inline(
18813        &mut self,
18814        user_triggered: bool,
18815        window: &mut Window,
18816        cx: &mut Context<Self>,
18817    ) {
18818        self.start_git_blame(user_triggered, window, cx);
18819
18820        if ProjectSettings::get_global(cx)
18821            .git
18822            .inline_blame_delay()
18823            .is_some()
18824        {
18825            self.start_inline_blame_timer(window, cx);
18826        } else {
18827            self.show_git_blame_inline = true
18828        }
18829    }
18830
18831    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18832        self.blame.as_ref()
18833    }
18834
18835    pub fn show_git_blame_gutter(&self) -> bool {
18836        self.show_git_blame_gutter
18837    }
18838
18839    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18840        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18841    }
18842
18843    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18844        self.show_git_blame_inline
18845            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18846            && !self.newest_selection_head_on_empty_line(cx)
18847            && self.has_blame_entries(cx)
18848    }
18849
18850    fn has_blame_entries(&self, cx: &App) -> bool {
18851        self.blame()
18852            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18853    }
18854
18855    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18856        let cursor_anchor = self.selections.newest_anchor().head();
18857
18858        let snapshot = self.buffer.read(cx).snapshot(cx);
18859        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18860
18861        snapshot.line_len(buffer_row) == 0
18862    }
18863
18864    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18865        let buffer_and_selection = maybe!({
18866            let selection = self.selections.newest::<Point>(cx);
18867            let selection_range = selection.range();
18868
18869            let multi_buffer = self.buffer().read(cx);
18870            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18871            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18872
18873            let (buffer, range, _) = if selection.reversed {
18874                buffer_ranges.first()
18875            } else {
18876                buffer_ranges.last()
18877            }?;
18878
18879            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18880                ..text::ToPoint::to_point(&range.end, &buffer).row;
18881            Some((
18882                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18883                selection,
18884            ))
18885        });
18886
18887        let Some((buffer, selection)) = buffer_and_selection else {
18888            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18889        };
18890
18891        let Some(project) = self.project.as_ref() else {
18892            return Task::ready(Err(anyhow!("editor does not have project")));
18893        };
18894
18895        project.update(cx, |project, cx| {
18896            project.get_permalink_to_line(&buffer, selection, cx)
18897        })
18898    }
18899
18900    pub fn copy_permalink_to_line(
18901        &mut self,
18902        _: &CopyPermalinkToLine,
18903        window: &mut Window,
18904        cx: &mut Context<Self>,
18905    ) {
18906        let permalink_task = self.get_permalink_to_line(cx);
18907        let workspace = self.workspace();
18908
18909        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18910            Ok(permalink) => {
18911                cx.update(|_, cx| {
18912                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18913                })
18914                .ok();
18915            }
18916            Err(err) => {
18917                let message = format!("Failed to copy permalink: {err}");
18918
18919                anyhow::Result::<()>::Err(err).log_err();
18920
18921                if let Some(workspace) = workspace {
18922                    workspace
18923                        .update_in(cx, |workspace, _, cx| {
18924                            struct CopyPermalinkToLine;
18925
18926                            workspace.show_toast(
18927                                Toast::new(
18928                                    NotificationId::unique::<CopyPermalinkToLine>(),
18929                                    message,
18930                                ),
18931                                cx,
18932                            )
18933                        })
18934                        .ok();
18935                }
18936            }
18937        })
18938        .detach();
18939    }
18940
18941    pub fn copy_file_location(
18942        &mut self,
18943        _: &CopyFileLocation,
18944        _: &mut Window,
18945        cx: &mut Context<Self>,
18946    ) {
18947        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18948        if let Some(file) = self.target_file(cx) {
18949            if let Some(path) = file.path().to_str() {
18950                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18951            }
18952        }
18953    }
18954
18955    pub fn open_permalink_to_line(
18956        &mut self,
18957        _: &OpenPermalinkToLine,
18958        window: &mut Window,
18959        cx: &mut Context<Self>,
18960    ) {
18961        let permalink_task = self.get_permalink_to_line(cx);
18962        let workspace = self.workspace();
18963
18964        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18965            Ok(permalink) => {
18966                cx.update(|_, cx| {
18967                    cx.open_url(permalink.as_ref());
18968                })
18969                .ok();
18970            }
18971            Err(err) => {
18972                let message = format!("Failed to open permalink: {err}");
18973
18974                anyhow::Result::<()>::Err(err).log_err();
18975
18976                if let Some(workspace) = workspace {
18977                    workspace
18978                        .update(cx, |workspace, cx| {
18979                            struct OpenPermalinkToLine;
18980
18981                            workspace.show_toast(
18982                                Toast::new(
18983                                    NotificationId::unique::<OpenPermalinkToLine>(),
18984                                    message,
18985                                ),
18986                                cx,
18987                            )
18988                        })
18989                        .ok();
18990                }
18991            }
18992        })
18993        .detach();
18994    }
18995
18996    pub fn insert_uuid_v4(
18997        &mut self,
18998        _: &InsertUuidV4,
18999        window: &mut Window,
19000        cx: &mut Context<Self>,
19001    ) {
19002        self.insert_uuid(UuidVersion::V4, window, cx);
19003    }
19004
19005    pub fn insert_uuid_v7(
19006        &mut self,
19007        _: &InsertUuidV7,
19008        window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) {
19011        self.insert_uuid(UuidVersion::V7, window, cx);
19012    }
19013
19014    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19015        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19016        self.transact(window, cx, |this, window, cx| {
19017            let edits = this
19018                .selections
19019                .all::<Point>(cx)
19020                .into_iter()
19021                .map(|selection| {
19022                    let uuid = match version {
19023                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19024                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19025                    };
19026
19027                    (selection.range(), uuid.to_string())
19028                });
19029            this.edit(edits, cx);
19030            this.refresh_edit_prediction(true, false, window, cx);
19031        });
19032    }
19033
19034    pub fn open_selections_in_multibuffer(
19035        &mut self,
19036        _: &OpenSelectionsInMultibuffer,
19037        window: &mut Window,
19038        cx: &mut Context<Self>,
19039    ) {
19040        let multibuffer = self.buffer.read(cx);
19041
19042        let Some(buffer) = multibuffer.as_singleton() else {
19043            return;
19044        };
19045
19046        let Some(workspace) = self.workspace() else {
19047            return;
19048        };
19049
19050        let title = multibuffer.title(cx).to_string();
19051
19052        let locations = self
19053            .selections
19054            .all_anchors(cx)
19055            .into_iter()
19056            .map(|selection| Location {
19057                buffer: buffer.clone(),
19058                range: selection.start.text_anchor..selection.end.text_anchor,
19059            })
19060            .collect::<Vec<_>>();
19061
19062        cx.spawn_in(window, async move |_, cx| {
19063            workspace.update_in(cx, |workspace, window, cx| {
19064                Self::open_locations_in_multibuffer(
19065                    workspace,
19066                    locations,
19067                    format!("Selections for '{title}'"),
19068                    false,
19069                    MultibufferSelectionMode::All,
19070                    window,
19071                    cx,
19072                );
19073            })
19074        })
19075        .detach();
19076    }
19077
19078    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19079    /// last highlight added will be used.
19080    ///
19081    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19082    pub fn highlight_rows<T: 'static>(
19083        &mut self,
19084        range: Range<Anchor>,
19085        color: Hsla,
19086        options: RowHighlightOptions,
19087        cx: &mut Context<Self>,
19088    ) {
19089        let snapshot = self.buffer().read(cx).snapshot(cx);
19090        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19091        let ix = row_highlights.binary_search_by(|highlight| {
19092            Ordering::Equal
19093                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19094                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19095        });
19096
19097        if let Err(mut ix) = ix {
19098            let index = post_inc(&mut self.highlight_order);
19099
19100            // If this range intersects with the preceding highlight, then merge it with
19101            // the preceding highlight. Otherwise insert a new highlight.
19102            let mut merged = false;
19103            if ix > 0 {
19104                let prev_highlight = &mut row_highlights[ix - 1];
19105                if prev_highlight
19106                    .range
19107                    .end
19108                    .cmp(&range.start, &snapshot)
19109                    .is_ge()
19110                {
19111                    ix -= 1;
19112                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19113                        prev_highlight.range.end = range.end;
19114                    }
19115                    merged = true;
19116                    prev_highlight.index = index;
19117                    prev_highlight.color = color;
19118                    prev_highlight.options = options;
19119                }
19120            }
19121
19122            if !merged {
19123                row_highlights.insert(
19124                    ix,
19125                    RowHighlight {
19126                        range: range.clone(),
19127                        index,
19128                        color,
19129                        options,
19130                        type_id: TypeId::of::<T>(),
19131                    },
19132                );
19133            }
19134
19135            // If any of the following highlights intersect with this one, merge them.
19136            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19137                let highlight = &row_highlights[ix];
19138                if next_highlight
19139                    .range
19140                    .start
19141                    .cmp(&highlight.range.end, &snapshot)
19142                    .is_le()
19143                {
19144                    if next_highlight
19145                        .range
19146                        .end
19147                        .cmp(&highlight.range.end, &snapshot)
19148                        .is_gt()
19149                    {
19150                        row_highlights[ix].range.end = next_highlight.range.end;
19151                    }
19152                    row_highlights.remove(ix + 1);
19153                } else {
19154                    break;
19155                }
19156            }
19157        }
19158    }
19159
19160    /// Remove any highlighted row ranges of the given type that intersect the
19161    /// given ranges.
19162    pub fn remove_highlighted_rows<T: 'static>(
19163        &mut self,
19164        ranges_to_remove: Vec<Range<Anchor>>,
19165        cx: &mut Context<Self>,
19166    ) {
19167        let snapshot = self.buffer().read(cx).snapshot(cx);
19168        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19169        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19170        row_highlights.retain(|highlight| {
19171            while let Some(range_to_remove) = ranges_to_remove.peek() {
19172                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19173                    Ordering::Less | Ordering::Equal => {
19174                        ranges_to_remove.next();
19175                    }
19176                    Ordering::Greater => {
19177                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19178                            Ordering::Less | Ordering::Equal => {
19179                                return false;
19180                            }
19181                            Ordering::Greater => break,
19182                        }
19183                    }
19184                }
19185            }
19186
19187            true
19188        })
19189    }
19190
19191    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19192    pub fn clear_row_highlights<T: 'static>(&mut self) {
19193        self.highlighted_rows.remove(&TypeId::of::<T>());
19194    }
19195
19196    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19197    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19198        self.highlighted_rows
19199            .get(&TypeId::of::<T>())
19200            .map_or(&[] as &[_], |vec| vec.as_slice())
19201            .iter()
19202            .map(|highlight| (highlight.range.clone(), highlight.color))
19203    }
19204
19205    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19206    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19207    /// Allows to ignore certain kinds of highlights.
19208    pub fn highlighted_display_rows(
19209        &self,
19210        window: &mut Window,
19211        cx: &mut App,
19212    ) -> BTreeMap<DisplayRow, LineHighlight> {
19213        let snapshot = self.snapshot(window, cx);
19214        let mut used_highlight_orders = HashMap::default();
19215        self.highlighted_rows
19216            .iter()
19217            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19218            .fold(
19219                BTreeMap::<DisplayRow, LineHighlight>::new(),
19220                |mut unique_rows, highlight| {
19221                    let start = highlight.range.start.to_display_point(&snapshot);
19222                    let end = highlight.range.end.to_display_point(&snapshot);
19223                    let start_row = start.row().0;
19224                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19225                        && end.column() == 0
19226                    {
19227                        end.row().0.saturating_sub(1)
19228                    } else {
19229                        end.row().0
19230                    };
19231                    for row in start_row..=end_row {
19232                        let used_index =
19233                            used_highlight_orders.entry(row).or_insert(highlight.index);
19234                        if highlight.index >= *used_index {
19235                            *used_index = highlight.index;
19236                            unique_rows.insert(
19237                                DisplayRow(row),
19238                                LineHighlight {
19239                                    include_gutter: highlight.options.include_gutter,
19240                                    border: None,
19241                                    background: highlight.color.into(),
19242                                    type_id: Some(highlight.type_id),
19243                                },
19244                            );
19245                        }
19246                    }
19247                    unique_rows
19248                },
19249            )
19250    }
19251
19252    pub fn highlighted_display_row_for_autoscroll(
19253        &self,
19254        snapshot: &DisplaySnapshot,
19255    ) -> Option<DisplayRow> {
19256        self.highlighted_rows
19257            .values()
19258            .flat_map(|highlighted_rows| highlighted_rows.iter())
19259            .filter_map(|highlight| {
19260                if highlight.options.autoscroll {
19261                    Some(highlight.range.start.to_display_point(snapshot).row())
19262                } else {
19263                    None
19264                }
19265            })
19266            .min()
19267    }
19268
19269    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19270        self.highlight_background::<SearchWithinRange>(
19271            ranges,
19272            |colors| colors.colors().editor_document_highlight_read_background,
19273            cx,
19274        )
19275    }
19276
19277    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19278        self.breadcrumb_header = Some(new_header);
19279    }
19280
19281    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19282        self.clear_background_highlights::<SearchWithinRange>(cx);
19283    }
19284
19285    pub fn highlight_background<T: 'static>(
19286        &mut self,
19287        ranges: &[Range<Anchor>],
19288        color_fetcher: fn(&Theme) -> Hsla,
19289        cx: &mut Context<Self>,
19290    ) {
19291        self.background_highlights.insert(
19292            HighlightKey::Type(TypeId::of::<T>()),
19293            (color_fetcher, Arc::from(ranges)),
19294        );
19295        self.scrollbar_marker_state.dirty = true;
19296        cx.notify();
19297    }
19298
19299    pub fn highlight_background_key<T: 'static>(
19300        &mut self,
19301        key: usize,
19302        ranges: &[Range<Anchor>],
19303        color_fetcher: fn(&Theme) -> Hsla,
19304        cx: &mut Context<Self>,
19305    ) {
19306        self.background_highlights.insert(
19307            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19308            (color_fetcher, Arc::from(ranges)),
19309        );
19310        self.scrollbar_marker_state.dirty = true;
19311        cx.notify();
19312    }
19313
19314    pub fn clear_background_highlights<T: 'static>(
19315        &mut self,
19316        cx: &mut Context<Self>,
19317    ) -> Option<BackgroundHighlight> {
19318        let text_highlights = self
19319            .background_highlights
19320            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19321        if !text_highlights.1.is_empty() {
19322            self.scrollbar_marker_state.dirty = true;
19323            cx.notify();
19324        }
19325        Some(text_highlights)
19326    }
19327
19328    pub fn highlight_gutter<T: 'static>(
19329        &mut self,
19330        ranges: impl Into<Vec<Range<Anchor>>>,
19331        color_fetcher: fn(&App) -> Hsla,
19332        cx: &mut Context<Self>,
19333    ) {
19334        self.gutter_highlights
19335            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19336        cx.notify();
19337    }
19338
19339    pub fn clear_gutter_highlights<T: 'static>(
19340        &mut self,
19341        cx: &mut Context<Self>,
19342    ) -> Option<GutterHighlight> {
19343        cx.notify();
19344        self.gutter_highlights.remove(&TypeId::of::<T>())
19345    }
19346
19347    pub fn insert_gutter_highlight<T: 'static>(
19348        &mut self,
19349        range: Range<Anchor>,
19350        color_fetcher: fn(&App) -> Hsla,
19351        cx: &mut Context<Self>,
19352    ) {
19353        let snapshot = self.buffer().read(cx).snapshot(cx);
19354        let mut highlights = self
19355            .gutter_highlights
19356            .remove(&TypeId::of::<T>())
19357            .map(|(_, highlights)| highlights)
19358            .unwrap_or_default();
19359        let ix = highlights.binary_search_by(|highlight| {
19360            Ordering::Equal
19361                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19362                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19363        });
19364        if let Err(ix) = ix {
19365            highlights.insert(ix, range);
19366        }
19367        self.gutter_highlights
19368            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19369    }
19370
19371    pub fn remove_gutter_highlights<T: 'static>(
19372        &mut self,
19373        ranges_to_remove: Vec<Range<Anchor>>,
19374        cx: &mut Context<Self>,
19375    ) {
19376        let snapshot = self.buffer().read(cx).snapshot(cx);
19377        let Some((color_fetcher, mut gutter_highlights)) =
19378            self.gutter_highlights.remove(&TypeId::of::<T>())
19379        else {
19380            return;
19381        };
19382        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19383        gutter_highlights.retain(|highlight| {
19384            while let Some(range_to_remove) = ranges_to_remove.peek() {
19385                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19386                    Ordering::Less | Ordering::Equal => {
19387                        ranges_to_remove.next();
19388                    }
19389                    Ordering::Greater => {
19390                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19391                            Ordering::Less | Ordering::Equal => {
19392                                return false;
19393                            }
19394                            Ordering::Greater => break,
19395                        }
19396                    }
19397                }
19398            }
19399
19400            true
19401        });
19402        self.gutter_highlights
19403            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19404    }
19405
19406    #[cfg(feature = "test-support")]
19407    pub fn all_text_highlights(
19408        &self,
19409        window: &mut Window,
19410        cx: &mut Context<Self>,
19411    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19412        let snapshot = self.snapshot(window, cx);
19413        self.display_map.update(cx, |display_map, _| {
19414            display_map
19415                .all_text_highlights()
19416                .map(|highlight| {
19417                    let (style, ranges) = highlight.as_ref();
19418                    (
19419                        *style,
19420                        ranges
19421                            .iter()
19422                            .map(|range| range.clone().to_display_points(&snapshot))
19423                            .collect(),
19424                    )
19425                })
19426                .collect()
19427        })
19428    }
19429
19430    #[cfg(feature = "test-support")]
19431    pub fn all_text_background_highlights(
19432        &self,
19433        window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19436        let snapshot = self.snapshot(window, cx);
19437        let buffer = &snapshot.buffer_snapshot;
19438        let start = buffer.anchor_before(0);
19439        let end = buffer.anchor_after(buffer.len());
19440        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19441    }
19442
19443    #[cfg(feature = "test-support")]
19444    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19445        let snapshot = self.buffer().read(cx).snapshot(cx);
19446
19447        let highlights = self
19448            .background_highlights
19449            .get(&HighlightKey::Type(TypeId::of::<
19450                items::BufferSearchHighlights,
19451            >()));
19452
19453        if let Some((_color, ranges)) = highlights {
19454            ranges
19455                .iter()
19456                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19457                .collect_vec()
19458        } else {
19459            vec![]
19460        }
19461    }
19462
19463    fn document_highlights_for_position<'a>(
19464        &'a self,
19465        position: Anchor,
19466        buffer: &'a MultiBufferSnapshot,
19467    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19468        let read_highlights = self
19469            .background_highlights
19470            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19471            .map(|h| &h.1);
19472        let write_highlights = self
19473            .background_highlights
19474            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19475            .map(|h| &h.1);
19476        let left_position = position.bias_left(buffer);
19477        let right_position = position.bias_right(buffer);
19478        read_highlights
19479            .into_iter()
19480            .chain(write_highlights)
19481            .flat_map(move |ranges| {
19482                let start_ix = match ranges.binary_search_by(|probe| {
19483                    let cmp = probe.end.cmp(&left_position, buffer);
19484                    if cmp.is_ge() {
19485                        Ordering::Greater
19486                    } else {
19487                        Ordering::Less
19488                    }
19489                }) {
19490                    Ok(i) | Err(i) => i,
19491                };
19492
19493                ranges[start_ix..]
19494                    .iter()
19495                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19496            })
19497    }
19498
19499    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19500        self.background_highlights
19501            .get(&HighlightKey::Type(TypeId::of::<T>()))
19502            .map_or(false, |(_, highlights)| !highlights.is_empty())
19503    }
19504
19505    pub fn background_highlights_in_range(
19506        &self,
19507        search_range: Range<Anchor>,
19508        display_snapshot: &DisplaySnapshot,
19509        theme: &Theme,
19510    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19511        let mut results = Vec::new();
19512        for (color_fetcher, ranges) in self.background_highlights.values() {
19513            let color = color_fetcher(theme);
19514            let start_ix = match ranges.binary_search_by(|probe| {
19515                let cmp = probe
19516                    .end
19517                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19518                if cmp.is_gt() {
19519                    Ordering::Greater
19520                } else {
19521                    Ordering::Less
19522                }
19523            }) {
19524                Ok(i) | Err(i) => i,
19525            };
19526            for range in &ranges[start_ix..] {
19527                if range
19528                    .start
19529                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19530                    .is_ge()
19531                {
19532                    break;
19533                }
19534
19535                let start = range.start.to_display_point(display_snapshot);
19536                let end = range.end.to_display_point(display_snapshot);
19537                results.push((start..end, color))
19538            }
19539        }
19540        results
19541    }
19542
19543    pub fn background_highlight_row_ranges<T: 'static>(
19544        &self,
19545        search_range: Range<Anchor>,
19546        display_snapshot: &DisplaySnapshot,
19547        count: usize,
19548    ) -> Vec<RangeInclusive<DisplayPoint>> {
19549        let mut results = Vec::new();
19550        let Some((_, ranges)) = self
19551            .background_highlights
19552            .get(&HighlightKey::Type(TypeId::of::<T>()))
19553        else {
19554            return vec![];
19555        };
19556
19557        let start_ix = match ranges.binary_search_by(|probe| {
19558            let cmp = probe
19559                .end
19560                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19561            if cmp.is_gt() {
19562                Ordering::Greater
19563            } else {
19564                Ordering::Less
19565            }
19566        }) {
19567            Ok(i) | Err(i) => i,
19568        };
19569        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19570            if let (Some(start_display), Some(end_display)) = (start, end) {
19571                results.push(
19572                    start_display.to_display_point(display_snapshot)
19573                        ..=end_display.to_display_point(display_snapshot),
19574                );
19575            }
19576        };
19577        let mut start_row: Option<Point> = None;
19578        let mut end_row: Option<Point> = None;
19579        if ranges.len() > count {
19580            return Vec::new();
19581        }
19582        for range in &ranges[start_ix..] {
19583            if range
19584                .start
19585                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19586                .is_ge()
19587            {
19588                break;
19589            }
19590            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19591            if let Some(current_row) = &end_row {
19592                if end.row == current_row.row {
19593                    continue;
19594                }
19595            }
19596            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19597            if start_row.is_none() {
19598                assert_eq!(end_row, None);
19599                start_row = Some(start);
19600                end_row = Some(end);
19601                continue;
19602            }
19603            if let Some(current_end) = end_row.as_mut() {
19604                if start.row > current_end.row + 1 {
19605                    push_region(start_row, end_row);
19606                    start_row = Some(start);
19607                    end_row = Some(end);
19608                } else {
19609                    // Merge two hunks.
19610                    *current_end = end;
19611                }
19612            } else {
19613                unreachable!();
19614            }
19615        }
19616        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19617        push_region(start_row, end_row);
19618        results
19619    }
19620
19621    pub fn gutter_highlights_in_range(
19622        &self,
19623        search_range: Range<Anchor>,
19624        display_snapshot: &DisplaySnapshot,
19625        cx: &App,
19626    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19627        let mut results = Vec::new();
19628        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19629            let color = color_fetcher(cx);
19630            let start_ix = match ranges.binary_search_by(|probe| {
19631                let cmp = probe
19632                    .end
19633                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19634                if cmp.is_gt() {
19635                    Ordering::Greater
19636                } else {
19637                    Ordering::Less
19638                }
19639            }) {
19640                Ok(i) | Err(i) => i,
19641            };
19642            for range in &ranges[start_ix..] {
19643                if range
19644                    .start
19645                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19646                    .is_ge()
19647                {
19648                    break;
19649                }
19650
19651                let start = range.start.to_display_point(display_snapshot);
19652                let end = range.end.to_display_point(display_snapshot);
19653                results.push((start..end, color))
19654            }
19655        }
19656        results
19657    }
19658
19659    /// Get the text ranges corresponding to the redaction query
19660    pub fn redacted_ranges(
19661        &self,
19662        search_range: Range<Anchor>,
19663        display_snapshot: &DisplaySnapshot,
19664        cx: &App,
19665    ) -> Vec<Range<DisplayPoint>> {
19666        display_snapshot
19667            .buffer_snapshot
19668            .redacted_ranges(search_range, |file| {
19669                if let Some(file) = file {
19670                    file.is_private()
19671                        && EditorSettings::get(
19672                            Some(SettingsLocation {
19673                                worktree_id: file.worktree_id(cx),
19674                                path: file.path().as_ref(),
19675                            }),
19676                            cx,
19677                        )
19678                        .redact_private_values
19679                } else {
19680                    false
19681                }
19682            })
19683            .map(|range| {
19684                range.start.to_display_point(display_snapshot)
19685                    ..range.end.to_display_point(display_snapshot)
19686            })
19687            .collect()
19688    }
19689
19690    pub fn highlight_text_key<T: 'static>(
19691        &mut self,
19692        key: usize,
19693        ranges: Vec<Range<Anchor>>,
19694        style: HighlightStyle,
19695        cx: &mut Context<Self>,
19696    ) {
19697        self.display_map.update(cx, |map, _| {
19698            map.highlight_text(
19699                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19700                ranges,
19701                style,
19702            );
19703        });
19704        cx.notify();
19705    }
19706
19707    pub fn highlight_text<T: 'static>(
19708        &mut self,
19709        ranges: Vec<Range<Anchor>>,
19710        style: HighlightStyle,
19711        cx: &mut Context<Self>,
19712    ) {
19713        self.display_map.update(cx, |map, _| {
19714            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19715        });
19716        cx.notify();
19717    }
19718
19719    pub(crate) fn highlight_inlays<T: 'static>(
19720        &mut self,
19721        highlights: Vec<InlayHighlight>,
19722        style: HighlightStyle,
19723        cx: &mut Context<Self>,
19724    ) {
19725        self.display_map.update(cx, |map, _| {
19726            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19727        });
19728        cx.notify();
19729    }
19730
19731    pub fn text_highlights<'a, T: 'static>(
19732        &'a self,
19733        cx: &'a App,
19734    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19735        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19736    }
19737
19738    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19739        let cleared = self
19740            .display_map
19741            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19742        if cleared {
19743            cx.notify();
19744        }
19745    }
19746
19747    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19748        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19749            && self.focus_handle.is_focused(window)
19750    }
19751
19752    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19753        self.show_cursor_when_unfocused = is_enabled;
19754        cx.notify();
19755    }
19756
19757    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19758        cx.notify();
19759    }
19760
19761    fn on_debug_session_event(
19762        &mut self,
19763        _session: Entity<Session>,
19764        event: &SessionEvent,
19765        cx: &mut Context<Self>,
19766    ) {
19767        match event {
19768            SessionEvent::InvalidateInlineValue => {
19769                self.refresh_inline_values(cx);
19770            }
19771            _ => {}
19772        }
19773    }
19774
19775    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19776        let Some(project) = self.project.clone() else {
19777            return;
19778        };
19779
19780        if !self.inline_value_cache.enabled {
19781            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19782            self.splice_inlays(&inlays, Vec::new(), cx);
19783            return;
19784        }
19785
19786        let current_execution_position = self
19787            .highlighted_rows
19788            .get(&TypeId::of::<ActiveDebugLine>())
19789            .and_then(|lines| lines.last().map(|line| line.range.end));
19790
19791        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19792            let inline_values = editor
19793                .update(cx, |editor, cx| {
19794                    let Some(current_execution_position) = current_execution_position else {
19795                        return Some(Task::ready(Ok(Vec::new())));
19796                    };
19797
19798                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19799                        let snapshot = buffer.snapshot(cx);
19800
19801                        let excerpt = snapshot.excerpt_containing(
19802                            current_execution_position..current_execution_position,
19803                        )?;
19804
19805                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19806                    })?;
19807
19808                    let range =
19809                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19810
19811                    project.inline_values(buffer, range, cx)
19812                })
19813                .ok()
19814                .flatten()?
19815                .await
19816                .context("refreshing debugger inlays")
19817                .log_err()?;
19818
19819            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19820
19821            for (buffer_id, inline_value) in inline_values
19822                .into_iter()
19823                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19824            {
19825                buffer_inline_values
19826                    .entry(buffer_id)
19827                    .or_default()
19828                    .push(inline_value);
19829            }
19830
19831            editor
19832                .update(cx, |editor, cx| {
19833                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19834                    let mut new_inlays = Vec::default();
19835
19836                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19837                        let buffer_id = buffer_snapshot.remote_id();
19838                        buffer_inline_values
19839                            .get(&buffer_id)
19840                            .into_iter()
19841                            .flatten()
19842                            .for_each(|hint| {
19843                                let inlay = Inlay::debugger(
19844                                    post_inc(&mut editor.next_inlay_id),
19845                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19846                                    hint.text(),
19847                                );
19848                                if !inlay.text.chars().contains(&'\n') {
19849                                    new_inlays.push(inlay);
19850                                }
19851                            });
19852                    }
19853
19854                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19855                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19856
19857                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19858                })
19859                .ok()?;
19860            Some(())
19861        });
19862    }
19863
19864    fn on_buffer_event(
19865        &mut self,
19866        multibuffer: &Entity<MultiBuffer>,
19867        event: &multi_buffer::Event,
19868        window: &mut Window,
19869        cx: &mut Context<Self>,
19870    ) {
19871        match event {
19872            multi_buffer::Event::Edited {
19873                singleton_buffer_edited,
19874                edited_buffer,
19875            } => {
19876                self.scrollbar_marker_state.dirty = true;
19877                self.active_indent_guides_state.dirty = true;
19878                self.refresh_active_diagnostics(cx);
19879                self.refresh_code_actions(window, cx);
19880                self.refresh_selected_text_highlights(true, window, cx);
19881                self.refresh_single_line_folds(window, cx);
19882                refresh_matching_bracket_highlights(self, window, cx);
19883                if self.has_active_edit_prediction() {
19884                    self.update_visible_edit_prediction(window, cx);
19885                }
19886                if let Some(project) = self.project.as_ref() {
19887                    if let Some(edited_buffer) = edited_buffer {
19888                        project.update(cx, |project, cx| {
19889                            self.registered_buffers
19890                                .entry(edited_buffer.read(cx).remote_id())
19891                                .or_insert_with(|| {
19892                                    project
19893                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19894                                });
19895                        });
19896                    }
19897                }
19898                cx.emit(EditorEvent::BufferEdited);
19899                cx.emit(SearchEvent::MatchesInvalidated);
19900
19901                if let Some(buffer) = edited_buffer {
19902                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19903                }
19904
19905                if *singleton_buffer_edited {
19906                    if let Some(buffer) = edited_buffer {
19907                        if buffer.read(cx).file().is_none() {
19908                            cx.emit(EditorEvent::TitleChanged);
19909                        }
19910                    }
19911                    if let Some(project) = &self.project {
19912                        #[allow(clippy::mutable_key_type)]
19913                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19914                            multibuffer
19915                                .all_buffers()
19916                                .into_iter()
19917                                .filter_map(|buffer| {
19918                                    buffer.update(cx, |buffer, cx| {
19919                                        let language = buffer.language()?;
19920                                        let should_discard = project.update(cx, |project, cx| {
19921                                            project.is_local()
19922                                                && !project.has_language_servers_for(buffer, cx)
19923                                        });
19924                                        should_discard.not().then_some(language.clone())
19925                                    })
19926                                })
19927                                .collect::<HashSet<_>>()
19928                        });
19929                        if !languages_affected.is_empty() {
19930                            self.refresh_inlay_hints(
19931                                InlayHintRefreshReason::BufferEdited(languages_affected),
19932                                cx,
19933                            );
19934                        }
19935                    }
19936                }
19937
19938                let Some(project) = &self.project else { return };
19939                let (telemetry, is_via_ssh) = {
19940                    let project = project.read(cx);
19941                    let telemetry = project.client().telemetry().clone();
19942                    let is_via_ssh = project.is_via_ssh();
19943                    (telemetry, is_via_ssh)
19944                };
19945                refresh_linked_ranges(self, window, cx);
19946                telemetry.log_edit_event("editor", is_via_ssh);
19947            }
19948            multi_buffer::Event::ExcerptsAdded {
19949                buffer,
19950                predecessor,
19951                excerpts,
19952            } => {
19953                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19954                let buffer_id = buffer.read(cx).remote_id();
19955                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19956                    if let Some(project) = &self.project {
19957                        update_uncommitted_diff_for_buffer(
19958                            cx.entity(),
19959                            project,
19960                            [buffer.clone()],
19961                            self.buffer.clone(),
19962                            cx,
19963                        )
19964                        .detach();
19965                    }
19966                }
19967                self.update_lsp_data(false, Some(buffer_id), window, cx);
19968                cx.emit(EditorEvent::ExcerptsAdded {
19969                    buffer: buffer.clone(),
19970                    predecessor: *predecessor,
19971                    excerpts: excerpts.clone(),
19972                });
19973                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19974            }
19975            multi_buffer::Event::ExcerptsRemoved {
19976                ids,
19977                removed_buffer_ids,
19978            } => {
19979                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19980                let buffer = self.buffer.read(cx);
19981                self.registered_buffers
19982                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19983                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19984                cx.emit(EditorEvent::ExcerptsRemoved {
19985                    ids: ids.clone(),
19986                    removed_buffer_ids: removed_buffer_ids.clone(),
19987                });
19988            }
19989            multi_buffer::Event::ExcerptsEdited {
19990                excerpt_ids,
19991                buffer_ids,
19992            } => {
19993                self.display_map.update(cx, |map, cx| {
19994                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19995                });
19996                cx.emit(EditorEvent::ExcerptsEdited {
19997                    ids: excerpt_ids.clone(),
19998                });
19999            }
20000            multi_buffer::Event::ExcerptsExpanded { ids } => {
20001                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20002                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20003            }
20004            multi_buffer::Event::Reparsed(buffer_id) => {
20005                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20006                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20007
20008                cx.emit(EditorEvent::Reparsed(*buffer_id));
20009            }
20010            multi_buffer::Event::DiffHunksToggled => {
20011                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20012            }
20013            multi_buffer::Event::LanguageChanged(buffer_id) => {
20014                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20015                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20016                cx.emit(EditorEvent::Reparsed(*buffer_id));
20017                cx.notify();
20018            }
20019            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20020            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20021            multi_buffer::Event::FileHandleChanged
20022            | multi_buffer::Event::Reloaded
20023            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20024            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20025            multi_buffer::Event::DiagnosticsUpdated => {
20026                self.update_diagnostics_state(window, cx);
20027            }
20028            _ => {}
20029        };
20030    }
20031
20032    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20033        if !self.diagnostics_enabled() {
20034            return;
20035        }
20036        self.refresh_active_diagnostics(cx);
20037        self.refresh_inline_diagnostics(true, window, cx);
20038        self.scrollbar_marker_state.dirty = true;
20039        cx.notify();
20040    }
20041
20042    pub fn start_temporary_diff_override(&mut self) {
20043        self.load_diff_task.take();
20044        self.temporary_diff_override = true;
20045    }
20046
20047    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20048        self.temporary_diff_override = false;
20049        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20050        self.buffer.update(cx, |buffer, cx| {
20051            buffer.set_all_diff_hunks_collapsed(cx);
20052        });
20053
20054        if let Some(project) = self.project.clone() {
20055            self.load_diff_task = Some(
20056                update_uncommitted_diff_for_buffer(
20057                    cx.entity(),
20058                    &project,
20059                    self.buffer.read(cx).all_buffers(),
20060                    self.buffer.clone(),
20061                    cx,
20062                )
20063                .shared(),
20064            );
20065        }
20066    }
20067
20068    fn on_display_map_changed(
20069        &mut self,
20070        _: Entity<DisplayMap>,
20071        _: &mut Window,
20072        cx: &mut Context<Self>,
20073    ) {
20074        cx.notify();
20075    }
20076
20077    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20078        if self.diagnostics_enabled() {
20079            let new_severity = EditorSettings::get_global(cx)
20080                .diagnostics_max_severity
20081                .unwrap_or(DiagnosticSeverity::Hint);
20082            self.set_max_diagnostics_severity(new_severity, cx);
20083        }
20084        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20085        self.update_edit_prediction_settings(cx);
20086        self.refresh_edit_prediction(true, false, window, cx);
20087        self.refresh_inline_values(cx);
20088        self.refresh_inlay_hints(
20089            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20090                self.selections.newest_anchor().head(),
20091                &self.buffer.read(cx).snapshot(cx),
20092                cx,
20093            )),
20094            cx,
20095        );
20096
20097        let old_cursor_shape = self.cursor_shape;
20098
20099        {
20100            let editor_settings = EditorSettings::get_global(cx);
20101            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20102            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20103            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20104            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20105        }
20106
20107        if old_cursor_shape != self.cursor_shape {
20108            cx.emit(EditorEvent::CursorShapeChanged);
20109        }
20110
20111        let project_settings = ProjectSettings::get_global(cx);
20112        self.serialize_dirty_buffers =
20113            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20114
20115        if self.mode.is_full() {
20116            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20117            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20118            if self.show_inline_diagnostics != show_inline_diagnostics {
20119                self.show_inline_diagnostics = show_inline_diagnostics;
20120                self.refresh_inline_diagnostics(false, window, cx);
20121            }
20122
20123            if self.git_blame_inline_enabled != inline_blame_enabled {
20124                self.toggle_git_blame_inline_internal(false, window, cx);
20125            }
20126
20127            let minimap_settings = EditorSettings::get_global(cx).minimap;
20128            if self.minimap_visibility != MinimapVisibility::Disabled {
20129                if self.minimap_visibility.settings_visibility()
20130                    != minimap_settings.minimap_enabled()
20131                {
20132                    self.set_minimap_visibility(
20133                        MinimapVisibility::for_mode(self.mode(), cx),
20134                        window,
20135                        cx,
20136                    );
20137                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20138                    minimap_entity.update(cx, |minimap_editor, cx| {
20139                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20140                    })
20141                }
20142            }
20143        }
20144
20145        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20146            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20147        }) {
20148            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20149                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20150            }
20151            self.refresh_colors(false, None, window, cx);
20152        }
20153
20154        cx.notify();
20155    }
20156
20157    pub fn set_searchable(&mut self, searchable: bool) {
20158        self.searchable = searchable;
20159    }
20160
20161    pub fn searchable(&self) -> bool {
20162        self.searchable
20163    }
20164
20165    fn open_proposed_changes_editor(
20166        &mut self,
20167        _: &OpenProposedChangesEditor,
20168        window: &mut Window,
20169        cx: &mut Context<Self>,
20170    ) {
20171        let Some(workspace) = self.workspace() else {
20172            cx.propagate();
20173            return;
20174        };
20175
20176        let selections = self.selections.all::<usize>(cx);
20177        let multi_buffer = self.buffer.read(cx);
20178        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20179        let mut new_selections_by_buffer = HashMap::default();
20180        for selection in selections {
20181            for (buffer, range, _) in
20182                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20183            {
20184                let mut range = range.to_point(buffer);
20185                range.start.column = 0;
20186                range.end.column = buffer.line_len(range.end.row);
20187                new_selections_by_buffer
20188                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20189                    .or_insert(Vec::new())
20190                    .push(range)
20191            }
20192        }
20193
20194        let proposed_changes_buffers = new_selections_by_buffer
20195            .into_iter()
20196            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20197            .collect::<Vec<_>>();
20198        let proposed_changes_editor = cx.new(|cx| {
20199            ProposedChangesEditor::new(
20200                "Proposed changes",
20201                proposed_changes_buffers,
20202                self.project.clone(),
20203                window,
20204                cx,
20205            )
20206        });
20207
20208        window.defer(cx, move |window, cx| {
20209            workspace.update(cx, |workspace, cx| {
20210                workspace.active_pane().update(cx, |pane, cx| {
20211                    pane.add_item(
20212                        Box::new(proposed_changes_editor),
20213                        true,
20214                        true,
20215                        None,
20216                        window,
20217                        cx,
20218                    );
20219                });
20220            });
20221        });
20222    }
20223
20224    pub fn open_excerpts_in_split(
20225        &mut self,
20226        _: &OpenExcerptsSplit,
20227        window: &mut Window,
20228        cx: &mut Context<Self>,
20229    ) {
20230        self.open_excerpts_common(None, true, window, cx)
20231    }
20232
20233    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20234        self.open_excerpts_common(None, false, window, cx)
20235    }
20236
20237    fn open_excerpts_common(
20238        &mut self,
20239        jump_data: Option<JumpData>,
20240        split: bool,
20241        window: &mut Window,
20242        cx: &mut Context<Self>,
20243    ) {
20244        let Some(workspace) = self.workspace() else {
20245            cx.propagate();
20246            return;
20247        };
20248
20249        if self.buffer.read(cx).is_singleton() {
20250            cx.propagate();
20251            return;
20252        }
20253
20254        let mut new_selections_by_buffer = HashMap::default();
20255        match &jump_data {
20256            Some(JumpData::MultiBufferPoint {
20257                excerpt_id,
20258                position,
20259                anchor,
20260                line_offset_from_top,
20261            }) => {
20262                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20263                if let Some(buffer) = multi_buffer_snapshot
20264                    .buffer_id_for_excerpt(*excerpt_id)
20265                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20266                {
20267                    let buffer_snapshot = buffer.read(cx).snapshot();
20268                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20269                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20270                    } else {
20271                        buffer_snapshot.clip_point(*position, Bias::Left)
20272                    };
20273                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20274                    new_selections_by_buffer.insert(
20275                        buffer,
20276                        (
20277                            vec![jump_to_offset..jump_to_offset],
20278                            Some(*line_offset_from_top),
20279                        ),
20280                    );
20281                }
20282            }
20283            Some(JumpData::MultiBufferRow {
20284                row,
20285                line_offset_from_top,
20286            }) => {
20287                let point = MultiBufferPoint::new(row.0, 0);
20288                if let Some((buffer, buffer_point, _)) =
20289                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20290                {
20291                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20292                    new_selections_by_buffer
20293                        .entry(buffer)
20294                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20295                        .0
20296                        .push(buffer_offset..buffer_offset)
20297                }
20298            }
20299            None => {
20300                let selections = self.selections.all::<usize>(cx);
20301                let multi_buffer = self.buffer.read(cx);
20302                for selection in selections {
20303                    for (snapshot, range, _, anchor) in multi_buffer
20304                        .snapshot(cx)
20305                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20306                    {
20307                        if let Some(anchor) = anchor {
20308                            // selection is in a deleted hunk
20309                            let Some(buffer_id) = anchor.buffer_id else {
20310                                continue;
20311                            };
20312                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20313                                continue;
20314                            };
20315                            let offset = text::ToOffset::to_offset(
20316                                &anchor.text_anchor,
20317                                &buffer_handle.read(cx).snapshot(),
20318                            );
20319                            let range = offset..offset;
20320                            new_selections_by_buffer
20321                                .entry(buffer_handle)
20322                                .or_insert((Vec::new(), None))
20323                                .0
20324                                .push(range)
20325                        } else {
20326                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20327                            else {
20328                                continue;
20329                            };
20330                            new_selections_by_buffer
20331                                .entry(buffer_handle)
20332                                .or_insert((Vec::new(), None))
20333                                .0
20334                                .push(range)
20335                        }
20336                    }
20337                }
20338            }
20339        }
20340
20341        new_selections_by_buffer
20342            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20343
20344        if new_selections_by_buffer.is_empty() {
20345            return;
20346        }
20347
20348        // We defer the pane interaction because we ourselves are a workspace item
20349        // and activating a new item causes the pane to call a method on us reentrantly,
20350        // which panics if we're on the stack.
20351        window.defer(cx, move |window, cx| {
20352            workspace.update(cx, |workspace, cx| {
20353                let pane = if split {
20354                    workspace.adjacent_pane(window, cx)
20355                } else {
20356                    workspace.active_pane().clone()
20357                };
20358
20359                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20360                    let editor = buffer
20361                        .read(cx)
20362                        .file()
20363                        .is_none()
20364                        .then(|| {
20365                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20366                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20367                            // Instead, we try to activate the existing editor in the pane first.
20368                            let (editor, pane_item_index) =
20369                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20370                                    let editor = item.downcast::<Editor>()?;
20371                                    let singleton_buffer =
20372                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20373                                    if singleton_buffer == buffer {
20374                                        Some((editor, i))
20375                                    } else {
20376                                        None
20377                                    }
20378                                })?;
20379                            pane.update(cx, |pane, cx| {
20380                                pane.activate_item(pane_item_index, true, true, window, cx)
20381                            });
20382                            Some(editor)
20383                        })
20384                        .flatten()
20385                        .unwrap_or_else(|| {
20386                            workspace.open_project_item::<Self>(
20387                                pane.clone(),
20388                                buffer,
20389                                true,
20390                                true,
20391                                window,
20392                                cx,
20393                            )
20394                        });
20395
20396                    editor.update(cx, |editor, cx| {
20397                        let autoscroll = match scroll_offset {
20398                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20399                            None => Autoscroll::newest(),
20400                        };
20401                        let nav_history = editor.nav_history.take();
20402                        editor.change_selections(
20403                            SelectionEffects::scroll(autoscroll),
20404                            window,
20405                            cx,
20406                            |s| {
20407                                s.select_ranges(ranges);
20408                            },
20409                        );
20410                        editor.nav_history = nav_history;
20411                    });
20412                }
20413            })
20414        });
20415    }
20416
20417    // For now, don't allow opening excerpts in buffers that aren't backed by
20418    // regular project files.
20419    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20420        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20421    }
20422
20423    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20424        let snapshot = self.buffer.read(cx).read(cx);
20425        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20426        Some(
20427            ranges
20428                .iter()
20429                .map(move |range| {
20430                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20431                })
20432                .collect(),
20433        )
20434    }
20435
20436    fn selection_replacement_ranges(
20437        &self,
20438        range: Range<OffsetUtf16>,
20439        cx: &mut App,
20440    ) -> Vec<Range<OffsetUtf16>> {
20441        let selections = self.selections.all::<OffsetUtf16>(cx);
20442        let newest_selection = selections
20443            .iter()
20444            .max_by_key(|selection| selection.id)
20445            .unwrap();
20446        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20447        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20448        let snapshot = self.buffer.read(cx).read(cx);
20449        selections
20450            .into_iter()
20451            .map(|mut selection| {
20452                selection.start.0 =
20453                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20454                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20455                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20456                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20457            })
20458            .collect()
20459    }
20460
20461    fn report_editor_event(
20462        &self,
20463        event_type: &'static str,
20464        file_extension: Option<String>,
20465        cx: &App,
20466    ) {
20467        if cfg!(any(test, feature = "test-support")) {
20468            return;
20469        }
20470
20471        let Some(project) = &self.project else { return };
20472
20473        // If None, we are in a file without an extension
20474        let file = self
20475            .buffer
20476            .read(cx)
20477            .as_singleton()
20478            .and_then(|b| b.read(cx).file());
20479        let file_extension = file_extension.or(file
20480            .as_ref()
20481            .and_then(|file| Path::new(file.file_name(cx)).extension())
20482            .and_then(|e| e.to_str())
20483            .map(|a| a.to_string()));
20484
20485        let vim_mode = vim_enabled(cx);
20486
20487        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20488        let copilot_enabled = edit_predictions_provider
20489            == language::language_settings::EditPredictionProvider::Copilot;
20490        let copilot_enabled_for_language = self
20491            .buffer
20492            .read(cx)
20493            .language_settings(cx)
20494            .show_edit_predictions;
20495
20496        let project = project.read(cx);
20497        telemetry::event!(
20498            event_type,
20499            file_extension,
20500            vim_mode,
20501            copilot_enabled,
20502            copilot_enabled_for_language,
20503            edit_predictions_provider,
20504            is_via_ssh = project.is_via_ssh(),
20505        );
20506    }
20507
20508    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20509    /// with each line being an array of {text, highlight} objects.
20510    fn copy_highlight_json(
20511        &mut self,
20512        _: &CopyHighlightJson,
20513        window: &mut Window,
20514        cx: &mut Context<Self>,
20515    ) {
20516        #[derive(Serialize)]
20517        struct Chunk<'a> {
20518            text: String,
20519            highlight: Option<&'a str>,
20520        }
20521
20522        let snapshot = self.buffer.read(cx).snapshot(cx);
20523        let range = self
20524            .selected_text_range(false, window, cx)
20525            .and_then(|selection| {
20526                if selection.range.is_empty() {
20527                    None
20528                } else {
20529                    Some(selection.range)
20530                }
20531            })
20532            .unwrap_or_else(|| 0..snapshot.len());
20533
20534        let chunks = snapshot.chunks(range, true);
20535        let mut lines = Vec::new();
20536        let mut line: VecDeque<Chunk> = VecDeque::new();
20537
20538        let Some(style) = self.style.as_ref() else {
20539            return;
20540        };
20541
20542        for chunk in chunks {
20543            let highlight = chunk
20544                .syntax_highlight_id
20545                .and_then(|id| id.name(&style.syntax));
20546            let mut chunk_lines = chunk.text.split('\n').peekable();
20547            while let Some(text) = chunk_lines.next() {
20548                let mut merged_with_last_token = false;
20549                if let Some(last_token) = line.back_mut() {
20550                    if last_token.highlight == highlight {
20551                        last_token.text.push_str(text);
20552                        merged_with_last_token = true;
20553                    }
20554                }
20555
20556                if !merged_with_last_token {
20557                    line.push_back(Chunk {
20558                        text: text.into(),
20559                        highlight,
20560                    });
20561                }
20562
20563                if chunk_lines.peek().is_some() {
20564                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20565                        line.pop_front();
20566                    }
20567                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20568                        line.pop_back();
20569                    }
20570
20571                    lines.push(mem::take(&mut line));
20572                }
20573            }
20574        }
20575
20576        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20577            return;
20578        };
20579        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20580    }
20581
20582    pub fn open_context_menu(
20583        &mut self,
20584        _: &OpenContextMenu,
20585        window: &mut Window,
20586        cx: &mut Context<Self>,
20587    ) {
20588        self.request_autoscroll(Autoscroll::newest(), cx);
20589        let position = self.selections.newest_display(cx).start;
20590        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20591    }
20592
20593    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20594        &self.inlay_hint_cache
20595    }
20596
20597    pub fn replay_insert_event(
20598        &mut self,
20599        text: &str,
20600        relative_utf16_range: Option<Range<isize>>,
20601        window: &mut Window,
20602        cx: &mut Context<Self>,
20603    ) {
20604        if !self.input_enabled {
20605            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20606            return;
20607        }
20608        if let Some(relative_utf16_range) = relative_utf16_range {
20609            let selections = self.selections.all::<OffsetUtf16>(cx);
20610            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20611                let new_ranges = selections.into_iter().map(|range| {
20612                    let start = OffsetUtf16(
20613                        range
20614                            .head()
20615                            .0
20616                            .saturating_add_signed(relative_utf16_range.start),
20617                    );
20618                    let end = OffsetUtf16(
20619                        range
20620                            .head()
20621                            .0
20622                            .saturating_add_signed(relative_utf16_range.end),
20623                    );
20624                    start..end
20625                });
20626                s.select_ranges(new_ranges);
20627            });
20628        }
20629
20630        self.handle_input(text, window, cx);
20631    }
20632
20633    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20634        let Some(provider) = self.semantics_provider.as_ref() else {
20635            return false;
20636        };
20637
20638        let mut supports = false;
20639        self.buffer().update(cx, |this, cx| {
20640            this.for_each_buffer(|buffer| {
20641                supports |= provider.supports_inlay_hints(buffer, cx);
20642            });
20643        });
20644
20645        supports
20646    }
20647
20648    pub fn is_focused(&self, window: &Window) -> bool {
20649        self.focus_handle.is_focused(window)
20650    }
20651
20652    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20653        cx.emit(EditorEvent::Focused);
20654
20655        if let Some(descendant) = self
20656            .last_focused_descendant
20657            .take()
20658            .and_then(|descendant| descendant.upgrade())
20659        {
20660            window.focus(&descendant);
20661        } else {
20662            if let Some(blame) = self.blame.as_ref() {
20663                blame.update(cx, GitBlame::focus)
20664            }
20665
20666            self.blink_manager.update(cx, BlinkManager::enable);
20667            self.show_cursor_names(window, cx);
20668            self.buffer.update(cx, |buffer, cx| {
20669                buffer.finalize_last_transaction(cx);
20670                if self.leader_id.is_none() {
20671                    buffer.set_active_selections(
20672                        &self.selections.disjoint_anchors(),
20673                        self.selections.line_mode,
20674                        self.cursor_shape,
20675                        cx,
20676                    );
20677                }
20678            });
20679        }
20680    }
20681
20682    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20683        cx.emit(EditorEvent::FocusedIn)
20684    }
20685
20686    fn handle_focus_out(
20687        &mut self,
20688        event: FocusOutEvent,
20689        _window: &mut Window,
20690        cx: &mut Context<Self>,
20691    ) {
20692        if event.blurred != self.focus_handle {
20693            self.last_focused_descendant = Some(event.blurred);
20694        }
20695        self.selection_drag_state = SelectionDragState::None;
20696        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20697    }
20698
20699    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20700        self.blink_manager.update(cx, BlinkManager::disable);
20701        self.buffer
20702            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20703
20704        if let Some(blame) = self.blame.as_ref() {
20705            blame.update(cx, GitBlame::blur)
20706        }
20707        if !self.hover_state.focused(window, cx) {
20708            hide_hover(self, cx);
20709        }
20710        if !self
20711            .context_menu
20712            .borrow()
20713            .as_ref()
20714            .is_some_and(|context_menu| context_menu.focused(window, cx))
20715        {
20716            self.hide_context_menu(window, cx);
20717        }
20718        self.discard_edit_prediction(false, cx);
20719        cx.emit(EditorEvent::Blurred);
20720        cx.notify();
20721    }
20722
20723    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20724        let mut pending: String = window
20725            .pending_input_keystrokes()
20726            .into_iter()
20727            .flatten()
20728            .filter_map(|keystroke| {
20729                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20730                    keystroke.key_char.clone()
20731                } else {
20732                    None
20733                }
20734            })
20735            .collect();
20736
20737        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20738            pending = "".to_string();
20739        }
20740
20741        let existing_pending = self
20742            .text_highlights::<PendingInput>(cx)
20743            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20744        if existing_pending.is_none() && pending.is_empty() {
20745            return;
20746        }
20747        let transaction =
20748            self.transact(window, cx, |this, window, cx| {
20749                let selections = this.selections.all::<usize>(cx);
20750                let edits = selections
20751                    .iter()
20752                    .map(|selection| (selection.end..selection.end, pending.clone()));
20753                this.edit(edits, cx);
20754                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20755                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20756                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20757                    }));
20758                });
20759                if let Some(existing_ranges) = existing_pending {
20760                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20761                    this.edit(edits, cx);
20762                }
20763            });
20764
20765        let snapshot = self.snapshot(window, cx);
20766        let ranges = self
20767            .selections
20768            .all::<usize>(cx)
20769            .into_iter()
20770            .map(|selection| {
20771                snapshot.buffer_snapshot.anchor_after(selection.end)
20772                    ..snapshot
20773                        .buffer_snapshot
20774                        .anchor_before(selection.end + pending.len())
20775            })
20776            .collect();
20777
20778        if pending.is_empty() {
20779            self.clear_highlights::<PendingInput>(cx);
20780        } else {
20781            self.highlight_text::<PendingInput>(
20782                ranges,
20783                HighlightStyle {
20784                    underline: Some(UnderlineStyle {
20785                        thickness: px(1.),
20786                        color: None,
20787                        wavy: false,
20788                    }),
20789                    ..Default::default()
20790                },
20791                cx,
20792            );
20793        }
20794
20795        self.ime_transaction = self.ime_transaction.or(transaction);
20796        if let Some(transaction) = self.ime_transaction {
20797            self.buffer.update(cx, |buffer, cx| {
20798                buffer.group_until_transaction(transaction, cx);
20799            });
20800        }
20801
20802        if self.text_highlights::<PendingInput>(cx).is_none() {
20803            self.ime_transaction.take();
20804        }
20805    }
20806
20807    pub fn register_action_renderer(
20808        &mut self,
20809        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20810    ) -> Subscription {
20811        let id = self.next_editor_action_id.post_inc();
20812        self.editor_actions
20813            .borrow_mut()
20814            .insert(id, Box::new(listener));
20815
20816        let editor_actions = self.editor_actions.clone();
20817        Subscription::new(move || {
20818            editor_actions.borrow_mut().remove(&id);
20819        })
20820    }
20821
20822    pub fn register_action<A: Action>(
20823        &mut self,
20824        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20825    ) -> Subscription {
20826        let id = self.next_editor_action_id.post_inc();
20827        let listener = Arc::new(listener);
20828        self.editor_actions.borrow_mut().insert(
20829            id,
20830            Box::new(move |_, window, _| {
20831                let listener = listener.clone();
20832                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20833                    let action = action.downcast_ref().unwrap();
20834                    if phase == DispatchPhase::Bubble {
20835                        listener(action, window, cx)
20836                    }
20837                })
20838            }),
20839        );
20840
20841        let editor_actions = self.editor_actions.clone();
20842        Subscription::new(move || {
20843            editor_actions.borrow_mut().remove(&id);
20844        })
20845    }
20846
20847    pub fn file_header_size(&self) -> u32 {
20848        FILE_HEADER_HEIGHT
20849    }
20850
20851    pub fn restore(
20852        &mut self,
20853        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20854        window: &mut Window,
20855        cx: &mut Context<Self>,
20856    ) {
20857        let workspace = self.workspace();
20858        let project = self.project.as_ref();
20859        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20860            let mut tasks = Vec::new();
20861            for (buffer_id, changes) in revert_changes {
20862                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20863                    buffer.update(cx, |buffer, cx| {
20864                        buffer.edit(
20865                            changes
20866                                .into_iter()
20867                                .map(|(range, text)| (range, text.to_string())),
20868                            None,
20869                            cx,
20870                        );
20871                    });
20872
20873                    if let Some(project) =
20874                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20875                    {
20876                        project.update(cx, |project, cx| {
20877                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20878                        })
20879                    }
20880                }
20881            }
20882            tasks
20883        });
20884        cx.spawn_in(window, async move |_, cx| {
20885            for (buffer, task) in save_tasks {
20886                let result = task.await;
20887                if result.is_err() {
20888                    let Some(path) = buffer
20889                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20890                        .ok()
20891                    else {
20892                        continue;
20893                    };
20894                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20895                        let Some(task) = cx
20896                            .update_window_entity(&workspace, |workspace, window, cx| {
20897                                workspace
20898                                    .open_path_preview(path, None, false, false, false, window, cx)
20899                            })
20900                            .ok()
20901                        else {
20902                            continue;
20903                        };
20904                        task.await.log_err();
20905                    }
20906                }
20907            }
20908        })
20909        .detach();
20910        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20911            selections.refresh()
20912        });
20913    }
20914
20915    pub fn to_pixel_point(
20916        &self,
20917        source: multi_buffer::Anchor,
20918        editor_snapshot: &EditorSnapshot,
20919        window: &mut Window,
20920    ) -> Option<gpui::Point<Pixels>> {
20921        let source_point = source.to_display_point(editor_snapshot);
20922        self.display_to_pixel_point(source_point, editor_snapshot, window)
20923    }
20924
20925    pub fn display_to_pixel_point(
20926        &self,
20927        source: DisplayPoint,
20928        editor_snapshot: &EditorSnapshot,
20929        window: &mut Window,
20930    ) -> Option<gpui::Point<Pixels>> {
20931        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20932        let text_layout_details = self.text_layout_details(window);
20933        let scroll_top = text_layout_details
20934            .scroll_anchor
20935            .scroll_position(editor_snapshot)
20936            .y;
20937
20938        if source.row().as_f32() < scroll_top.floor() {
20939            return None;
20940        }
20941        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20942        let source_y = line_height * (source.row().as_f32() - scroll_top);
20943        Some(gpui::Point::new(source_x, source_y))
20944    }
20945
20946    pub fn has_visible_completions_menu(&self) -> bool {
20947        !self.edit_prediction_preview_is_active()
20948            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20949                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20950            })
20951    }
20952
20953    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20954        if self.mode.is_minimap() {
20955            return;
20956        }
20957        self.addons
20958            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20959    }
20960
20961    pub fn unregister_addon<T: Addon>(&mut self) {
20962        self.addons.remove(&std::any::TypeId::of::<T>());
20963    }
20964
20965    pub fn addon<T: Addon>(&self) -> Option<&T> {
20966        let type_id = std::any::TypeId::of::<T>();
20967        self.addons
20968            .get(&type_id)
20969            .and_then(|item| item.to_any().downcast_ref::<T>())
20970    }
20971
20972    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20973        let type_id = std::any::TypeId::of::<T>();
20974        self.addons
20975            .get_mut(&type_id)
20976            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20977    }
20978
20979    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20980        let text_layout_details = self.text_layout_details(window);
20981        let style = &text_layout_details.editor_style;
20982        let font_id = window.text_system().resolve_font(&style.text.font());
20983        let font_size = style.text.font_size.to_pixels(window.rem_size());
20984        let line_height = style.text.line_height_in_pixels(window.rem_size());
20985        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20986        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20987
20988        CharacterDimensions {
20989            em_width,
20990            em_advance,
20991            line_height,
20992        }
20993    }
20994
20995    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20996        self.load_diff_task.clone()
20997    }
20998
20999    fn read_metadata_from_db(
21000        &mut self,
21001        item_id: u64,
21002        workspace_id: WorkspaceId,
21003        window: &mut Window,
21004        cx: &mut Context<Editor>,
21005    ) {
21006        if self.is_singleton(cx)
21007            && !self.mode.is_minimap()
21008            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21009        {
21010            let buffer_snapshot = OnceCell::new();
21011
21012            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21013                if !folds.is_empty() {
21014                    let snapshot =
21015                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21016                    self.fold_ranges(
21017                        folds
21018                            .into_iter()
21019                            .map(|(start, end)| {
21020                                snapshot.clip_offset(start, Bias::Left)
21021                                    ..snapshot.clip_offset(end, Bias::Right)
21022                            })
21023                            .collect(),
21024                        false,
21025                        window,
21026                        cx,
21027                    );
21028                }
21029            }
21030
21031            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21032                if !selections.is_empty() {
21033                    let snapshot =
21034                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21035                    // skip adding the initial selection to selection history
21036                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21037                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21038                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21039                            snapshot.clip_offset(start, Bias::Left)
21040                                ..snapshot.clip_offset(end, Bias::Right)
21041                        }));
21042                    });
21043                    self.selection_history.mode = SelectionHistoryMode::Normal;
21044                }
21045            };
21046        }
21047
21048        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21049    }
21050
21051    fn update_lsp_data(
21052        &mut self,
21053        ignore_cache: bool,
21054        for_buffer: Option<BufferId>,
21055        window: &mut Window,
21056        cx: &mut Context<'_, Self>,
21057    ) {
21058        self.pull_diagnostics(for_buffer, window, cx);
21059        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21060    }
21061}
21062
21063fn vim_enabled(cx: &App) -> bool {
21064    cx.global::<SettingsStore>()
21065        .raw_user_settings()
21066        .get("vim_mode")
21067        == Some(&serde_json::Value::Bool(true))
21068}
21069
21070fn process_completion_for_edit(
21071    completion: &Completion,
21072    intent: CompletionIntent,
21073    buffer: &Entity<Buffer>,
21074    cursor_position: &text::Anchor,
21075    cx: &mut Context<Editor>,
21076) -> CompletionEdit {
21077    let buffer = buffer.read(cx);
21078    let buffer_snapshot = buffer.snapshot();
21079    let (snippet, new_text) = if completion.is_snippet() {
21080        // Workaround for typescript language server issues so that methods don't expand within
21081        // strings and functions with type expressions. The previous point is used because the query
21082        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21083        let mut snippet_source = completion.new_text.clone();
21084        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21085        previous_point.column = previous_point.column.saturating_sub(1);
21086        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21087            if scope.prefers_label_for_snippet_in_completion() {
21088                if let Some(label) = completion.label() {
21089                    if matches!(
21090                        completion.kind(),
21091                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21092                    ) {
21093                        snippet_source = label;
21094                    }
21095                }
21096            }
21097        }
21098        match Snippet::parse(&snippet_source).log_err() {
21099            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21100            None => (None, completion.new_text.clone()),
21101        }
21102    } else {
21103        (None, completion.new_text.clone())
21104    };
21105
21106    let mut range_to_replace = {
21107        let replace_range = &completion.replace_range;
21108        if let CompletionSource::Lsp {
21109            insert_range: Some(insert_range),
21110            ..
21111        } = &completion.source
21112        {
21113            debug_assert_eq!(
21114                insert_range.start, replace_range.start,
21115                "insert_range and replace_range should start at the same position"
21116            );
21117            debug_assert!(
21118                insert_range
21119                    .start
21120                    .cmp(&cursor_position, &buffer_snapshot)
21121                    .is_le(),
21122                "insert_range should start before or at cursor position"
21123            );
21124            debug_assert!(
21125                replace_range
21126                    .start
21127                    .cmp(&cursor_position, &buffer_snapshot)
21128                    .is_le(),
21129                "replace_range should start before or at cursor position"
21130            );
21131
21132            let should_replace = match intent {
21133                CompletionIntent::CompleteWithInsert => false,
21134                CompletionIntent::CompleteWithReplace => true,
21135                CompletionIntent::Complete | CompletionIntent::Compose => {
21136                    let insert_mode =
21137                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21138                            .completions
21139                            .lsp_insert_mode;
21140                    match insert_mode {
21141                        LspInsertMode::Insert => false,
21142                        LspInsertMode::Replace => true,
21143                        LspInsertMode::ReplaceSubsequence => {
21144                            let mut text_to_replace = buffer.chars_for_range(
21145                                buffer.anchor_before(replace_range.start)
21146                                    ..buffer.anchor_after(replace_range.end),
21147                            );
21148                            let mut current_needle = text_to_replace.next();
21149                            for haystack_ch in completion.label.text.chars() {
21150                                if let Some(needle_ch) = current_needle {
21151                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21152                                        current_needle = text_to_replace.next();
21153                                    }
21154                                }
21155                            }
21156                            current_needle.is_none()
21157                        }
21158                        LspInsertMode::ReplaceSuffix => {
21159                            if replace_range
21160                                .end
21161                                .cmp(&cursor_position, &buffer_snapshot)
21162                                .is_gt()
21163                            {
21164                                let range_after_cursor = *cursor_position..replace_range.end;
21165                                let text_after_cursor = buffer
21166                                    .text_for_range(
21167                                        buffer.anchor_before(range_after_cursor.start)
21168                                            ..buffer.anchor_after(range_after_cursor.end),
21169                                    )
21170                                    .collect::<String>()
21171                                    .to_ascii_lowercase();
21172                                completion
21173                                    .label
21174                                    .text
21175                                    .to_ascii_lowercase()
21176                                    .ends_with(&text_after_cursor)
21177                            } else {
21178                                true
21179                            }
21180                        }
21181                    }
21182                }
21183            };
21184
21185            if should_replace {
21186                replace_range.clone()
21187            } else {
21188                insert_range.clone()
21189            }
21190        } else {
21191            replace_range.clone()
21192        }
21193    };
21194
21195    if range_to_replace
21196        .end
21197        .cmp(&cursor_position, &buffer_snapshot)
21198        .is_lt()
21199    {
21200        range_to_replace.end = *cursor_position;
21201    }
21202
21203    CompletionEdit {
21204        new_text,
21205        replace_range: range_to_replace.to_offset(&buffer),
21206        snippet,
21207    }
21208}
21209
21210struct CompletionEdit {
21211    new_text: String,
21212    replace_range: Range<usize>,
21213    snippet: Option<Snippet>,
21214}
21215
21216fn insert_extra_newline_brackets(
21217    buffer: &MultiBufferSnapshot,
21218    range: Range<usize>,
21219    language: &language::LanguageScope,
21220) -> bool {
21221    let leading_whitespace_len = buffer
21222        .reversed_chars_at(range.start)
21223        .take_while(|c| c.is_whitespace() && *c != '\n')
21224        .map(|c| c.len_utf8())
21225        .sum::<usize>();
21226    let trailing_whitespace_len = buffer
21227        .chars_at(range.end)
21228        .take_while(|c| c.is_whitespace() && *c != '\n')
21229        .map(|c| c.len_utf8())
21230        .sum::<usize>();
21231    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21232
21233    language.brackets().any(|(pair, enabled)| {
21234        let pair_start = pair.start.trim_end();
21235        let pair_end = pair.end.trim_start();
21236
21237        enabled
21238            && pair.newline
21239            && buffer.contains_str_at(range.end, pair_end)
21240            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21241    })
21242}
21243
21244fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21245    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21246        [(buffer, range, _)] => (*buffer, range.clone()),
21247        _ => return false,
21248    };
21249    let pair = {
21250        let mut result: Option<BracketMatch> = None;
21251
21252        for pair in buffer
21253            .all_bracket_ranges(range.clone())
21254            .filter(move |pair| {
21255                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21256            })
21257        {
21258            let len = pair.close_range.end - pair.open_range.start;
21259
21260            if let Some(existing) = &result {
21261                let existing_len = existing.close_range.end - existing.open_range.start;
21262                if len > existing_len {
21263                    continue;
21264                }
21265            }
21266
21267            result = Some(pair);
21268        }
21269
21270        result
21271    };
21272    let Some(pair) = pair else {
21273        return false;
21274    };
21275    pair.newline_only
21276        && buffer
21277            .chars_for_range(pair.open_range.end..range.start)
21278            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21279            .all(|c| c.is_whitespace() && c != '\n')
21280}
21281
21282fn update_uncommitted_diff_for_buffer(
21283    editor: Entity<Editor>,
21284    project: &Entity<Project>,
21285    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21286    buffer: Entity<MultiBuffer>,
21287    cx: &mut App,
21288) -> Task<()> {
21289    let mut tasks = Vec::new();
21290    project.update(cx, |project, cx| {
21291        for buffer in buffers {
21292            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21293                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21294            }
21295        }
21296    });
21297    cx.spawn(async move |cx| {
21298        let diffs = future::join_all(tasks).await;
21299        if editor
21300            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21301            .unwrap_or(false)
21302        {
21303            return;
21304        }
21305
21306        buffer
21307            .update(cx, |buffer, cx| {
21308                for diff in diffs.into_iter().flatten() {
21309                    buffer.add_diff(diff, cx);
21310                }
21311            })
21312            .ok();
21313    })
21314}
21315
21316fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21317    let tab_size = tab_size.get() as usize;
21318    let mut width = offset;
21319
21320    for ch in text.chars() {
21321        width += if ch == '\t' {
21322            tab_size - (width % tab_size)
21323        } else {
21324            1
21325        };
21326    }
21327
21328    width - offset
21329}
21330
21331#[cfg(test)]
21332mod tests {
21333    use super::*;
21334
21335    #[test]
21336    fn test_string_size_with_expanded_tabs() {
21337        let nz = |val| NonZeroU32::new(val).unwrap();
21338        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21339        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21340        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21341        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21342        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21343        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21344        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21345        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21346    }
21347}
21348
21349/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21350struct WordBreakingTokenizer<'a> {
21351    input: &'a str,
21352}
21353
21354impl<'a> WordBreakingTokenizer<'a> {
21355    fn new(input: &'a str) -> Self {
21356        Self { input }
21357    }
21358}
21359
21360fn is_char_ideographic(ch: char) -> bool {
21361    use unicode_script::Script::*;
21362    use unicode_script::UnicodeScript;
21363    matches!(ch.script(), Han | Tangut | Yi)
21364}
21365
21366fn is_grapheme_ideographic(text: &str) -> bool {
21367    text.chars().any(is_char_ideographic)
21368}
21369
21370fn is_grapheme_whitespace(text: &str) -> bool {
21371    text.chars().any(|x| x.is_whitespace())
21372}
21373
21374fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21375    text.chars().next().map_or(false, |ch| {
21376        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21377    })
21378}
21379
21380#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21381enum WordBreakToken<'a> {
21382    Word { token: &'a str, grapheme_len: usize },
21383    InlineWhitespace { token: &'a str, grapheme_len: usize },
21384    Newline,
21385}
21386
21387impl<'a> Iterator for WordBreakingTokenizer<'a> {
21388    /// Yields a span, the count of graphemes in the token, and whether it was
21389    /// whitespace. Note that it also breaks at word boundaries.
21390    type Item = WordBreakToken<'a>;
21391
21392    fn next(&mut self) -> Option<Self::Item> {
21393        use unicode_segmentation::UnicodeSegmentation;
21394        if self.input.is_empty() {
21395            return None;
21396        }
21397
21398        let mut iter = self.input.graphemes(true).peekable();
21399        let mut offset = 0;
21400        let mut grapheme_len = 0;
21401        if let Some(first_grapheme) = iter.next() {
21402            let is_newline = first_grapheme == "\n";
21403            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21404            offset += first_grapheme.len();
21405            grapheme_len += 1;
21406            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21407                if let Some(grapheme) = iter.peek().copied() {
21408                    if should_stay_with_preceding_ideograph(grapheme) {
21409                        offset += grapheme.len();
21410                        grapheme_len += 1;
21411                    }
21412                }
21413            } else {
21414                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21415                let mut next_word_bound = words.peek().copied();
21416                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21417                    next_word_bound = words.next();
21418                }
21419                while let Some(grapheme) = iter.peek().copied() {
21420                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21421                        break;
21422                    };
21423                    if is_grapheme_whitespace(grapheme) != is_whitespace
21424                        || (grapheme == "\n") != is_newline
21425                    {
21426                        break;
21427                    };
21428                    offset += grapheme.len();
21429                    grapheme_len += 1;
21430                    iter.next();
21431                }
21432            }
21433            let token = &self.input[..offset];
21434            self.input = &self.input[offset..];
21435            if token == "\n" {
21436                Some(WordBreakToken::Newline)
21437            } else if is_whitespace {
21438                Some(WordBreakToken::InlineWhitespace {
21439                    token,
21440                    grapheme_len,
21441                })
21442            } else {
21443                Some(WordBreakToken::Word {
21444                    token,
21445                    grapheme_len,
21446                })
21447            }
21448        } else {
21449            None
21450        }
21451    }
21452}
21453
21454#[test]
21455fn test_word_breaking_tokenizer() {
21456    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21457        ("", &[]),
21458        ("  ", &[whitespace("  ", 2)]),
21459        ("Ʒ", &[word("Ʒ", 1)]),
21460        ("Ǽ", &[word("Ǽ", 1)]),
21461        ("", &[word("", 1)]),
21462        ("⋑⋑", &[word("⋑⋑", 2)]),
21463        (
21464            "原理,进而",
21465            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21466        ),
21467        (
21468            "hello world",
21469            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21470        ),
21471        (
21472            "hello, world",
21473            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21474        ),
21475        (
21476            "  hello world",
21477            &[
21478                whitespace("  ", 2),
21479                word("hello", 5),
21480                whitespace(" ", 1),
21481                word("world", 5),
21482            ],
21483        ),
21484        (
21485            "这是什么 \n 钢笔",
21486            &[
21487                word("", 1),
21488                word("", 1),
21489                word("", 1),
21490                word("", 1),
21491                whitespace(" ", 1),
21492                newline(),
21493                whitespace(" ", 1),
21494                word("", 1),
21495                word("", 1),
21496            ],
21497        ),
21498        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21499    ];
21500
21501    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21502        WordBreakToken::Word {
21503            token,
21504            grapheme_len,
21505        }
21506    }
21507
21508    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21509        WordBreakToken::InlineWhitespace {
21510            token,
21511            grapheme_len,
21512        }
21513    }
21514
21515    fn newline() -> WordBreakToken<'static> {
21516        WordBreakToken::Newline
21517    }
21518
21519    for (input, result) in tests {
21520        assert_eq!(
21521            WordBreakingTokenizer::new(input)
21522                .collect::<Vec<_>>()
21523                .as_slice(),
21524            *result,
21525        );
21526    }
21527}
21528
21529fn wrap_with_prefix(
21530    first_line_prefix: String,
21531    subsequent_lines_prefix: String,
21532    unwrapped_text: String,
21533    wrap_column: usize,
21534    tab_size: NonZeroU32,
21535    preserve_existing_whitespace: bool,
21536) -> String {
21537    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21538    let subsequent_lines_prefix_len =
21539        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21540    let mut wrapped_text = String::new();
21541    let mut current_line = first_line_prefix.clone();
21542    let mut is_first_line = true;
21543
21544    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21545    let mut current_line_len = first_line_prefix_len;
21546    let mut in_whitespace = false;
21547    for token in tokenizer {
21548        let have_preceding_whitespace = in_whitespace;
21549        match token {
21550            WordBreakToken::Word {
21551                token,
21552                grapheme_len,
21553            } => {
21554                in_whitespace = false;
21555                let current_prefix_len = if is_first_line {
21556                    first_line_prefix_len
21557                } else {
21558                    subsequent_lines_prefix_len
21559                };
21560                if current_line_len + grapheme_len > wrap_column
21561                    && current_line_len != current_prefix_len
21562                {
21563                    wrapped_text.push_str(current_line.trim_end());
21564                    wrapped_text.push('\n');
21565                    is_first_line = false;
21566                    current_line = subsequent_lines_prefix.clone();
21567                    current_line_len = subsequent_lines_prefix_len;
21568                }
21569                current_line.push_str(token);
21570                current_line_len += grapheme_len;
21571            }
21572            WordBreakToken::InlineWhitespace {
21573                mut token,
21574                mut grapheme_len,
21575            } => {
21576                in_whitespace = true;
21577                if have_preceding_whitespace && !preserve_existing_whitespace {
21578                    continue;
21579                }
21580                if !preserve_existing_whitespace {
21581                    token = " ";
21582                    grapheme_len = 1;
21583                }
21584                let current_prefix_len = if is_first_line {
21585                    first_line_prefix_len
21586                } else {
21587                    subsequent_lines_prefix_len
21588                };
21589                if current_line_len + grapheme_len > wrap_column {
21590                    wrapped_text.push_str(current_line.trim_end());
21591                    wrapped_text.push('\n');
21592                    is_first_line = false;
21593                    current_line = subsequent_lines_prefix.clone();
21594                    current_line_len = subsequent_lines_prefix_len;
21595                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21596                    current_line.push_str(token);
21597                    current_line_len += grapheme_len;
21598                }
21599            }
21600            WordBreakToken::Newline => {
21601                in_whitespace = true;
21602                let current_prefix_len = if is_first_line {
21603                    first_line_prefix_len
21604                } else {
21605                    subsequent_lines_prefix_len
21606                };
21607                if preserve_existing_whitespace {
21608                    wrapped_text.push_str(current_line.trim_end());
21609                    wrapped_text.push('\n');
21610                    is_first_line = false;
21611                    current_line = subsequent_lines_prefix.clone();
21612                    current_line_len = subsequent_lines_prefix_len;
21613                } else if have_preceding_whitespace {
21614                    continue;
21615                } else if current_line_len + 1 > wrap_column
21616                    && current_line_len != current_prefix_len
21617                {
21618                    wrapped_text.push_str(current_line.trim_end());
21619                    wrapped_text.push('\n');
21620                    is_first_line = false;
21621                    current_line = subsequent_lines_prefix.clone();
21622                    current_line_len = subsequent_lines_prefix_len;
21623                } else if current_line_len != current_prefix_len {
21624                    current_line.push(' ');
21625                    current_line_len += 1;
21626                }
21627            }
21628        }
21629    }
21630
21631    if !current_line.is_empty() {
21632        wrapped_text.push_str(&current_line);
21633    }
21634    wrapped_text
21635}
21636
21637#[test]
21638fn test_wrap_with_prefix() {
21639    assert_eq!(
21640        wrap_with_prefix(
21641            "# ".to_string(),
21642            "# ".to_string(),
21643            "abcdefg".to_string(),
21644            4,
21645            NonZeroU32::new(4).unwrap(),
21646            false,
21647        ),
21648        "# abcdefg"
21649    );
21650    assert_eq!(
21651        wrap_with_prefix(
21652            "".to_string(),
21653            "".to_string(),
21654            "\thello world".to_string(),
21655            8,
21656            NonZeroU32::new(4).unwrap(),
21657            false,
21658        ),
21659        "hello\nworld"
21660    );
21661    assert_eq!(
21662        wrap_with_prefix(
21663            "// ".to_string(),
21664            "// ".to_string(),
21665            "xx \nyy zz aa bb cc".to_string(),
21666            12,
21667            NonZeroU32::new(4).unwrap(),
21668            false,
21669        ),
21670        "// xx yy zz\n// aa bb cc"
21671    );
21672    assert_eq!(
21673        wrap_with_prefix(
21674            String::new(),
21675            String::new(),
21676            "这是什么 \n 钢笔".to_string(),
21677            3,
21678            NonZeroU32::new(4).unwrap(),
21679            false,
21680        ),
21681        "这是什\n么 钢\n"
21682    );
21683}
21684
21685pub trait CollaborationHub {
21686    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21687    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21688    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21689}
21690
21691impl CollaborationHub for Entity<Project> {
21692    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21693        self.read(cx).collaborators()
21694    }
21695
21696    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21697        self.read(cx).user_store().read(cx).participant_indices()
21698    }
21699
21700    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21701        let this = self.read(cx);
21702        let user_ids = this.collaborators().values().map(|c| c.user_id);
21703        this.user_store().read(cx).participant_names(user_ids, cx)
21704    }
21705}
21706
21707pub trait SemanticsProvider {
21708    fn hover(
21709        &self,
21710        buffer: &Entity<Buffer>,
21711        position: text::Anchor,
21712        cx: &mut App,
21713    ) -> Option<Task<Vec<project::Hover>>>;
21714
21715    fn inline_values(
21716        &self,
21717        buffer_handle: Entity<Buffer>,
21718        range: Range<text::Anchor>,
21719        cx: &mut App,
21720    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21721
21722    fn inlay_hints(
21723        &self,
21724        buffer_handle: Entity<Buffer>,
21725        range: Range<text::Anchor>,
21726        cx: &mut App,
21727    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21728
21729    fn resolve_inlay_hint(
21730        &self,
21731        hint: InlayHint,
21732        buffer_handle: Entity<Buffer>,
21733        server_id: LanguageServerId,
21734        cx: &mut App,
21735    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21736
21737    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21738
21739    fn document_highlights(
21740        &self,
21741        buffer: &Entity<Buffer>,
21742        position: text::Anchor,
21743        cx: &mut App,
21744    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21745
21746    fn definitions(
21747        &self,
21748        buffer: &Entity<Buffer>,
21749        position: text::Anchor,
21750        kind: GotoDefinitionKind,
21751        cx: &mut App,
21752    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21753
21754    fn range_for_rename(
21755        &self,
21756        buffer: &Entity<Buffer>,
21757        position: text::Anchor,
21758        cx: &mut App,
21759    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21760
21761    fn perform_rename(
21762        &self,
21763        buffer: &Entity<Buffer>,
21764        position: text::Anchor,
21765        new_name: String,
21766        cx: &mut App,
21767    ) -> Option<Task<Result<ProjectTransaction>>>;
21768}
21769
21770pub trait CompletionProvider {
21771    fn completions(
21772        &self,
21773        excerpt_id: ExcerptId,
21774        buffer: &Entity<Buffer>,
21775        buffer_position: text::Anchor,
21776        trigger: CompletionContext,
21777        window: &mut Window,
21778        cx: &mut Context<Editor>,
21779    ) -> Task<Result<Vec<CompletionResponse>>>;
21780
21781    fn resolve_completions(
21782        &self,
21783        _buffer: Entity<Buffer>,
21784        _completion_indices: Vec<usize>,
21785        _completions: Rc<RefCell<Box<[Completion]>>>,
21786        _cx: &mut Context<Editor>,
21787    ) -> Task<Result<bool>> {
21788        Task::ready(Ok(false))
21789    }
21790
21791    fn apply_additional_edits_for_completion(
21792        &self,
21793        _buffer: Entity<Buffer>,
21794        _completions: Rc<RefCell<Box<[Completion]>>>,
21795        _completion_index: usize,
21796        _push_to_history: bool,
21797        _cx: &mut Context<Editor>,
21798    ) -> Task<Result<Option<language::Transaction>>> {
21799        Task::ready(Ok(None))
21800    }
21801
21802    fn is_completion_trigger(
21803        &self,
21804        buffer: &Entity<Buffer>,
21805        position: language::Anchor,
21806        text: &str,
21807        trigger_in_words: bool,
21808        menu_is_open: bool,
21809        cx: &mut Context<Editor>,
21810    ) -> bool;
21811
21812    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21813
21814    fn sort_completions(&self) -> bool {
21815        true
21816    }
21817
21818    fn filter_completions(&self) -> bool {
21819        true
21820    }
21821}
21822
21823pub trait CodeActionProvider {
21824    fn id(&self) -> Arc<str>;
21825
21826    fn code_actions(
21827        &self,
21828        buffer: &Entity<Buffer>,
21829        range: Range<text::Anchor>,
21830        window: &mut Window,
21831        cx: &mut App,
21832    ) -> Task<Result<Vec<CodeAction>>>;
21833
21834    fn apply_code_action(
21835        &self,
21836        buffer_handle: Entity<Buffer>,
21837        action: CodeAction,
21838        excerpt_id: ExcerptId,
21839        push_to_history: bool,
21840        window: &mut Window,
21841        cx: &mut App,
21842    ) -> Task<Result<ProjectTransaction>>;
21843}
21844
21845impl CodeActionProvider for Entity<Project> {
21846    fn id(&self) -> Arc<str> {
21847        "project".into()
21848    }
21849
21850    fn code_actions(
21851        &self,
21852        buffer: &Entity<Buffer>,
21853        range: Range<text::Anchor>,
21854        _window: &mut Window,
21855        cx: &mut App,
21856    ) -> Task<Result<Vec<CodeAction>>> {
21857        self.update(cx, |project, cx| {
21858            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
21859            let code_actions = project.code_actions(buffer, range, None, cx);
21860            cx.background_spawn(async move {
21861                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
21862                Ok(code_lens_actions
21863                    .context("code lens fetch")?
21864                    .into_iter()
21865                    .chain(code_actions.context("code action fetch")?)
21866                    .collect())
21867            })
21868        })
21869    }
21870
21871    fn apply_code_action(
21872        &self,
21873        buffer_handle: Entity<Buffer>,
21874        action: CodeAction,
21875        _excerpt_id: ExcerptId,
21876        push_to_history: bool,
21877        _window: &mut Window,
21878        cx: &mut App,
21879    ) -> Task<Result<ProjectTransaction>> {
21880        self.update(cx, |project, cx| {
21881            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21882        })
21883    }
21884}
21885
21886fn snippet_completions(
21887    project: &Project,
21888    buffer: &Entity<Buffer>,
21889    buffer_position: text::Anchor,
21890    cx: &mut App,
21891) -> Task<Result<CompletionResponse>> {
21892    let languages = buffer.read(cx).languages_at(buffer_position);
21893    let snippet_store = project.snippets().read(cx);
21894
21895    let scopes: Vec<_> = languages
21896        .iter()
21897        .filter_map(|language| {
21898            let language_name = language.lsp_id();
21899            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21900
21901            if snippets.is_empty() {
21902                None
21903            } else {
21904                Some((language.default_scope(), snippets))
21905            }
21906        })
21907        .collect();
21908
21909    if scopes.is_empty() {
21910        return Task::ready(Ok(CompletionResponse {
21911            completions: vec![],
21912            is_incomplete: false,
21913        }));
21914    }
21915
21916    let snapshot = buffer.read(cx).text_snapshot();
21917    let chars: String = snapshot
21918        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21919        .collect();
21920    let executor = cx.background_executor().clone();
21921
21922    cx.background_spawn(async move {
21923        let mut is_incomplete = false;
21924        let mut completions: Vec<Completion> = Vec::new();
21925        for (scope, snippets) in scopes.into_iter() {
21926            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21927            let mut last_word = chars
21928                .chars()
21929                .take_while(|c| classifier.is_word(*c))
21930                .collect::<String>();
21931            last_word = last_word.chars().rev().collect();
21932
21933            if last_word.is_empty() {
21934                return Ok(CompletionResponse {
21935                    completions: vec![],
21936                    is_incomplete: true,
21937                });
21938            }
21939
21940            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21941            let to_lsp = |point: &text::Anchor| {
21942                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21943                point_to_lsp(end)
21944            };
21945            let lsp_end = to_lsp(&buffer_position);
21946
21947            let candidates = snippets
21948                .iter()
21949                .enumerate()
21950                .flat_map(|(ix, snippet)| {
21951                    snippet
21952                        .prefix
21953                        .iter()
21954                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21955                })
21956                .collect::<Vec<StringMatchCandidate>>();
21957
21958            const MAX_RESULTS: usize = 100;
21959            let mut matches = fuzzy::match_strings(
21960                &candidates,
21961                &last_word,
21962                last_word.chars().any(|c| c.is_uppercase()),
21963                true,
21964                MAX_RESULTS,
21965                &Default::default(),
21966                executor.clone(),
21967            )
21968            .await;
21969
21970            if matches.len() >= MAX_RESULTS {
21971                is_incomplete = true;
21972            }
21973
21974            // Remove all candidates where the query's start does not match the start of any word in the candidate
21975            if let Some(query_start) = last_word.chars().next() {
21976                matches.retain(|string_match| {
21977                    split_words(&string_match.string).any(|word| {
21978                        // Check that the first codepoint of the word as lowercase matches the first
21979                        // codepoint of the query as lowercase
21980                        word.chars()
21981                            .flat_map(|codepoint| codepoint.to_lowercase())
21982                            .zip(query_start.to_lowercase())
21983                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21984                    })
21985                });
21986            }
21987
21988            let matched_strings = matches
21989                .into_iter()
21990                .map(|m| m.string)
21991                .collect::<HashSet<_>>();
21992
21993            completions.extend(snippets.iter().filter_map(|snippet| {
21994                let matching_prefix = snippet
21995                    .prefix
21996                    .iter()
21997                    .find(|prefix| matched_strings.contains(*prefix))?;
21998                let start = as_offset - last_word.len();
21999                let start = snapshot.anchor_before(start);
22000                let range = start..buffer_position;
22001                let lsp_start = to_lsp(&start);
22002                let lsp_range = lsp::Range {
22003                    start: lsp_start,
22004                    end: lsp_end,
22005                };
22006                Some(Completion {
22007                    replace_range: range,
22008                    new_text: snippet.body.clone(),
22009                    source: CompletionSource::Lsp {
22010                        insert_range: None,
22011                        server_id: LanguageServerId(usize::MAX),
22012                        resolved: true,
22013                        lsp_completion: Box::new(lsp::CompletionItem {
22014                            label: snippet.prefix.first().unwrap().clone(),
22015                            kind: Some(CompletionItemKind::SNIPPET),
22016                            label_details: snippet.description.as_ref().map(|description| {
22017                                lsp::CompletionItemLabelDetails {
22018                                    detail: Some(description.clone()),
22019                                    description: None,
22020                                }
22021                            }),
22022                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22023                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22024                                lsp::InsertReplaceEdit {
22025                                    new_text: snippet.body.clone(),
22026                                    insert: lsp_range,
22027                                    replace: lsp_range,
22028                                },
22029                            )),
22030                            filter_text: Some(snippet.body.clone()),
22031                            sort_text: Some(char::MAX.to_string()),
22032                            ..lsp::CompletionItem::default()
22033                        }),
22034                        lsp_defaults: None,
22035                    },
22036                    label: CodeLabel {
22037                        text: matching_prefix.clone(),
22038                        runs: Vec::new(),
22039                        filter_range: 0..matching_prefix.len(),
22040                    },
22041                    icon_path: None,
22042                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22043                        single_line: snippet.name.clone().into(),
22044                        plain_text: snippet
22045                            .description
22046                            .clone()
22047                            .map(|description| description.into()),
22048                    }),
22049                    insert_text_mode: None,
22050                    confirm: None,
22051                })
22052            }))
22053        }
22054
22055        Ok(CompletionResponse {
22056            completions,
22057            is_incomplete,
22058        })
22059    })
22060}
22061
22062impl CompletionProvider for Entity<Project> {
22063    fn completions(
22064        &self,
22065        _excerpt_id: ExcerptId,
22066        buffer: &Entity<Buffer>,
22067        buffer_position: text::Anchor,
22068        options: CompletionContext,
22069        _window: &mut Window,
22070        cx: &mut Context<Editor>,
22071    ) -> Task<Result<Vec<CompletionResponse>>> {
22072        self.update(cx, |project, cx| {
22073            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22074            let project_completions = project.completions(buffer, buffer_position, options, cx);
22075            cx.background_spawn(async move {
22076                let mut responses = project_completions.await?;
22077                let snippets = snippets.await?;
22078                if !snippets.completions.is_empty() {
22079                    responses.push(snippets);
22080                }
22081                Ok(responses)
22082            })
22083        })
22084    }
22085
22086    fn resolve_completions(
22087        &self,
22088        buffer: Entity<Buffer>,
22089        completion_indices: Vec<usize>,
22090        completions: Rc<RefCell<Box<[Completion]>>>,
22091        cx: &mut Context<Editor>,
22092    ) -> Task<Result<bool>> {
22093        self.update(cx, |project, cx| {
22094            project.lsp_store().update(cx, |lsp_store, cx| {
22095                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22096            })
22097        })
22098    }
22099
22100    fn apply_additional_edits_for_completion(
22101        &self,
22102        buffer: Entity<Buffer>,
22103        completions: Rc<RefCell<Box<[Completion]>>>,
22104        completion_index: usize,
22105        push_to_history: bool,
22106        cx: &mut Context<Editor>,
22107    ) -> Task<Result<Option<language::Transaction>>> {
22108        self.update(cx, |project, cx| {
22109            project.lsp_store().update(cx, |lsp_store, cx| {
22110                lsp_store.apply_additional_edits_for_completion(
22111                    buffer,
22112                    completions,
22113                    completion_index,
22114                    push_to_history,
22115                    cx,
22116                )
22117            })
22118        })
22119    }
22120
22121    fn is_completion_trigger(
22122        &self,
22123        buffer: &Entity<Buffer>,
22124        position: language::Anchor,
22125        text: &str,
22126        trigger_in_words: bool,
22127        menu_is_open: bool,
22128        cx: &mut Context<Editor>,
22129    ) -> bool {
22130        let mut chars = text.chars();
22131        let char = if let Some(char) = chars.next() {
22132            char
22133        } else {
22134            return false;
22135        };
22136        if chars.next().is_some() {
22137            return false;
22138        }
22139
22140        let buffer = buffer.read(cx);
22141        let snapshot = buffer.snapshot();
22142        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22143            return false;
22144        }
22145        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22146        if trigger_in_words && classifier.is_word(char) {
22147            return true;
22148        }
22149
22150        buffer.completion_triggers().contains(text)
22151    }
22152}
22153
22154impl SemanticsProvider for Entity<Project> {
22155    fn hover(
22156        &self,
22157        buffer: &Entity<Buffer>,
22158        position: text::Anchor,
22159        cx: &mut App,
22160    ) -> Option<Task<Vec<project::Hover>>> {
22161        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22162    }
22163
22164    fn document_highlights(
22165        &self,
22166        buffer: &Entity<Buffer>,
22167        position: text::Anchor,
22168        cx: &mut App,
22169    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22170        Some(self.update(cx, |project, cx| {
22171            project.document_highlights(buffer, position, cx)
22172        }))
22173    }
22174
22175    fn definitions(
22176        &self,
22177        buffer: &Entity<Buffer>,
22178        position: text::Anchor,
22179        kind: GotoDefinitionKind,
22180        cx: &mut App,
22181    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22182        Some(self.update(cx, |project, cx| match kind {
22183            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22184            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22185            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22186            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22187        }))
22188    }
22189
22190    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22191        // TODO: make this work for remote projects
22192        self.update(cx, |project, cx| {
22193            if project
22194                .active_debug_session(cx)
22195                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22196            {
22197                return true;
22198            }
22199
22200            buffer.update(cx, |buffer, cx| {
22201                project.any_language_server_supports_inlay_hints(buffer, cx)
22202            })
22203        })
22204    }
22205
22206    fn inline_values(
22207        &self,
22208        buffer_handle: Entity<Buffer>,
22209        range: Range<text::Anchor>,
22210        cx: &mut App,
22211    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22212        self.update(cx, |project, cx| {
22213            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22214
22215            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22216        })
22217    }
22218
22219    fn inlay_hints(
22220        &self,
22221        buffer_handle: Entity<Buffer>,
22222        range: Range<text::Anchor>,
22223        cx: &mut App,
22224    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22225        Some(self.update(cx, |project, cx| {
22226            project.inlay_hints(buffer_handle, range, cx)
22227        }))
22228    }
22229
22230    fn resolve_inlay_hint(
22231        &self,
22232        hint: InlayHint,
22233        buffer_handle: Entity<Buffer>,
22234        server_id: LanguageServerId,
22235        cx: &mut App,
22236    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22237        Some(self.update(cx, |project, cx| {
22238            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22239        }))
22240    }
22241
22242    fn range_for_rename(
22243        &self,
22244        buffer: &Entity<Buffer>,
22245        position: text::Anchor,
22246        cx: &mut App,
22247    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22248        Some(self.update(cx, |project, cx| {
22249            let buffer = buffer.clone();
22250            let task = project.prepare_rename(buffer.clone(), position, cx);
22251            cx.spawn(async move |_, cx| {
22252                Ok(match task.await? {
22253                    PrepareRenameResponse::Success(range) => Some(range),
22254                    PrepareRenameResponse::InvalidPosition => None,
22255                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22256                        // Fallback on using TreeSitter info to determine identifier range
22257                        buffer.read_with(cx, |buffer, _| {
22258                            let snapshot = buffer.snapshot();
22259                            let (range, kind) = snapshot.surrounding_word(position, false);
22260                            if kind != Some(CharKind::Word) {
22261                                return None;
22262                            }
22263                            Some(
22264                                snapshot.anchor_before(range.start)
22265                                    ..snapshot.anchor_after(range.end),
22266                            )
22267                        })?
22268                    }
22269                })
22270            })
22271        }))
22272    }
22273
22274    fn perform_rename(
22275        &self,
22276        buffer: &Entity<Buffer>,
22277        position: text::Anchor,
22278        new_name: String,
22279        cx: &mut App,
22280    ) -> Option<Task<Result<ProjectTransaction>>> {
22281        Some(self.update(cx, |project, cx| {
22282            project.perform_rename(buffer.clone(), position, new_name, cx)
22283        }))
22284    }
22285}
22286
22287fn inlay_hint_settings(
22288    location: Anchor,
22289    snapshot: &MultiBufferSnapshot,
22290    cx: &mut Context<Editor>,
22291) -> InlayHintSettings {
22292    let file = snapshot.file_at(location);
22293    let language = snapshot.language_at(location).map(|l| l.name());
22294    language_settings(language, file, cx).inlay_hints
22295}
22296
22297fn consume_contiguous_rows(
22298    contiguous_row_selections: &mut Vec<Selection<Point>>,
22299    selection: &Selection<Point>,
22300    display_map: &DisplaySnapshot,
22301    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22302) -> (MultiBufferRow, MultiBufferRow) {
22303    contiguous_row_selections.push(selection.clone());
22304    let start_row = starting_row(selection, display_map);
22305    let mut end_row = ending_row(selection, display_map);
22306
22307    while let Some(next_selection) = selections.peek() {
22308        if next_selection.start.row <= end_row.0 {
22309            end_row = ending_row(next_selection, display_map);
22310            contiguous_row_selections.push(selections.next().unwrap().clone());
22311        } else {
22312            break;
22313        }
22314    }
22315    (start_row, end_row)
22316}
22317
22318fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22319    if selection.start.column > 0 {
22320        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22321    } else {
22322        MultiBufferRow(selection.start.row)
22323    }
22324}
22325
22326fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22327    if next_selection.end.column > 0 || next_selection.is_empty() {
22328        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22329    } else {
22330        MultiBufferRow(next_selection.end.row)
22331    }
22332}
22333
22334impl EditorSnapshot {
22335    pub fn remote_selections_in_range<'a>(
22336        &'a self,
22337        range: &'a Range<Anchor>,
22338        collaboration_hub: &dyn CollaborationHub,
22339        cx: &'a App,
22340    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22341        let participant_names = collaboration_hub.user_names(cx);
22342        let participant_indices = collaboration_hub.user_participant_indices(cx);
22343        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22344        let collaborators_by_replica_id = collaborators_by_peer_id
22345            .values()
22346            .map(|collaborator| (collaborator.replica_id, collaborator))
22347            .collect::<HashMap<_, _>>();
22348        self.buffer_snapshot
22349            .selections_in_range(range, false)
22350            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22351                if replica_id == AGENT_REPLICA_ID {
22352                    Some(RemoteSelection {
22353                        replica_id,
22354                        selection,
22355                        cursor_shape,
22356                        line_mode,
22357                        collaborator_id: CollaboratorId::Agent,
22358                        user_name: Some("Agent".into()),
22359                        color: cx.theme().players().agent(),
22360                    })
22361                } else {
22362                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22363                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22364                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22365                    Some(RemoteSelection {
22366                        replica_id,
22367                        selection,
22368                        cursor_shape,
22369                        line_mode,
22370                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22371                        user_name,
22372                        color: if let Some(index) = participant_index {
22373                            cx.theme().players().color_for_participant(index.0)
22374                        } else {
22375                            cx.theme().players().absent()
22376                        },
22377                    })
22378                }
22379            })
22380    }
22381
22382    pub fn hunks_for_ranges(
22383        &self,
22384        ranges: impl IntoIterator<Item = Range<Point>>,
22385    ) -> Vec<MultiBufferDiffHunk> {
22386        let mut hunks = Vec::new();
22387        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22388            HashMap::default();
22389        for query_range in ranges {
22390            let query_rows =
22391                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22392            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22393                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22394            ) {
22395                // Include deleted hunks that are adjacent to the query range, because
22396                // otherwise they would be missed.
22397                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22398                if hunk.status().is_deleted() {
22399                    intersects_range |= hunk.row_range.start == query_rows.end;
22400                    intersects_range |= hunk.row_range.end == query_rows.start;
22401                }
22402                if intersects_range {
22403                    if !processed_buffer_rows
22404                        .entry(hunk.buffer_id)
22405                        .or_default()
22406                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22407                    {
22408                        continue;
22409                    }
22410                    hunks.push(hunk);
22411                }
22412            }
22413        }
22414
22415        hunks
22416    }
22417
22418    fn display_diff_hunks_for_rows<'a>(
22419        &'a self,
22420        display_rows: Range<DisplayRow>,
22421        folded_buffers: &'a HashSet<BufferId>,
22422    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22423        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22424        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22425
22426        self.buffer_snapshot
22427            .diff_hunks_in_range(buffer_start..buffer_end)
22428            .filter_map(|hunk| {
22429                if folded_buffers.contains(&hunk.buffer_id) {
22430                    return None;
22431                }
22432
22433                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22434                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22435
22436                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22437                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22438
22439                let display_hunk = if hunk_display_start.column() != 0 {
22440                    DisplayDiffHunk::Folded {
22441                        display_row: hunk_display_start.row(),
22442                    }
22443                } else {
22444                    let mut end_row = hunk_display_end.row();
22445                    if hunk_display_end.column() > 0 {
22446                        end_row.0 += 1;
22447                    }
22448                    let is_created_file = hunk.is_created_file();
22449                    DisplayDiffHunk::Unfolded {
22450                        status: hunk.status(),
22451                        diff_base_byte_range: hunk.diff_base_byte_range,
22452                        display_row_range: hunk_display_start.row()..end_row,
22453                        multi_buffer_range: Anchor::range_in_buffer(
22454                            hunk.excerpt_id,
22455                            hunk.buffer_id,
22456                            hunk.buffer_range,
22457                        ),
22458                        is_created_file,
22459                    }
22460                };
22461
22462                Some(display_hunk)
22463            })
22464    }
22465
22466    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22467        self.display_snapshot.buffer_snapshot.language_at(position)
22468    }
22469
22470    pub fn is_focused(&self) -> bool {
22471        self.is_focused
22472    }
22473
22474    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22475        self.placeholder_text.as_ref()
22476    }
22477
22478    pub fn scroll_position(&self) -> gpui::Point<f32> {
22479        self.scroll_anchor.scroll_position(&self.display_snapshot)
22480    }
22481
22482    fn gutter_dimensions(
22483        &self,
22484        font_id: FontId,
22485        font_size: Pixels,
22486        max_line_number_width: Pixels,
22487        cx: &App,
22488    ) -> Option<GutterDimensions> {
22489        if !self.show_gutter {
22490            return None;
22491        }
22492
22493        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22494        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22495
22496        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22497            matches!(
22498                ProjectSettings::get_global(cx).git.git_gutter,
22499                Some(GitGutterSetting::TrackedFiles)
22500            )
22501        });
22502        let gutter_settings = EditorSettings::get_global(cx).gutter;
22503        let show_line_numbers = self
22504            .show_line_numbers
22505            .unwrap_or(gutter_settings.line_numbers);
22506        let line_gutter_width = if show_line_numbers {
22507            // Avoid flicker-like gutter resizes when the line number gains another digit by
22508            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22509            let min_width_for_number_on_gutter =
22510                ch_advance * gutter_settings.min_line_number_digits as f32;
22511            max_line_number_width.max(min_width_for_number_on_gutter)
22512        } else {
22513            0.0.into()
22514        };
22515
22516        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22517        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22518
22519        let git_blame_entries_width =
22520            self.git_blame_gutter_max_author_length
22521                .map(|max_author_length| {
22522                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22523                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22524
22525                    /// The number of characters to dedicate to gaps and margins.
22526                    const SPACING_WIDTH: usize = 4;
22527
22528                    let max_char_count = max_author_length.min(renderer.max_author_length())
22529                        + ::git::SHORT_SHA_LENGTH
22530                        + MAX_RELATIVE_TIMESTAMP.len()
22531                        + SPACING_WIDTH;
22532
22533                    ch_advance * max_char_count
22534                });
22535
22536        let is_singleton = self.buffer_snapshot.is_singleton();
22537
22538        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22539        left_padding += if !is_singleton {
22540            ch_width * 4.0
22541        } else if show_runnables || show_breakpoints {
22542            ch_width * 3.0
22543        } else if show_git_gutter && show_line_numbers {
22544            ch_width * 2.0
22545        } else if show_git_gutter || show_line_numbers {
22546            ch_width
22547        } else {
22548            px(0.)
22549        };
22550
22551        let shows_folds = is_singleton && gutter_settings.folds;
22552
22553        let right_padding = if shows_folds && show_line_numbers {
22554            ch_width * 4.0
22555        } else if shows_folds || (!is_singleton && show_line_numbers) {
22556            ch_width * 3.0
22557        } else if show_line_numbers {
22558            ch_width
22559        } else {
22560            px(0.)
22561        };
22562
22563        Some(GutterDimensions {
22564            left_padding,
22565            right_padding,
22566            width: line_gutter_width + left_padding + right_padding,
22567            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22568            git_blame_entries_width,
22569        })
22570    }
22571
22572    pub fn render_crease_toggle(
22573        &self,
22574        buffer_row: MultiBufferRow,
22575        row_contains_cursor: bool,
22576        editor: Entity<Editor>,
22577        window: &mut Window,
22578        cx: &mut App,
22579    ) -> Option<AnyElement> {
22580        let folded = self.is_line_folded(buffer_row);
22581        let mut is_foldable = false;
22582
22583        if let Some(crease) = self
22584            .crease_snapshot
22585            .query_row(buffer_row, &self.buffer_snapshot)
22586        {
22587            is_foldable = true;
22588            match crease {
22589                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22590                    if let Some(render_toggle) = render_toggle {
22591                        let toggle_callback =
22592                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22593                                if folded {
22594                                    editor.update(cx, |editor, cx| {
22595                                        editor.fold_at(buffer_row, window, cx)
22596                                    });
22597                                } else {
22598                                    editor.update(cx, |editor, cx| {
22599                                        editor.unfold_at(buffer_row, window, cx)
22600                                    });
22601                                }
22602                            });
22603                        return Some((render_toggle)(
22604                            buffer_row,
22605                            folded,
22606                            toggle_callback,
22607                            window,
22608                            cx,
22609                        ));
22610                    }
22611                }
22612            }
22613        }
22614
22615        is_foldable |= self.starts_indent(buffer_row);
22616
22617        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22618            Some(
22619                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22620                    .toggle_state(folded)
22621                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22622                        if folded {
22623                            this.unfold_at(buffer_row, window, cx);
22624                        } else {
22625                            this.fold_at(buffer_row, window, cx);
22626                        }
22627                    }))
22628                    .into_any_element(),
22629            )
22630        } else {
22631            None
22632        }
22633    }
22634
22635    pub fn render_crease_trailer(
22636        &self,
22637        buffer_row: MultiBufferRow,
22638        window: &mut Window,
22639        cx: &mut App,
22640    ) -> Option<AnyElement> {
22641        let folded = self.is_line_folded(buffer_row);
22642        if let Crease::Inline { render_trailer, .. } = self
22643            .crease_snapshot
22644            .query_row(buffer_row, &self.buffer_snapshot)?
22645        {
22646            let render_trailer = render_trailer.as_ref()?;
22647            Some(render_trailer(buffer_row, folded, window, cx))
22648        } else {
22649            None
22650        }
22651    }
22652}
22653
22654impl Deref for EditorSnapshot {
22655    type Target = DisplaySnapshot;
22656
22657    fn deref(&self) -> &Self::Target {
22658        &self.display_snapshot
22659    }
22660}
22661
22662#[derive(Clone, Debug, PartialEq, Eq)]
22663pub enum EditorEvent {
22664    InputIgnored {
22665        text: Arc<str>,
22666    },
22667    InputHandled {
22668        utf16_range_to_replace: Option<Range<isize>>,
22669        text: Arc<str>,
22670    },
22671    ExcerptsAdded {
22672        buffer: Entity<Buffer>,
22673        predecessor: ExcerptId,
22674        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22675    },
22676    ExcerptsRemoved {
22677        ids: Vec<ExcerptId>,
22678        removed_buffer_ids: Vec<BufferId>,
22679    },
22680    BufferFoldToggled {
22681        ids: Vec<ExcerptId>,
22682        folded: bool,
22683    },
22684    ExcerptsEdited {
22685        ids: Vec<ExcerptId>,
22686    },
22687    ExcerptsExpanded {
22688        ids: Vec<ExcerptId>,
22689    },
22690    BufferEdited,
22691    Edited {
22692        transaction_id: clock::Lamport,
22693    },
22694    Reparsed(BufferId),
22695    Focused,
22696    FocusedIn,
22697    Blurred,
22698    DirtyChanged,
22699    Saved,
22700    TitleChanged,
22701    DiffBaseChanged,
22702    SelectionsChanged {
22703        local: bool,
22704    },
22705    ScrollPositionChanged {
22706        local: bool,
22707        autoscroll: bool,
22708    },
22709    Closed,
22710    TransactionUndone {
22711        transaction_id: clock::Lamport,
22712    },
22713    TransactionBegun {
22714        transaction_id: clock::Lamport,
22715    },
22716    Reloaded,
22717    CursorShapeChanged,
22718    PushedToNavHistory {
22719        anchor: Anchor,
22720        is_deactivate: bool,
22721    },
22722}
22723
22724impl EventEmitter<EditorEvent> for Editor {}
22725
22726impl Focusable for Editor {
22727    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22728        self.focus_handle.clone()
22729    }
22730}
22731
22732impl Render for Editor {
22733    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22734        let settings = ThemeSettings::get_global(cx);
22735
22736        let mut text_style = match self.mode {
22737            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22738                color: cx.theme().colors().editor_foreground,
22739                font_family: settings.ui_font.family.clone(),
22740                font_features: settings.ui_font.features.clone(),
22741                font_fallbacks: settings.ui_font.fallbacks.clone(),
22742                font_size: rems(0.875).into(),
22743                font_weight: settings.ui_font.weight,
22744                line_height: relative(settings.buffer_line_height.value()),
22745                ..Default::default()
22746            },
22747            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22748                color: cx.theme().colors().editor_foreground,
22749                font_family: settings.buffer_font.family.clone(),
22750                font_features: settings.buffer_font.features.clone(),
22751                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22752                font_size: settings.buffer_font_size(cx).into(),
22753                font_weight: settings.buffer_font.weight,
22754                line_height: relative(settings.buffer_line_height.value()),
22755                ..Default::default()
22756            },
22757        };
22758        if let Some(text_style_refinement) = &self.text_style_refinement {
22759            text_style.refine(text_style_refinement)
22760        }
22761
22762        let background = match self.mode {
22763            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22764            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22765            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22766            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22767        };
22768
22769        EditorElement::new(
22770            &cx.entity(),
22771            EditorStyle {
22772                background,
22773                border: cx.theme().colors().border,
22774                local_player: cx.theme().players().local(),
22775                text: text_style,
22776                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22777                syntax: cx.theme().syntax().clone(),
22778                status: cx.theme().status().clone(),
22779                inlay_hints_style: make_inlay_hints_style(cx),
22780                edit_prediction_styles: make_suggestion_styles(cx),
22781                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22782                show_underlines: self.diagnostics_enabled(),
22783            },
22784        )
22785    }
22786}
22787
22788impl EntityInputHandler for Editor {
22789    fn text_for_range(
22790        &mut self,
22791        range_utf16: Range<usize>,
22792        adjusted_range: &mut Option<Range<usize>>,
22793        _: &mut Window,
22794        cx: &mut Context<Self>,
22795    ) -> Option<String> {
22796        let snapshot = self.buffer.read(cx).read(cx);
22797        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22798        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22799        if (start.0..end.0) != range_utf16 {
22800            adjusted_range.replace(start.0..end.0);
22801        }
22802        Some(snapshot.text_for_range(start..end).collect())
22803    }
22804
22805    fn selected_text_range(
22806        &mut self,
22807        ignore_disabled_input: bool,
22808        _: &mut Window,
22809        cx: &mut Context<Self>,
22810    ) -> Option<UTF16Selection> {
22811        // Prevent the IME menu from appearing when holding down an alphabetic key
22812        // while input is disabled.
22813        if !ignore_disabled_input && !self.input_enabled {
22814            return None;
22815        }
22816
22817        let selection = self.selections.newest::<OffsetUtf16>(cx);
22818        let range = selection.range();
22819
22820        Some(UTF16Selection {
22821            range: range.start.0..range.end.0,
22822            reversed: selection.reversed,
22823        })
22824    }
22825
22826    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22827        let snapshot = self.buffer.read(cx).read(cx);
22828        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22829        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22830    }
22831
22832    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22833        self.clear_highlights::<InputComposition>(cx);
22834        self.ime_transaction.take();
22835    }
22836
22837    fn replace_text_in_range(
22838        &mut self,
22839        range_utf16: Option<Range<usize>>,
22840        text: &str,
22841        window: &mut Window,
22842        cx: &mut Context<Self>,
22843    ) {
22844        if !self.input_enabled {
22845            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22846            return;
22847        }
22848
22849        self.transact(window, cx, |this, window, cx| {
22850            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22851                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22852                Some(this.selection_replacement_ranges(range_utf16, cx))
22853            } else {
22854                this.marked_text_ranges(cx)
22855            };
22856
22857            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22858                let newest_selection_id = this.selections.newest_anchor().id;
22859                this.selections
22860                    .all::<OffsetUtf16>(cx)
22861                    .iter()
22862                    .zip(ranges_to_replace.iter())
22863                    .find_map(|(selection, range)| {
22864                        if selection.id == newest_selection_id {
22865                            Some(
22866                                (range.start.0 as isize - selection.head().0 as isize)
22867                                    ..(range.end.0 as isize - selection.head().0 as isize),
22868                            )
22869                        } else {
22870                            None
22871                        }
22872                    })
22873            });
22874
22875            cx.emit(EditorEvent::InputHandled {
22876                utf16_range_to_replace: range_to_replace,
22877                text: text.into(),
22878            });
22879
22880            if let Some(new_selected_ranges) = new_selected_ranges {
22881                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22882                    selections.select_ranges(new_selected_ranges)
22883                });
22884                this.backspace(&Default::default(), window, cx);
22885            }
22886
22887            this.handle_input(text, window, cx);
22888        });
22889
22890        if let Some(transaction) = self.ime_transaction {
22891            self.buffer.update(cx, |buffer, cx| {
22892                buffer.group_until_transaction(transaction, cx);
22893            });
22894        }
22895
22896        self.unmark_text(window, cx);
22897    }
22898
22899    fn replace_and_mark_text_in_range(
22900        &mut self,
22901        range_utf16: Option<Range<usize>>,
22902        text: &str,
22903        new_selected_range_utf16: Option<Range<usize>>,
22904        window: &mut Window,
22905        cx: &mut Context<Self>,
22906    ) {
22907        if !self.input_enabled {
22908            return;
22909        }
22910
22911        let transaction = self.transact(window, cx, |this, window, cx| {
22912            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22913                let snapshot = this.buffer.read(cx).read(cx);
22914                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22915                    for marked_range in &mut marked_ranges {
22916                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22917                        marked_range.start.0 += relative_range_utf16.start;
22918                        marked_range.start =
22919                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22920                        marked_range.end =
22921                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22922                    }
22923                }
22924                Some(marked_ranges)
22925            } else if let Some(range_utf16) = range_utf16 {
22926                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22927                Some(this.selection_replacement_ranges(range_utf16, cx))
22928            } else {
22929                None
22930            };
22931
22932            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22933                let newest_selection_id = this.selections.newest_anchor().id;
22934                this.selections
22935                    .all::<OffsetUtf16>(cx)
22936                    .iter()
22937                    .zip(ranges_to_replace.iter())
22938                    .find_map(|(selection, range)| {
22939                        if selection.id == newest_selection_id {
22940                            Some(
22941                                (range.start.0 as isize - selection.head().0 as isize)
22942                                    ..(range.end.0 as isize - selection.head().0 as isize),
22943                            )
22944                        } else {
22945                            None
22946                        }
22947                    })
22948            });
22949
22950            cx.emit(EditorEvent::InputHandled {
22951                utf16_range_to_replace: range_to_replace,
22952                text: text.into(),
22953            });
22954
22955            if let Some(ranges) = ranges_to_replace {
22956                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22957                    s.select_ranges(ranges)
22958                });
22959            }
22960
22961            let marked_ranges = {
22962                let snapshot = this.buffer.read(cx).read(cx);
22963                this.selections
22964                    .disjoint_anchors()
22965                    .iter()
22966                    .map(|selection| {
22967                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22968                    })
22969                    .collect::<Vec<_>>()
22970            };
22971
22972            if text.is_empty() {
22973                this.unmark_text(window, cx);
22974            } else {
22975                this.highlight_text::<InputComposition>(
22976                    marked_ranges.clone(),
22977                    HighlightStyle {
22978                        underline: Some(UnderlineStyle {
22979                            thickness: px(1.),
22980                            color: None,
22981                            wavy: false,
22982                        }),
22983                        ..Default::default()
22984                    },
22985                    cx,
22986                );
22987            }
22988
22989            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22990            let use_autoclose = this.use_autoclose;
22991            let use_auto_surround = this.use_auto_surround;
22992            this.set_use_autoclose(false);
22993            this.set_use_auto_surround(false);
22994            this.handle_input(text, window, cx);
22995            this.set_use_autoclose(use_autoclose);
22996            this.set_use_auto_surround(use_auto_surround);
22997
22998            if let Some(new_selected_range) = new_selected_range_utf16 {
22999                let snapshot = this.buffer.read(cx).read(cx);
23000                let new_selected_ranges = marked_ranges
23001                    .into_iter()
23002                    .map(|marked_range| {
23003                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23004                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23005                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23006                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23007                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23008                    })
23009                    .collect::<Vec<_>>();
23010
23011                drop(snapshot);
23012                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23013                    selections.select_ranges(new_selected_ranges)
23014                });
23015            }
23016        });
23017
23018        self.ime_transaction = self.ime_transaction.or(transaction);
23019        if let Some(transaction) = self.ime_transaction {
23020            self.buffer.update(cx, |buffer, cx| {
23021                buffer.group_until_transaction(transaction, cx);
23022            });
23023        }
23024
23025        if self.text_highlights::<InputComposition>(cx).is_none() {
23026            self.ime_transaction.take();
23027        }
23028    }
23029
23030    fn bounds_for_range(
23031        &mut self,
23032        range_utf16: Range<usize>,
23033        element_bounds: gpui::Bounds<Pixels>,
23034        window: &mut Window,
23035        cx: &mut Context<Self>,
23036    ) -> Option<gpui::Bounds<Pixels>> {
23037        let text_layout_details = self.text_layout_details(window);
23038        let CharacterDimensions {
23039            em_width,
23040            em_advance,
23041            line_height,
23042        } = self.character_dimensions(window);
23043
23044        let snapshot = self.snapshot(window, cx);
23045        let scroll_position = snapshot.scroll_position();
23046        let scroll_left = scroll_position.x * em_advance;
23047
23048        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23049        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23050            + self.gutter_dimensions.full_width();
23051        let y = line_height * (start.row().as_f32() - scroll_position.y);
23052
23053        Some(Bounds {
23054            origin: element_bounds.origin + point(x, y),
23055            size: size(em_width, line_height),
23056        })
23057    }
23058
23059    fn character_index_for_point(
23060        &mut self,
23061        point: gpui::Point<Pixels>,
23062        _window: &mut Window,
23063        _cx: &mut Context<Self>,
23064    ) -> Option<usize> {
23065        let position_map = self.last_position_map.as_ref()?;
23066        if !position_map.text_hitbox.contains(&point) {
23067            return None;
23068        }
23069        let display_point = position_map.point_for_position(point).previous_valid;
23070        let anchor = position_map
23071            .snapshot
23072            .display_point_to_anchor(display_point, Bias::Left);
23073        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23074        Some(utf16_offset.0)
23075    }
23076}
23077
23078trait SelectionExt {
23079    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23080    fn spanned_rows(
23081        &self,
23082        include_end_if_at_line_start: bool,
23083        map: &DisplaySnapshot,
23084    ) -> Range<MultiBufferRow>;
23085}
23086
23087impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23088    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23089        let start = self
23090            .start
23091            .to_point(&map.buffer_snapshot)
23092            .to_display_point(map);
23093        let end = self
23094            .end
23095            .to_point(&map.buffer_snapshot)
23096            .to_display_point(map);
23097        if self.reversed {
23098            end..start
23099        } else {
23100            start..end
23101        }
23102    }
23103
23104    fn spanned_rows(
23105        &self,
23106        include_end_if_at_line_start: bool,
23107        map: &DisplaySnapshot,
23108    ) -> Range<MultiBufferRow> {
23109        let start = self.start.to_point(&map.buffer_snapshot);
23110        let mut end = self.end.to_point(&map.buffer_snapshot);
23111        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23112            end.row -= 1;
23113        }
23114
23115        let buffer_start = map.prev_line_boundary(start).0;
23116        let buffer_end = map.next_line_boundary(end).0;
23117        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23118    }
23119}
23120
23121impl<T: InvalidationRegion> InvalidationStack<T> {
23122    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23123    where
23124        S: Clone + ToOffset,
23125    {
23126        while let Some(region) = self.last() {
23127            let all_selections_inside_invalidation_ranges =
23128                if selections.len() == region.ranges().len() {
23129                    selections
23130                        .iter()
23131                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23132                        .all(|(selection, invalidation_range)| {
23133                            let head = selection.head().to_offset(buffer);
23134                            invalidation_range.start <= head && invalidation_range.end >= head
23135                        })
23136                } else {
23137                    false
23138                };
23139
23140            if all_selections_inside_invalidation_ranges {
23141                break;
23142            } else {
23143                self.pop();
23144            }
23145        }
23146    }
23147}
23148
23149impl<T> Default for InvalidationStack<T> {
23150    fn default() -> Self {
23151        Self(Default::default())
23152    }
23153}
23154
23155impl<T> Deref for InvalidationStack<T> {
23156    type Target = Vec<T>;
23157
23158    fn deref(&self) -> &Self::Target {
23159        &self.0
23160    }
23161}
23162
23163impl<T> DerefMut for InvalidationStack<T> {
23164    fn deref_mut(&mut self) -> &mut Self::Target {
23165        &mut self.0
23166    }
23167}
23168
23169impl InvalidationRegion for SnippetState {
23170    fn ranges(&self) -> &[Range<Anchor>] {
23171        &self.ranges[self.active_index]
23172    }
23173}
23174
23175fn edit_prediction_edit_text(
23176    current_snapshot: &BufferSnapshot,
23177    edits: &[(Range<Anchor>, String)],
23178    edit_preview: &EditPreview,
23179    include_deletions: bool,
23180    cx: &App,
23181) -> HighlightedText {
23182    let edits = edits
23183        .iter()
23184        .map(|(anchor, text)| {
23185            (
23186                anchor.start.text_anchor..anchor.end.text_anchor,
23187                text.clone(),
23188            )
23189        })
23190        .collect::<Vec<_>>();
23191
23192    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23193}
23194
23195pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23196    match severity {
23197        lsp::DiagnosticSeverity::ERROR => colors.error,
23198        lsp::DiagnosticSeverity::WARNING => colors.warning,
23199        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23200        lsp::DiagnosticSeverity::HINT => colors.info,
23201        _ => colors.ignored,
23202    }
23203}
23204
23205pub fn styled_runs_for_code_label<'a>(
23206    label: &'a CodeLabel,
23207    syntax_theme: &'a theme::SyntaxTheme,
23208) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23209    let fade_out = HighlightStyle {
23210        fade_out: Some(0.35),
23211        ..Default::default()
23212    };
23213
23214    let mut prev_end = label.filter_range.end;
23215    label
23216        .runs
23217        .iter()
23218        .enumerate()
23219        .flat_map(move |(ix, (range, highlight_id))| {
23220            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23221                style
23222            } else {
23223                return Default::default();
23224            };
23225            let mut muted_style = style;
23226            muted_style.highlight(fade_out);
23227
23228            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23229            if range.start >= label.filter_range.end {
23230                if range.start > prev_end {
23231                    runs.push((prev_end..range.start, fade_out));
23232                }
23233                runs.push((range.clone(), muted_style));
23234            } else if range.end <= label.filter_range.end {
23235                runs.push((range.clone(), style));
23236            } else {
23237                runs.push((range.start..label.filter_range.end, style));
23238                runs.push((label.filter_range.end..range.end, muted_style));
23239            }
23240            prev_end = cmp::max(prev_end, range.end);
23241
23242            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23243                runs.push((prev_end..label.text.len(), fade_out));
23244            }
23245
23246            runs
23247        })
23248}
23249
23250pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23251    let mut prev_index = 0;
23252    let mut prev_codepoint: Option<char> = None;
23253    text.char_indices()
23254        .chain([(text.len(), '\0')])
23255        .filter_map(move |(index, codepoint)| {
23256            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23257            let is_boundary = index == text.len()
23258                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23259                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23260            if is_boundary {
23261                let chunk = &text[prev_index..index];
23262                prev_index = index;
23263                Some(chunk)
23264            } else {
23265                None
23266            }
23267        })
23268}
23269
23270pub trait RangeToAnchorExt: Sized {
23271    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23272
23273    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23274        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23275        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23276    }
23277}
23278
23279impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23280    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23281        let start_offset = self.start.to_offset(snapshot);
23282        let end_offset = self.end.to_offset(snapshot);
23283        if start_offset == end_offset {
23284            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23285        } else {
23286            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23287        }
23288    }
23289}
23290
23291pub trait RowExt {
23292    fn as_f32(&self) -> f32;
23293
23294    fn next_row(&self) -> Self;
23295
23296    fn previous_row(&self) -> Self;
23297
23298    fn minus(&self, other: Self) -> u32;
23299}
23300
23301impl RowExt for DisplayRow {
23302    fn as_f32(&self) -> f32 {
23303        self.0 as f32
23304    }
23305
23306    fn next_row(&self) -> Self {
23307        Self(self.0 + 1)
23308    }
23309
23310    fn previous_row(&self) -> Self {
23311        Self(self.0.saturating_sub(1))
23312    }
23313
23314    fn minus(&self, other: Self) -> u32 {
23315        self.0 - other.0
23316    }
23317}
23318
23319impl RowExt for MultiBufferRow {
23320    fn as_f32(&self) -> f32 {
23321        self.0 as f32
23322    }
23323
23324    fn next_row(&self) -> Self {
23325        Self(self.0 + 1)
23326    }
23327
23328    fn previous_row(&self) -> Self {
23329        Self(self.0.saturating_sub(1))
23330    }
23331
23332    fn minus(&self, other: Self) -> u32 {
23333        self.0 - other.0
23334    }
23335}
23336
23337trait RowRangeExt {
23338    type Row;
23339
23340    fn len(&self) -> usize;
23341
23342    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23343}
23344
23345impl RowRangeExt for Range<MultiBufferRow> {
23346    type Row = MultiBufferRow;
23347
23348    fn len(&self) -> usize {
23349        (self.end.0 - self.start.0) as usize
23350    }
23351
23352    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23353        (self.start.0..self.end.0).map(MultiBufferRow)
23354    }
23355}
23356
23357impl RowRangeExt for Range<DisplayRow> {
23358    type Row = DisplayRow;
23359
23360    fn len(&self) -> usize {
23361        (self.end.0 - self.start.0) as usize
23362    }
23363
23364    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23365        (self.start.0..self.end.0).map(DisplayRow)
23366    }
23367}
23368
23369/// If select range has more than one line, we
23370/// just point the cursor to range.start.
23371fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23372    if range.start.row == range.end.row {
23373        range
23374    } else {
23375        range.start..range.start
23376    }
23377}
23378pub struct KillRing(ClipboardItem);
23379impl Global for KillRing {}
23380
23381const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23382
23383enum BreakpointPromptEditAction {
23384    Log,
23385    Condition,
23386    HitCondition,
23387}
23388
23389struct BreakpointPromptEditor {
23390    pub(crate) prompt: Entity<Editor>,
23391    editor: WeakEntity<Editor>,
23392    breakpoint_anchor: Anchor,
23393    breakpoint: Breakpoint,
23394    edit_action: BreakpointPromptEditAction,
23395    block_ids: HashSet<CustomBlockId>,
23396    editor_margins: Arc<Mutex<EditorMargins>>,
23397    _subscriptions: Vec<Subscription>,
23398}
23399
23400impl BreakpointPromptEditor {
23401    const MAX_LINES: u8 = 4;
23402
23403    fn new(
23404        editor: WeakEntity<Editor>,
23405        breakpoint_anchor: Anchor,
23406        breakpoint: Breakpoint,
23407        edit_action: BreakpointPromptEditAction,
23408        window: &mut Window,
23409        cx: &mut Context<Self>,
23410    ) -> Self {
23411        let base_text = match edit_action {
23412            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23413            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23414            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23415        }
23416        .map(|msg| msg.to_string())
23417        .unwrap_or_default();
23418
23419        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23420        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23421
23422        let prompt = cx.new(|cx| {
23423            let mut prompt = Editor::new(
23424                EditorMode::AutoHeight {
23425                    min_lines: 1,
23426                    max_lines: Some(Self::MAX_LINES as usize),
23427                },
23428                buffer,
23429                None,
23430                window,
23431                cx,
23432            );
23433            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23434            prompt.set_show_cursor_when_unfocused(false, cx);
23435            prompt.set_placeholder_text(
23436                match edit_action {
23437                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23438                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23439                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23440                },
23441                cx,
23442            );
23443
23444            prompt
23445        });
23446
23447        Self {
23448            prompt,
23449            editor,
23450            breakpoint_anchor,
23451            breakpoint,
23452            edit_action,
23453            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23454            block_ids: Default::default(),
23455            _subscriptions: vec![],
23456        }
23457    }
23458
23459    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23460        self.block_ids.extend(block_ids)
23461    }
23462
23463    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23464        if let Some(editor) = self.editor.upgrade() {
23465            let message = self
23466                .prompt
23467                .read(cx)
23468                .buffer
23469                .read(cx)
23470                .as_singleton()
23471                .expect("A multi buffer in breakpoint prompt isn't possible")
23472                .read(cx)
23473                .as_rope()
23474                .to_string();
23475
23476            editor.update(cx, |editor, cx| {
23477                editor.edit_breakpoint_at_anchor(
23478                    self.breakpoint_anchor,
23479                    self.breakpoint.clone(),
23480                    match self.edit_action {
23481                        BreakpointPromptEditAction::Log => {
23482                            BreakpointEditAction::EditLogMessage(message.into())
23483                        }
23484                        BreakpointPromptEditAction::Condition => {
23485                            BreakpointEditAction::EditCondition(message.into())
23486                        }
23487                        BreakpointPromptEditAction::HitCondition => {
23488                            BreakpointEditAction::EditHitCondition(message.into())
23489                        }
23490                    },
23491                    cx,
23492                );
23493
23494                editor.remove_blocks(self.block_ids.clone(), None, cx);
23495                cx.focus_self(window);
23496            });
23497        }
23498    }
23499
23500    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23501        self.editor
23502            .update(cx, |editor, cx| {
23503                editor.remove_blocks(self.block_ids.clone(), None, cx);
23504                window.focus(&editor.focus_handle);
23505            })
23506            .log_err();
23507    }
23508
23509    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23510        let settings = ThemeSettings::get_global(cx);
23511        let text_style = TextStyle {
23512            color: if self.prompt.read(cx).read_only(cx) {
23513                cx.theme().colors().text_disabled
23514            } else {
23515                cx.theme().colors().text
23516            },
23517            font_family: settings.buffer_font.family.clone(),
23518            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23519            font_size: settings.buffer_font_size(cx).into(),
23520            font_weight: settings.buffer_font.weight,
23521            line_height: relative(settings.buffer_line_height.value()),
23522            ..Default::default()
23523        };
23524        EditorElement::new(
23525            &self.prompt,
23526            EditorStyle {
23527                background: cx.theme().colors().editor_background,
23528                local_player: cx.theme().players().local(),
23529                text: text_style,
23530                ..Default::default()
23531            },
23532        )
23533    }
23534}
23535
23536impl Render for BreakpointPromptEditor {
23537    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23538        let editor_margins = *self.editor_margins.lock();
23539        let gutter_dimensions = editor_margins.gutter;
23540        h_flex()
23541            .key_context("Editor")
23542            .bg(cx.theme().colors().editor_background)
23543            .border_y_1()
23544            .border_color(cx.theme().status().info_border)
23545            .size_full()
23546            .py(window.line_height() / 2.5)
23547            .on_action(cx.listener(Self::confirm))
23548            .on_action(cx.listener(Self::cancel))
23549            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23550            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23551    }
23552}
23553
23554impl Focusable for BreakpointPromptEditor {
23555    fn focus_handle(&self, cx: &App) -> FocusHandle {
23556        self.prompt.focus_handle(cx)
23557    }
23558}
23559
23560fn all_edits_insertions_or_deletions(
23561    edits: &Vec<(Range<Anchor>, String)>,
23562    snapshot: &MultiBufferSnapshot,
23563) -> bool {
23564    let mut all_insertions = true;
23565    let mut all_deletions = true;
23566
23567    for (range, new_text) in edits.iter() {
23568        let range_is_empty = range.to_offset(&snapshot).is_empty();
23569        let text_is_empty = new_text.is_empty();
23570
23571        if range_is_empty != text_is_empty {
23572            if range_is_empty {
23573                all_deletions = false;
23574            } else {
23575                all_insertions = false;
23576            }
23577        } else {
23578            return false;
23579        }
23580
23581        if !all_insertions && !all_deletions {
23582            return false;
23583        }
23584    }
23585    all_insertions || all_deletions
23586}
23587
23588struct MissingEditPredictionKeybindingTooltip;
23589
23590impl Render for MissingEditPredictionKeybindingTooltip {
23591    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23592        ui::tooltip_container(window, cx, |container, _, cx| {
23593            container
23594                .flex_shrink_0()
23595                .max_w_80()
23596                .min_h(rems_from_px(124.))
23597                .justify_between()
23598                .child(
23599                    v_flex()
23600                        .flex_1()
23601                        .text_ui_sm(cx)
23602                        .child(Label::new("Conflict with Accept Keybinding"))
23603                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23604                )
23605                .child(
23606                    h_flex()
23607                        .pb_1()
23608                        .gap_1()
23609                        .items_end()
23610                        .w_full()
23611                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23612                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23613                        }))
23614                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23615                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23616                        })),
23617                )
23618        })
23619    }
23620}
23621
23622#[derive(Debug, Clone, Copy, PartialEq)]
23623pub struct LineHighlight {
23624    pub background: Background,
23625    pub border: Option<gpui::Hsla>,
23626    pub include_gutter: bool,
23627    pub type_id: Option<TypeId>,
23628}
23629
23630struct LineManipulationResult {
23631    pub new_text: String,
23632    pub line_count_before: usize,
23633    pub line_count_after: usize,
23634}
23635
23636fn render_diff_hunk_controls(
23637    row: u32,
23638    status: &DiffHunkStatus,
23639    hunk_range: Range<Anchor>,
23640    is_created_file: bool,
23641    line_height: Pixels,
23642    editor: &Entity<Editor>,
23643    _window: &mut Window,
23644    cx: &mut App,
23645) -> AnyElement {
23646    h_flex()
23647        .h(line_height)
23648        .mr_1()
23649        .gap_1()
23650        .px_0p5()
23651        .pb_1()
23652        .border_x_1()
23653        .border_b_1()
23654        .border_color(cx.theme().colors().border_variant)
23655        .rounded_b_lg()
23656        .bg(cx.theme().colors().editor_background)
23657        .gap_1()
23658        .block_mouse_except_scroll()
23659        .shadow_md()
23660        .child(if status.has_secondary_hunk() {
23661            Button::new(("stage", row as u64), "Stage")
23662                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23663                .tooltip({
23664                    let focus_handle = editor.focus_handle(cx);
23665                    move |window, cx| {
23666                        Tooltip::for_action_in(
23667                            "Stage Hunk",
23668                            &::git::ToggleStaged,
23669                            &focus_handle,
23670                            window,
23671                            cx,
23672                        )
23673                    }
23674                })
23675                .on_click({
23676                    let editor = editor.clone();
23677                    move |_event, _window, cx| {
23678                        editor.update(cx, |editor, cx| {
23679                            editor.stage_or_unstage_diff_hunks(
23680                                true,
23681                                vec![hunk_range.start..hunk_range.start],
23682                                cx,
23683                            );
23684                        });
23685                    }
23686                })
23687        } else {
23688            Button::new(("unstage", row as u64), "Unstage")
23689                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23690                .tooltip({
23691                    let focus_handle = editor.focus_handle(cx);
23692                    move |window, cx| {
23693                        Tooltip::for_action_in(
23694                            "Unstage Hunk",
23695                            &::git::ToggleStaged,
23696                            &focus_handle,
23697                            window,
23698                            cx,
23699                        )
23700                    }
23701                })
23702                .on_click({
23703                    let editor = editor.clone();
23704                    move |_event, _window, cx| {
23705                        editor.update(cx, |editor, cx| {
23706                            editor.stage_or_unstage_diff_hunks(
23707                                false,
23708                                vec![hunk_range.start..hunk_range.start],
23709                                cx,
23710                            );
23711                        });
23712                    }
23713                })
23714        })
23715        .child(
23716            Button::new(("restore", row as u64), "Restore")
23717                .tooltip({
23718                    let focus_handle = editor.focus_handle(cx);
23719                    move |window, cx| {
23720                        Tooltip::for_action_in(
23721                            "Restore Hunk",
23722                            &::git::Restore,
23723                            &focus_handle,
23724                            window,
23725                            cx,
23726                        )
23727                    }
23728                })
23729                .on_click({
23730                    let editor = editor.clone();
23731                    move |_event, window, cx| {
23732                        editor.update(cx, |editor, cx| {
23733                            let snapshot = editor.snapshot(window, cx);
23734                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23735                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23736                        });
23737                    }
23738                })
23739                .disabled(is_created_file),
23740        )
23741        .when(
23742            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23743            |el| {
23744                el.child(
23745                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23746                        .shape(IconButtonShape::Square)
23747                        .icon_size(IconSize::Small)
23748                        // .disabled(!has_multiple_hunks)
23749                        .tooltip({
23750                            let focus_handle = editor.focus_handle(cx);
23751                            move |window, cx| {
23752                                Tooltip::for_action_in(
23753                                    "Next Hunk",
23754                                    &GoToHunk,
23755                                    &focus_handle,
23756                                    window,
23757                                    cx,
23758                                )
23759                            }
23760                        })
23761                        .on_click({
23762                            let editor = editor.clone();
23763                            move |_event, window, cx| {
23764                                editor.update(cx, |editor, cx| {
23765                                    let snapshot = editor.snapshot(window, cx);
23766                                    let position =
23767                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23768                                    editor.go_to_hunk_before_or_after_position(
23769                                        &snapshot,
23770                                        position,
23771                                        Direction::Next,
23772                                        window,
23773                                        cx,
23774                                    );
23775                                    editor.expand_selected_diff_hunks(cx);
23776                                });
23777                            }
23778                        }),
23779                )
23780                .child(
23781                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23782                        .shape(IconButtonShape::Square)
23783                        .icon_size(IconSize::Small)
23784                        // .disabled(!has_multiple_hunks)
23785                        .tooltip({
23786                            let focus_handle = editor.focus_handle(cx);
23787                            move |window, cx| {
23788                                Tooltip::for_action_in(
23789                                    "Previous Hunk",
23790                                    &GoToPreviousHunk,
23791                                    &focus_handle,
23792                                    window,
23793                                    cx,
23794                                )
23795                            }
23796                        })
23797                        .on_click({
23798                            let editor = editor.clone();
23799                            move |_event, window, cx| {
23800                                editor.update(cx, |editor, cx| {
23801                                    let snapshot = editor.snapshot(window, cx);
23802                                    let point =
23803                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23804                                    editor.go_to_hunk_before_or_after_position(
23805                                        &snapshot,
23806                                        point,
23807                                        Direction::Prev,
23808                                        window,
23809                                        cx,
23810                                    );
23811                                    editor.expand_selected_diff_hunks(cx);
23812                                });
23813                            }
23814                        }),
23815                )
23816            },
23817        )
23818        .into_any_element()
23819}