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 editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, Capability, CharKind,
  113    CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview,
  114    HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection,
  115    SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216use zed_actions;
  217
  218use crate::{
  219    code_context_menus::CompletionsMenuSource,
  220    hover_links::{find_url, find_url_from_range},
  221};
  222use crate::{
  223    editor_settings::MultiCursorModifier,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    DebuggerValue(usize),
  280    // LSP
  281    Hint(usize),
  282    Color(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::DebuggerValue(id) => *id,
  290            Self::Hint(id) => *id,
  291            Self::Color(id) => *id,
  292        }
  293    }
  294}
  295
  296pub enum ActiveDebugLine {}
  297pub enum DebugStackFrameLine {}
  298enum DocumentHighlightRead {}
  299enum DocumentHighlightWrite {}
  300enum InputComposition {}
  301pub enum PendingInput {}
  302enum SelectedTextHighlight {}
  303
  304pub enum ConflictsOuter {}
  305pub enum ConflictsOurs {}
  306pub enum ConflictsTheirs {}
  307pub enum ConflictsOursMarker {}
  308pub enum ConflictsTheirsMarker {}
  309
  310#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  311pub enum Navigated {
  312    Yes,
  313    No,
  314}
  315
  316impl Navigated {
  317    pub fn from_bool(yes: bool) -> Navigated {
  318        if yes { Navigated::Yes } else { Navigated::No }
  319    }
  320}
  321
  322#[derive(Debug, Clone, PartialEq, Eq)]
  323enum DisplayDiffHunk {
  324    Folded {
  325        display_row: DisplayRow,
  326    },
  327    Unfolded {
  328        is_created_file: bool,
  329        diff_base_byte_range: Range<usize>,
  330        display_row_range: Range<DisplayRow>,
  331        multi_buffer_range: Range<Anchor>,
  332        status: DiffHunkStatus,
  333    },
  334}
  335
  336pub enum HideMouseCursorOrigin {
  337    TypingAction,
  338    MovementAction,
  339}
  340
  341pub fn init_settings(cx: &mut App) {
  342    EditorSettings::register(cx);
  343}
  344
  345pub fn init(cx: &mut App) {
  346    init_settings(cx);
  347
  348    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  349
  350    workspace::register_project_item::<Editor>(cx);
  351    workspace::FollowableViewRegistry::register::<Editor>(cx);
  352    workspace::register_serializable_item::<Editor>(cx);
  353
  354    cx.observe_new(
  355        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  356            workspace.register_action(Editor::new_file);
  357            workspace.register_action(Editor::new_file_vertical);
  358            workspace.register_action(Editor::new_file_horizontal);
  359            workspace.register_action(Editor::cancel_language_server_work);
  360            workspace.register_action(Editor::toggle_focus);
  361        },
  362    )
  363    .detach();
  364
  365    cx.on_action(move |_: &workspace::NewFile, cx| {
  366        let app_state = workspace::AppState::global(cx);
  367        if let Some(app_state) = app_state.upgrade() {
  368            workspace::open_new(
  369                Default::default(),
  370                app_state,
  371                cx,
  372                |workspace, window, cx| {
  373                    Editor::new_file(workspace, &Default::default(), window, cx)
  374                },
  375            )
  376            .detach();
  377        }
  378    });
  379    cx.on_action(move |_: &workspace::NewWindow, cx| {
  380        let app_state = workspace::AppState::global(cx);
  381        if let Some(app_state) = app_state.upgrade() {
  382            workspace::open_new(
  383                Default::default(),
  384                app_state,
  385                cx,
  386                |workspace, window, cx| {
  387                    cx.activate(true);
  388                    Editor::new_file(workspace, &Default::default(), window, cx)
  389                },
  390            )
  391            .detach();
  392        }
  393    });
  394}
  395
  396pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  397    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  398}
  399
  400pub trait DiagnosticRenderer {
  401    fn render_group(
  402        &self,
  403        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  404        buffer_id: BufferId,
  405        snapshot: EditorSnapshot,
  406        editor: WeakEntity<Editor>,
  407        cx: &mut App,
  408    ) -> Vec<BlockProperties<Anchor>>;
  409
  410    fn render_hover(
  411        &self,
  412        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  413        range: Range<Point>,
  414        buffer_id: BufferId,
  415        cx: &mut App,
  416    ) -> Option<Entity<markdown::Markdown>>;
  417
  418    fn open_link(
  419        &self,
  420        editor: &mut Editor,
  421        link: SharedString,
  422        window: &mut Window,
  423        cx: &mut Context<Editor>,
  424    );
  425}
  426
  427pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  428
  429impl GlobalDiagnosticRenderer {
  430    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  431        cx.try_global::<Self>().map(|g| g.0.clone())
  432    }
  433}
  434
  435impl gpui::Global for GlobalDiagnosticRenderer {}
  436pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  437    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  438}
  439
  440pub struct SearchWithinRange;
  441
  442trait InvalidationRegion {
  443    fn ranges(&self) -> &[Range<Anchor>];
  444}
  445
  446#[derive(Clone, Debug, PartialEq)]
  447pub enum SelectPhase {
  448    Begin {
  449        position: DisplayPoint,
  450        add: bool,
  451        click_count: usize,
  452    },
  453    BeginColumnar {
  454        position: DisplayPoint,
  455        reset: bool,
  456        mode: ColumnarMode,
  457        goal_column: u32,
  458    },
  459    Extend {
  460        position: DisplayPoint,
  461        click_count: usize,
  462    },
  463    Update {
  464        position: DisplayPoint,
  465        goal_column: u32,
  466        scroll_delta: gpui::Point<f32>,
  467    },
  468    End,
  469}
  470
  471#[derive(Clone, Debug, PartialEq)]
  472pub enum ColumnarMode {
  473    FromMouse,
  474    FromSelection,
  475}
  476
  477#[derive(Clone, Debug)]
  478pub enum SelectMode {
  479    Character,
  480    Word(Range<Anchor>),
  481    Line(Range<Anchor>),
  482    All,
  483}
  484
  485#[derive(Clone, PartialEq, Eq, Debug)]
  486pub enum EditorMode {
  487    SingleLine,
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954    keyboard_grace: bool,
  955}
  956
  957enum SelectionDragState {
  958    /// State when no drag related activity is detected.
  959    None,
  960    /// State when the mouse is down on a selection that is about to be dragged.
  961    ReadyToDrag {
  962        selection: Selection<Anchor>,
  963        click_position: gpui::Point<Pixels>,
  964        mouse_down_time: Instant,
  965    },
  966    /// State when the mouse is dragging the selection in the editor.
  967    Dragging {
  968        selection: Selection<Anchor>,
  969        drop_cursor: Selection<Anchor>,
  970        hide_drop_cursor: bool,
  971    },
  972}
  973
  974enum ColumnarSelectionState {
  975    FromMouse {
  976        selection_tail: Anchor,
  977        display_point: Option<DisplayPoint>,
  978    },
  979    FromSelection {
  980        selection_tail: Anchor,
  981    },
  982}
  983
  984/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  985/// a breakpoint on them.
  986#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  987struct PhantomBreakpointIndicator {
  988    display_row: DisplayRow,
  989    /// There's a small debounce between hovering over the line and showing the indicator.
  990    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  991    is_active: bool,
  992    collides_with_existing_breakpoint: bool,
  993}
  994
  995/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  996///
  997/// See the [module level documentation](self) for more information.
  998pub struct Editor {
  999    focus_handle: FocusHandle,
 1000    last_focused_descendant: Option<WeakFocusHandle>,
 1001    /// The text buffer being edited
 1002    buffer: Entity<MultiBuffer>,
 1003    /// Map of how text in the buffer should be displayed.
 1004    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1005    pub display_map: Entity<DisplayMap>,
 1006    pub selections: SelectionsCollection,
 1007    pub scroll_manager: ScrollManager,
 1008    /// When inline assist editors are linked, they all render cursors because
 1009    /// typing enters text into each of them, even the ones that aren't focused.
 1010    pub(crate) show_cursor_when_unfocused: bool,
 1011    columnar_selection_state: Option<ColumnarSelectionState>,
 1012    add_selections_state: Option<AddSelectionsState>,
 1013    select_next_state: Option<SelectNextState>,
 1014    select_prev_state: Option<SelectNextState>,
 1015    selection_history: SelectionHistory,
 1016    defer_selection_effects: bool,
 1017    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1018    autoclose_regions: Vec<AutocloseRegion>,
 1019    snippet_stack: InvalidationStack<SnippetState>,
 1020    select_syntax_node_history: SelectSyntaxNodeHistory,
 1021    ime_transaction: Option<TransactionId>,
 1022    pub diagnostics_max_severity: DiagnosticSeverity,
 1023    active_diagnostics: ActiveDiagnostic,
 1024    show_inline_diagnostics: bool,
 1025    inline_diagnostics_update: Task<()>,
 1026    inline_diagnostics_enabled: bool,
 1027    diagnostics_enabled: bool,
 1028    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1029    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1030    hard_wrap: Option<usize>,
 1031
 1032    // TODO: make this a access method
 1033    pub project: Option<Entity<Project>>,
 1034    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1035    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1036    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1037    blink_manager: Entity<BlinkManager>,
 1038    show_cursor_names: bool,
 1039    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1040    pub show_local_selections: bool,
 1041    mode: EditorMode,
 1042    show_breadcrumbs: bool,
 1043    show_gutter: bool,
 1044    show_scrollbars: ScrollbarAxes,
 1045    minimap_visibility: MinimapVisibility,
 1046    offset_content: bool,
 1047    disable_expand_excerpt_buttons: bool,
 1048    show_line_numbers: Option<bool>,
 1049    use_relative_line_numbers: Option<bool>,
 1050    show_git_diff_gutter: Option<bool>,
 1051    show_code_actions: Option<bool>,
 1052    show_runnables: Option<bool>,
 1053    show_breakpoints: Option<bool>,
 1054    show_wrap_guides: Option<bool>,
 1055    show_indent_guides: Option<bool>,
 1056    placeholder_text: Option<Arc<str>>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_inline_completion: Option<InlineCompletionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    inline_completions_hidden_for_vim_mode: bool,
 1104    show_inline_completions_override: Option<bool>,
 1105    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177}
 1178
 1179#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1180enum NextScrollCursorCenterTopBottom {
 1181    #[default]
 1182    Center,
 1183    Top,
 1184    Bottom,
 1185}
 1186
 1187impl NextScrollCursorCenterTopBottom {
 1188    fn next(&self) -> Self {
 1189        match self {
 1190            Self::Center => Self::Top,
 1191            Self::Top => Self::Bottom,
 1192            Self::Bottom => Self::Center,
 1193        }
 1194    }
 1195}
 1196
 1197#[derive(Clone)]
 1198pub struct EditorSnapshot {
 1199    pub mode: EditorMode,
 1200    show_gutter: bool,
 1201    show_line_numbers: Option<bool>,
 1202    show_git_diff_gutter: Option<bool>,
 1203    show_code_actions: Option<bool>,
 1204    show_runnables: Option<bool>,
 1205    show_breakpoints: Option<bool>,
 1206    git_blame_gutter_max_author_length: Option<usize>,
 1207    pub display_snapshot: DisplaySnapshot,
 1208    pub placeholder_text: Option<Arc<str>>,
 1209    is_focused: bool,
 1210    scroll_anchor: ScrollAnchor,
 1211    ongoing_scroll: OngoingScroll,
 1212    current_line_highlight: CurrentLineHighlight,
 1213    gutter_hovered: bool,
 1214}
 1215
 1216#[derive(Default, Debug, Clone, Copy)]
 1217pub struct GutterDimensions {
 1218    pub left_padding: Pixels,
 1219    pub right_padding: Pixels,
 1220    pub width: Pixels,
 1221    pub margin: Pixels,
 1222    pub git_blame_entries_width: Option<Pixels>,
 1223}
 1224
 1225impl GutterDimensions {
 1226    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1227        Self {
 1228            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1229            ..Default::default()
 1230        }
 1231    }
 1232
 1233    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1234        -cx.text_system().descent(font_id, font_size)
 1235    }
 1236    /// The full width of the space taken up by the gutter.
 1237    pub fn full_width(&self) -> Pixels {
 1238        self.margin + self.width
 1239    }
 1240
 1241    /// The width of the space reserved for the fold indicators,
 1242    /// use alongside 'justify_end' and `gutter_width` to
 1243    /// right align content with the line numbers
 1244    pub fn fold_area_width(&self) -> Pixels {
 1245        self.margin + self.right_padding
 1246    }
 1247}
 1248
 1249struct CharacterDimensions {
 1250    em_width: Pixels,
 1251    em_advance: Pixels,
 1252    line_height: Pixels,
 1253}
 1254
 1255#[derive(Debug)]
 1256pub struct RemoteSelection {
 1257    pub replica_id: ReplicaId,
 1258    pub selection: Selection<Anchor>,
 1259    pub cursor_shape: CursorShape,
 1260    pub collaborator_id: CollaboratorId,
 1261    pub line_mode: bool,
 1262    pub user_name: Option<SharedString>,
 1263    pub color: PlayerColor,
 1264}
 1265
 1266#[derive(Clone, Debug)]
 1267struct SelectionHistoryEntry {
 1268    selections: Arc<[Selection<Anchor>]>,
 1269    select_next_state: Option<SelectNextState>,
 1270    select_prev_state: Option<SelectNextState>,
 1271    add_selections_state: Option<AddSelectionsState>,
 1272}
 1273
 1274#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1275enum SelectionHistoryMode {
 1276    Normal,
 1277    Undoing,
 1278    Redoing,
 1279    Skipping,
 1280}
 1281
 1282#[derive(Clone, PartialEq, Eq, Hash)]
 1283struct HoveredCursor {
 1284    replica_id: u16,
 1285    selection_id: usize,
 1286}
 1287
 1288impl Default for SelectionHistoryMode {
 1289    fn default() -> Self {
 1290        Self::Normal
 1291    }
 1292}
 1293
 1294#[derive(Debug)]
 1295/// SelectionEffects controls the side-effects of updating the selection.
 1296///
 1297/// The default behaviour does "what you mostly want":
 1298/// - it pushes to the nav history if the cursor moved by >10 lines
 1299/// - it re-triggers completion requests
 1300/// - it scrolls to fit
 1301///
 1302/// You might want to modify these behaviours. For example when doing a "jump"
 1303/// like go to definition, we always want to add to nav history; but when scrolling
 1304/// in vim mode we never do.
 1305///
 1306/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1307/// move.
 1308pub struct SelectionEffects {
 1309    nav_history: Option<bool>,
 1310    completions: bool,
 1311    scroll: Option<Autoscroll>,
 1312}
 1313
 1314impl Default for SelectionEffects {
 1315    fn default() -> Self {
 1316        Self {
 1317            nav_history: None,
 1318            completions: true,
 1319            scroll: Some(Autoscroll::fit()),
 1320        }
 1321    }
 1322}
 1323impl SelectionEffects {
 1324    pub fn scroll(scroll: Autoscroll) -> Self {
 1325        Self {
 1326            scroll: Some(scroll),
 1327            ..Default::default()
 1328        }
 1329    }
 1330
 1331    pub fn no_scroll() -> Self {
 1332        Self {
 1333            scroll: None,
 1334            ..Default::default()
 1335        }
 1336    }
 1337
 1338    pub fn completions(self, completions: bool) -> Self {
 1339        Self {
 1340            completions,
 1341            ..self
 1342        }
 1343    }
 1344
 1345    pub fn nav_history(self, nav_history: bool) -> Self {
 1346        Self {
 1347            nav_history: Some(nav_history),
 1348            ..self
 1349        }
 1350    }
 1351}
 1352
 1353struct DeferredSelectionEffectsState {
 1354    changed: bool,
 1355    effects: SelectionEffects,
 1356    old_cursor_position: Anchor,
 1357    history_entry: SelectionHistoryEntry,
 1358}
 1359
 1360#[derive(Default)]
 1361struct SelectionHistory {
 1362    #[allow(clippy::type_complexity)]
 1363    selections_by_transaction:
 1364        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1365    mode: SelectionHistoryMode,
 1366    undo_stack: VecDeque<SelectionHistoryEntry>,
 1367    redo_stack: VecDeque<SelectionHistoryEntry>,
 1368}
 1369
 1370impl SelectionHistory {
 1371    #[track_caller]
 1372    fn insert_transaction(
 1373        &mut self,
 1374        transaction_id: TransactionId,
 1375        selections: Arc<[Selection<Anchor>]>,
 1376    ) {
 1377        if selections.is_empty() {
 1378            log::error!(
 1379                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1380                std::panic::Location::caller()
 1381            );
 1382            return;
 1383        }
 1384        self.selections_by_transaction
 1385            .insert(transaction_id, (selections, None));
 1386    }
 1387
 1388    #[allow(clippy::type_complexity)]
 1389    fn transaction(
 1390        &self,
 1391        transaction_id: TransactionId,
 1392    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1393        self.selections_by_transaction.get(&transaction_id)
 1394    }
 1395
 1396    #[allow(clippy::type_complexity)]
 1397    fn transaction_mut(
 1398        &mut self,
 1399        transaction_id: TransactionId,
 1400    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1401        self.selections_by_transaction.get_mut(&transaction_id)
 1402    }
 1403
 1404    fn push(&mut self, entry: SelectionHistoryEntry) {
 1405        if !entry.selections.is_empty() {
 1406            match self.mode {
 1407                SelectionHistoryMode::Normal => {
 1408                    self.push_undo(entry);
 1409                    self.redo_stack.clear();
 1410                }
 1411                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1412                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1413                SelectionHistoryMode::Skipping => {}
 1414            }
 1415        }
 1416    }
 1417
 1418    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1419        if self
 1420            .undo_stack
 1421            .back()
 1422            .map_or(true, |e| e.selections != entry.selections)
 1423        {
 1424            self.undo_stack.push_back(entry);
 1425            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1426                self.undo_stack.pop_front();
 1427            }
 1428        }
 1429    }
 1430
 1431    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1432        if self
 1433            .redo_stack
 1434            .back()
 1435            .map_or(true, |e| e.selections != entry.selections)
 1436        {
 1437            self.redo_stack.push_back(entry);
 1438            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1439                self.redo_stack.pop_front();
 1440            }
 1441        }
 1442    }
 1443}
 1444
 1445#[derive(Clone, Copy)]
 1446pub struct RowHighlightOptions {
 1447    pub autoscroll: bool,
 1448    pub include_gutter: bool,
 1449}
 1450
 1451impl Default for RowHighlightOptions {
 1452    fn default() -> Self {
 1453        Self {
 1454            autoscroll: Default::default(),
 1455            include_gutter: true,
 1456        }
 1457    }
 1458}
 1459
 1460struct RowHighlight {
 1461    index: usize,
 1462    range: Range<Anchor>,
 1463    color: Hsla,
 1464    options: RowHighlightOptions,
 1465    type_id: TypeId,
 1466}
 1467
 1468#[derive(Clone, Debug)]
 1469struct AddSelectionsState {
 1470    groups: Vec<AddSelectionsGroup>,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsGroup {
 1475    above: bool,
 1476    stack: Vec<usize>,
 1477}
 1478
 1479#[derive(Clone)]
 1480struct SelectNextState {
 1481    query: AhoCorasick,
 1482    wordwise: bool,
 1483    done: bool,
 1484}
 1485
 1486impl std::fmt::Debug for SelectNextState {
 1487    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1488        f.debug_struct(std::any::type_name::<Self>())
 1489            .field("wordwise", &self.wordwise)
 1490            .field("done", &self.done)
 1491            .finish()
 1492    }
 1493}
 1494
 1495#[derive(Debug)]
 1496struct AutocloseRegion {
 1497    selection_id: usize,
 1498    range: Range<Anchor>,
 1499    pair: BracketPair,
 1500}
 1501
 1502#[derive(Debug)]
 1503struct SnippetState {
 1504    ranges: Vec<Vec<Range<Anchor>>>,
 1505    active_index: usize,
 1506    choices: Vec<Option<Vec<String>>>,
 1507}
 1508
 1509#[doc(hidden)]
 1510pub struct RenameState {
 1511    pub range: Range<Anchor>,
 1512    pub old_name: Arc<str>,
 1513    pub editor: Entity<Editor>,
 1514    block_id: CustomBlockId,
 1515}
 1516
 1517struct InvalidationStack<T>(Vec<T>);
 1518
 1519struct RegisteredInlineCompletionProvider {
 1520    provider: Arc<dyn InlineCompletionProviderHandle>,
 1521    _subscription: Subscription,
 1522}
 1523
 1524#[derive(Debug, PartialEq, Eq)]
 1525pub struct ActiveDiagnosticGroup {
 1526    pub active_range: Range<Anchor>,
 1527    pub active_message: String,
 1528    pub group_id: usize,
 1529    pub blocks: HashSet<CustomBlockId>,
 1530}
 1531
 1532#[derive(Debug, PartialEq, Eq)]
 1533
 1534pub(crate) enum ActiveDiagnostic {
 1535    None,
 1536    All,
 1537    Group(ActiveDiagnosticGroup),
 1538}
 1539
 1540#[derive(Serialize, Deserialize, Clone, Debug)]
 1541pub struct ClipboardSelection {
 1542    /// The number of bytes in this selection.
 1543    pub len: usize,
 1544    /// Whether this was a full-line selection.
 1545    pub is_entire_line: bool,
 1546    /// The indentation of the first line when this content was originally copied.
 1547    pub first_line_indent: u32,
 1548}
 1549
 1550// selections, scroll behavior, was newest selection reversed
 1551type SelectSyntaxNodeHistoryState = (
 1552    Box<[Selection<usize>]>,
 1553    SelectSyntaxNodeScrollBehavior,
 1554    bool,
 1555);
 1556
 1557#[derive(Default)]
 1558struct SelectSyntaxNodeHistory {
 1559    stack: Vec<SelectSyntaxNodeHistoryState>,
 1560    // disable temporarily to allow changing selections without losing the stack
 1561    pub disable_clearing: bool,
 1562}
 1563
 1564impl SelectSyntaxNodeHistory {
 1565    pub fn try_clear(&mut self) {
 1566        if !self.disable_clearing {
 1567            self.stack.clear();
 1568        }
 1569    }
 1570
 1571    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1572        self.stack.push(selection);
 1573    }
 1574
 1575    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1576        self.stack.pop()
 1577    }
 1578}
 1579
 1580enum SelectSyntaxNodeScrollBehavior {
 1581    CursorTop,
 1582    FitSelection,
 1583    CursorBottom,
 1584}
 1585
 1586#[derive(Debug)]
 1587pub(crate) struct NavigationData {
 1588    cursor_anchor: Anchor,
 1589    cursor_position: Point,
 1590    scroll_anchor: ScrollAnchor,
 1591    scroll_top_row: u32,
 1592}
 1593
 1594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1595pub enum GotoDefinitionKind {
 1596    Symbol,
 1597    Declaration,
 1598    Type,
 1599    Implementation,
 1600}
 1601
 1602#[derive(Debug, Clone)]
 1603enum InlayHintRefreshReason {
 1604    ModifiersChanged(bool),
 1605    Toggle(bool),
 1606    SettingsChange(InlayHintSettings),
 1607    NewLinesShown,
 1608    BufferEdited(HashSet<Arc<Language>>),
 1609    RefreshRequested,
 1610    ExcerptsRemoved(Vec<ExcerptId>),
 1611}
 1612
 1613impl InlayHintRefreshReason {
 1614    fn description(&self) -> &'static str {
 1615        match self {
 1616            Self::ModifiersChanged(_) => "modifiers changed",
 1617            Self::Toggle(_) => "toggle",
 1618            Self::SettingsChange(_) => "settings change",
 1619            Self::NewLinesShown => "new lines shown",
 1620            Self::BufferEdited(_) => "buffer edited",
 1621            Self::RefreshRequested => "refresh requested",
 1622            Self::ExcerptsRemoved(_) => "excerpts removed",
 1623        }
 1624    }
 1625}
 1626
 1627pub enum FormatTarget {
 1628    Buffers(HashSet<Entity<Buffer>>),
 1629    Ranges(Vec<Range<MultiBufferPoint>>),
 1630}
 1631
 1632pub(crate) struct FocusedBlock {
 1633    id: BlockId,
 1634    focus_handle: WeakFocusHandle,
 1635}
 1636
 1637#[derive(Clone)]
 1638enum JumpData {
 1639    MultiBufferRow {
 1640        row: MultiBufferRow,
 1641        line_offset_from_top: u32,
 1642    },
 1643    MultiBufferPoint {
 1644        excerpt_id: ExcerptId,
 1645        position: Point,
 1646        anchor: text::Anchor,
 1647        line_offset_from_top: u32,
 1648    },
 1649}
 1650
 1651pub enum MultibufferSelectionMode {
 1652    First,
 1653    All,
 1654}
 1655
 1656#[derive(Clone, Copy, Debug, Default)]
 1657pub struct RewrapOptions {
 1658    pub override_language_settings: bool,
 1659    pub preserve_existing_whitespace: bool,
 1660}
 1661
 1662impl Editor {
 1663    pub fn single_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::SingleLine, buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::full(), buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn auto_height(
 1676        min_lines: usize,
 1677        max_lines: usize,
 1678        window: &mut Window,
 1679        cx: &mut Context<Self>,
 1680    ) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::AutoHeight {
 1685                min_lines,
 1686                max_lines: Some(max_lines),
 1687            },
 1688            buffer,
 1689            None,
 1690            window,
 1691            cx,
 1692        )
 1693    }
 1694
 1695    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1696    /// The editor grows as tall as needed to fit its content.
 1697    pub fn auto_height_unbounded(
 1698        min_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: None,
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    pub fn for_buffer(
 1717        buffer: Entity<Buffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(EditorMode::full(), buffer, project, window, cx)
 1724    }
 1725
 1726    pub fn for_multibuffer(
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Self::new(EditorMode::full(), buffer, project, window, cx)
 1733    }
 1734
 1735    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let mut clone = Self::new(
 1737            self.mode.clone(),
 1738            self.buffer.clone(),
 1739            self.project.clone(),
 1740            window,
 1741            cx,
 1742        );
 1743        self.display_map.update(cx, |display_map, cx| {
 1744            let snapshot = display_map.snapshot(cx);
 1745            clone.display_map.update(cx, |display_map, cx| {
 1746                display_map.set_state(&snapshot, cx);
 1747            });
 1748        });
 1749        clone.folds_did_change(cx);
 1750        clone.selections.clone_state(&self.selections);
 1751        clone.scroll_manager.clone_state(&self.scroll_manager);
 1752        clone.searchable = self.searchable;
 1753        clone.read_only = self.read_only;
 1754        clone
 1755    }
 1756
 1757    pub fn new(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        Editor::new_internal(mode, buffer, project, None, window, cx)
 1765    }
 1766
 1767    fn new_internal(
 1768        mode: EditorMode,
 1769        buffer: Entity<MultiBuffer>,
 1770        project: Option<Entity<Project>>,
 1771        display_map: Option<Entity<DisplayMap>>,
 1772        window: &mut Window,
 1773        cx: &mut Context<Self>,
 1774    ) -> Self {
 1775        debug_assert!(
 1776            display_map.is_none() || mode.is_minimap(),
 1777            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1778        );
 1779
 1780        let full_mode = mode.is_full();
 1781        let is_minimap = mode.is_minimap();
 1782        let diagnostics_max_severity = if full_mode {
 1783            EditorSettings::get_global(cx)
 1784                .diagnostics_max_severity
 1785                .unwrap_or(DiagnosticSeverity::Hint)
 1786        } else {
 1787            DiagnosticSeverity::Off
 1788        };
 1789        let style = window.text_style();
 1790        let font_size = style.font_size.to_pixels(window.rem_size());
 1791        let editor = cx.entity().downgrade();
 1792        let fold_placeholder = FoldPlaceholder {
 1793            constrain_width: true,
 1794            render: Arc::new(move |fold_id, fold_range, cx| {
 1795                let editor = editor.clone();
 1796                div()
 1797                    .id(fold_id)
 1798                    .bg(cx.theme().colors().ghost_element_background)
 1799                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1800                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1801                    .rounded_xs()
 1802                    .size_full()
 1803                    .cursor_pointer()
 1804                    .child("")
 1805                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1806                    .on_click(move |_, _window, cx| {
 1807                        editor
 1808                            .update(cx, |editor, cx| {
 1809                                editor.unfold_ranges(
 1810                                    &[fold_range.start..fold_range.end],
 1811                                    true,
 1812                                    false,
 1813                                    cx,
 1814                                );
 1815                                cx.stop_propagation();
 1816                            })
 1817                            .ok();
 1818                    })
 1819                    .into_any()
 1820            }),
 1821            merge_adjacent: true,
 1822            ..FoldPlaceholder::default()
 1823        };
 1824        let display_map = display_map.unwrap_or_else(|| {
 1825            cx.new(|cx| {
 1826                DisplayMap::new(
 1827                    buffer.clone(),
 1828                    style.font(),
 1829                    font_size,
 1830                    None,
 1831                    FILE_HEADER_HEIGHT,
 1832                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1833                    fold_placeholder,
 1834                    diagnostics_max_severity,
 1835                    cx,
 1836                )
 1837            })
 1838        });
 1839
 1840        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1841
 1842        let blink_manager = cx.new(|cx| {
 1843            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1844            if is_minimap {
 1845                blink_manager.disable(cx);
 1846            }
 1847            blink_manager
 1848        });
 1849
 1850        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1851            .then(|| language_settings::SoftWrap::None);
 1852
 1853        let mut project_subscriptions = Vec::new();
 1854        if full_mode {
 1855            if let Some(project) = project.as_ref() {
 1856                project_subscriptions.push(cx.subscribe_in(
 1857                    project,
 1858                    window,
 1859                    |editor, _, event, window, cx| match event {
 1860                        project::Event::RefreshCodeLens => {
 1861                            // we always query lens with actions, without storing them, always refreshing them
 1862                        }
 1863                        project::Event::RefreshInlayHints => {
 1864                            editor
 1865                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                        }
 1867                        project::Event::LanguageServerAdded(..)
 1868                        | project::Event::LanguageServerRemoved(..) => {
 1869                            if editor.tasks_update_task.is_none() {
 1870                                editor.tasks_update_task =
 1871                                    Some(editor.refresh_runnables(window, cx));
 1872                            }
 1873                            editor.update_lsp_data(true, None, window, cx);
 1874                        }
 1875                        project::Event::SnippetEdit(id, snippet_edits) => {
 1876                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                                let focus_handle = editor.focus_handle(cx);
 1878                                if focus_handle.is_focused(window) {
 1879                                    let snapshot = buffer.read(cx).snapshot();
 1880                                    for (range, snippet) in snippet_edits {
 1881                                        let editor_range =
 1882                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                        editor
 1884                                            .insert_snippet(
 1885                                                &[editor_range],
 1886                                                snippet.clone(),
 1887                                                window,
 1888                                                cx,
 1889                                            )
 1890                                            .ok();
 1891                                    }
 1892                                }
 1893                            }
 1894                        }
 1895                        _ => {}
 1896                    },
 1897                ));
 1898                if let Some(task_inventory) = project
 1899                    .read(cx)
 1900                    .task_store()
 1901                    .read(cx)
 1902                    .task_inventory()
 1903                    .cloned()
 1904                {
 1905                    project_subscriptions.push(cx.observe_in(
 1906                        &task_inventory,
 1907                        window,
 1908                        |editor, _, window, cx| {
 1909                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1910                        },
 1911                    ));
 1912                };
 1913
 1914                project_subscriptions.push(cx.subscribe_in(
 1915                    &project.read(cx).breakpoint_store(),
 1916                    window,
 1917                    |editor, _, event, window, cx| match event {
 1918                        BreakpointStoreEvent::ClearDebugLines => {
 1919                            editor.clear_row_highlights::<ActiveDebugLine>();
 1920                            editor.refresh_inline_values(cx);
 1921                        }
 1922                        BreakpointStoreEvent::SetDebugLine => {
 1923                            if editor.go_to_active_debug_line(window, cx) {
 1924                                cx.stop_propagation();
 1925                            }
 1926
 1927                            editor.refresh_inline_values(cx);
 1928                        }
 1929                        _ => {}
 1930                    },
 1931                ));
 1932                let git_store = project.read(cx).git_store().clone();
 1933                let project = project.clone();
 1934                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1935                    match event {
 1936                        GitStoreEvent::RepositoryUpdated(
 1937                            _,
 1938                            RepositoryEvent::Updated {
 1939                                new_instance: true, ..
 1940                            },
 1941                            _,
 1942                        ) => {
 1943                            this.load_diff_task = Some(
 1944                                update_uncommitted_diff_for_buffer(
 1945                                    cx.entity(),
 1946                                    &project,
 1947                                    this.buffer.read(cx).all_buffers(),
 1948                                    this.buffer.clone(),
 1949                                    cx,
 1950                                )
 1951                                .shared(),
 1952                            );
 1953                        }
 1954                        _ => {}
 1955                    }
 1956                }));
 1957            }
 1958        }
 1959
 1960        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1961
 1962        let inlay_hint_settings =
 1963            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1964        let focus_handle = cx.focus_handle();
 1965        if !is_minimap {
 1966            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1967                .detach();
 1968            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1969                .detach();
 1970            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1971                .detach();
 1972            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1973                .detach();
 1974            cx.observe_pending_input(window, Self::observe_pending_input)
 1975                .detach();
 1976        }
 1977
 1978        let show_indent_guides = if matches!(
 1979            mode,
 1980            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1981        ) {
 1982            Some(false)
 1983        } else {
 1984            None
 1985        };
 1986
 1987        let breakpoint_store = match (&mode, project.as_ref()) {
 1988            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1989            _ => None,
 1990        };
 1991
 1992        let mut code_action_providers = Vec::new();
 1993        let mut load_uncommitted_diff = None;
 1994        if let Some(project) = project.clone() {
 1995            load_uncommitted_diff = Some(
 1996                update_uncommitted_diff_for_buffer(
 1997                    cx.entity(),
 1998                    &project,
 1999                    buffer.read(cx).all_buffers(),
 2000                    buffer.clone(),
 2001                    cx,
 2002                )
 2003                .shared(),
 2004            );
 2005            code_action_providers.push(Rc::new(project) as Rc<_>);
 2006        }
 2007
 2008        let mut editor = Self {
 2009            focus_handle,
 2010            show_cursor_when_unfocused: false,
 2011            last_focused_descendant: None,
 2012            buffer: buffer.clone(),
 2013            display_map: display_map.clone(),
 2014            selections,
 2015            scroll_manager: ScrollManager::new(cx),
 2016            columnar_selection_state: None,
 2017            add_selections_state: None,
 2018            select_next_state: None,
 2019            select_prev_state: None,
 2020            selection_history: SelectionHistory::default(),
 2021            defer_selection_effects: false,
 2022            deferred_selection_effects_state: None,
 2023            autoclose_regions: Vec::new(),
 2024            snippet_stack: InvalidationStack::default(),
 2025            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2026            ime_transaction: None,
 2027            active_diagnostics: ActiveDiagnostic::None,
 2028            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2029            inline_diagnostics_update: Task::ready(()),
 2030            inline_diagnostics: Vec::new(),
 2031            soft_wrap_mode_override,
 2032            diagnostics_max_severity,
 2033            hard_wrap: None,
 2034            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2035            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2037            project,
 2038            blink_manager: blink_manager.clone(),
 2039            show_local_selections: true,
 2040            show_scrollbars: ScrollbarAxes {
 2041                horizontal: full_mode,
 2042                vertical: full_mode,
 2043            },
 2044            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2045            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2046            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2047            show_gutter: full_mode,
 2048            show_line_numbers: (!full_mode).then_some(false),
 2049            use_relative_line_numbers: None,
 2050            disable_expand_excerpt_buttons: !full_mode,
 2051            show_git_diff_gutter: None,
 2052            show_code_actions: None,
 2053            show_runnables: None,
 2054            show_breakpoints: None,
 2055            show_wrap_guides: None,
 2056            show_indent_guides,
 2057            placeholder_text: None,
 2058            highlight_order: 0,
 2059            highlighted_rows: HashMap::default(),
 2060            background_highlights: TreeMap::default(),
 2061            gutter_highlights: TreeMap::default(),
 2062            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2063            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2064            nav_history: None,
 2065            context_menu: RefCell::new(None),
 2066            context_menu_options: None,
 2067            mouse_context_menu: None,
 2068            completion_tasks: Vec::new(),
 2069            inline_blame_popover: None,
 2070            inline_blame_popover_show_task: None,
 2071            signature_help_state: SignatureHelpState::default(),
 2072            auto_signature_help: None,
 2073            find_all_references_task_sources: Vec::new(),
 2074            next_completion_id: 0,
 2075            next_inlay_id: 0,
 2076            code_action_providers,
 2077            available_code_actions: None,
 2078            code_actions_task: None,
 2079            quick_selection_highlight_task: None,
 2080            debounced_selection_highlight_task: None,
 2081            document_highlights_task: None,
 2082            linked_editing_range_task: None,
 2083            pending_rename: None,
 2084            searchable: !is_minimap,
 2085            cursor_shape: EditorSettings::get_global(cx)
 2086                .cursor_shape
 2087                .unwrap_or_default(),
 2088            current_line_highlight: None,
 2089            autoindent_mode: Some(AutoindentMode::EachLine),
 2090            collapse_matches: false,
 2091            workspace: None,
 2092            input_enabled: !is_minimap,
 2093            use_modal_editing: full_mode,
 2094            read_only: is_minimap,
 2095            use_autoclose: true,
 2096            use_auto_surround: true,
 2097            auto_replace_emoji_shortcode: false,
 2098            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2099            leader_id: None,
 2100            remote_id: None,
 2101            hover_state: HoverState::default(),
 2102            pending_mouse_down: None,
 2103            hovered_link_state: None,
 2104            edit_prediction_provider: None,
 2105            active_inline_completion: None,
 2106            stale_inline_completion_in_menu: None,
 2107            edit_prediction_preview: EditPredictionPreview::Inactive {
 2108                released_too_fast: false,
 2109            },
 2110            inline_diagnostics_enabled: full_mode,
 2111            diagnostics_enabled: full_mode,
 2112            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2113            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2114            gutter_hovered: false,
 2115            pixel_position_of_newest_cursor: None,
 2116            last_bounds: None,
 2117            last_position_map: None,
 2118            expect_bounds_change: None,
 2119            gutter_dimensions: GutterDimensions::default(),
 2120            style: None,
 2121            show_cursor_names: false,
 2122            hovered_cursors: HashMap::default(),
 2123            next_editor_action_id: EditorActionId::default(),
 2124            editor_actions: Rc::default(),
 2125            inline_completions_hidden_for_vim_mode: false,
 2126            show_inline_completions_override: None,
 2127            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2128            edit_prediction_settings: EditPredictionSettings::Disabled,
 2129            edit_prediction_indent_conflict: false,
 2130            edit_prediction_requires_modifier_in_indent_conflict: true,
 2131            custom_context_menu: None,
 2132            show_git_blame_gutter: false,
 2133            show_git_blame_inline: false,
 2134            show_selection_menu: None,
 2135            show_git_blame_inline_delay_task: None,
 2136            git_blame_inline_enabled: full_mode
 2137                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2138            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2139            serialize_dirty_buffers: !is_minimap
 2140                && ProjectSettings::get_global(cx)
 2141                    .session
 2142                    .restore_unsaved_buffers,
 2143            blame: None,
 2144            blame_subscription: None,
 2145            tasks: BTreeMap::default(),
 2146
 2147            breakpoint_store,
 2148            gutter_breakpoint_indicator: (None, None),
 2149            hovered_diff_hunk_row: None,
 2150            _subscriptions: (!is_minimap)
 2151                .then(|| {
 2152                    vec![
 2153                        cx.observe(&buffer, Self::on_buffer_changed),
 2154                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2155                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2156                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2157                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2158                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2159                        cx.observe_window_activation(window, |editor, window, cx| {
 2160                            let active = window.is_window_active();
 2161                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2162                                if active {
 2163                                    blink_manager.enable(cx);
 2164                                } else {
 2165                                    blink_manager.disable(cx);
 2166                                }
 2167                            });
 2168                            if active {
 2169                                editor.show_mouse_cursor(cx);
 2170                            }
 2171                        }),
 2172                    ]
 2173                })
 2174                .unwrap_or_default(),
 2175            tasks_update_task: None,
 2176            pull_diagnostics_task: Task::ready(()),
 2177            colors: None,
 2178            next_color_inlay_id: 0,
 2179            linked_edit_ranges: Default::default(),
 2180            in_project_search: false,
 2181            previous_search_ranges: None,
 2182            breadcrumb_header: None,
 2183            focused_block: None,
 2184            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2185            addons: HashMap::default(),
 2186            registered_buffers: HashMap::default(),
 2187            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2188            selection_mark_mode: false,
 2189            toggle_fold_multiple_buffers: Task::ready(()),
 2190            serialize_selections: Task::ready(()),
 2191            serialize_folds: Task::ready(()),
 2192            text_style_refinement: None,
 2193            load_diff_task: load_uncommitted_diff,
 2194            temporary_diff_override: false,
 2195            mouse_cursor_hidden: false,
 2196            minimap: None,
 2197            hide_mouse_mode: EditorSettings::get_global(cx)
 2198                .hide_mouse
 2199                .unwrap_or_default(),
 2200            change_list: ChangeList::new(),
 2201            mode,
 2202            selection_drag_state: SelectionDragState::None,
 2203            folding_newlines: Task::ready(()),
 2204        };
 2205
 2206        if is_minimap {
 2207            return editor;
 2208        }
 2209
 2210        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2211            editor
 2212                ._subscriptions
 2213                .push(cx.observe(breakpoints, |_, _, cx| {
 2214                    cx.notify();
 2215                }));
 2216        }
 2217        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2218        editor._subscriptions.extend(project_subscriptions);
 2219
 2220        editor._subscriptions.push(cx.subscribe_in(
 2221            &cx.entity(),
 2222            window,
 2223            |editor, _, e: &EditorEvent, window, cx| match e {
 2224                EditorEvent::ScrollPositionChanged { local, .. } => {
 2225                    if *local {
 2226                        let new_anchor = editor.scroll_manager.anchor();
 2227                        let snapshot = editor.snapshot(window, cx);
 2228                        editor.update_restoration_data(cx, move |data| {
 2229                            data.scroll_position = (
 2230                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2231                                new_anchor.offset,
 2232                            );
 2233                        });
 2234                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2235                        editor.inline_blame_popover.take();
 2236                    }
 2237                }
 2238                EditorEvent::Edited { .. } => {
 2239                    if !vim_enabled(cx) {
 2240                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2241                        let pop_state = editor
 2242                            .change_list
 2243                            .last()
 2244                            .map(|previous| {
 2245                                previous.len() == selections.len()
 2246                                    && previous.iter().enumerate().all(|(ix, p)| {
 2247                                        p.to_display_point(&map).row()
 2248                                            == selections[ix].head().row()
 2249                                    })
 2250                            })
 2251                            .unwrap_or(false);
 2252                        let new_positions = selections
 2253                            .into_iter()
 2254                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2255                            .collect();
 2256                        editor
 2257                            .change_list
 2258                            .push_to_change_list(pop_state, new_positions);
 2259                    }
 2260                }
 2261                _ => (),
 2262            },
 2263        ));
 2264
 2265        if let Some(dap_store) = editor
 2266            .project
 2267            .as_ref()
 2268            .map(|project| project.read(cx).dap_store())
 2269        {
 2270            let weak_editor = cx.weak_entity();
 2271
 2272            editor
 2273                ._subscriptions
 2274                .push(
 2275                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2276                        let session_entity = cx.entity();
 2277                        weak_editor
 2278                            .update(cx, |editor, cx| {
 2279                                editor._subscriptions.push(
 2280                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2281                                );
 2282                            })
 2283                            .ok();
 2284                    }),
 2285                );
 2286
 2287            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2288                editor
 2289                    ._subscriptions
 2290                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2291            }
 2292        }
 2293
 2294        // skip adding the initial selection to selection history
 2295        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2296        editor.end_selection(window, cx);
 2297        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2298
 2299        editor.scroll_manager.show_scrollbars(window, cx);
 2300        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2301
 2302        if full_mode {
 2303            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2304            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2305
 2306            if editor.git_blame_inline_enabled {
 2307                editor.start_git_blame_inline(false, window, cx);
 2308            }
 2309
 2310            editor.go_to_active_debug_line(window, cx);
 2311
 2312            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2313                if let Some(project) = editor.project.as_ref() {
 2314                    let handle = project.update(cx, |project, cx| {
 2315                        project.register_buffer_with_language_servers(&buffer, cx)
 2316                    });
 2317                    editor
 2318                        .registered_buffers
 2319                        .insert(buffer.read(cx).remote_id(), handle);
 2320                }
 2321            }
 2322
 2323            editor.minimap =
 2324                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2325            editor.colors = Some(LspColorData::new(cx));
 2326            editor.update_lsp_data(false, None, window, cx);
 2327        }
 2328
 2329        if editor.mode.is_full() {
 2330            editor.report_editor_event("Editor Opened", None, cx);
 2331        }
 2332
 2333        editor
 2334    }
 2335
 2336    pub fn deploy_mouse_context_menu(
 2337        &mut self,
 2338        position: gpui::Point<Pixels>,
 2339        context_menu: Entity<ContextMenu>,
 2340        window: &mut Window,
 2341        cx: &mut Context<Self>,
 2342    ) {
 2343        self.mouse_context_menu = Some(MouseContextMenu::new(
 2344            self,
 2345            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2346            context_menu,
 2347            window,
 2348            cx,
 2349        ));
 2350    }
 2351
 2352    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2353        self.mouse_context_menu
 2354            .as_ref()
 2355            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2356    }
 2357
 2358    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2359        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2360    }
 2361
 2362    fn key_context_internal(
 2363        &self,
 2364        has_active_edit_prediction: bool,
 2365        window: &Window,
 2366        cx: &App,
 2367    ) -> KeyContext {
 2368        let mut key_context = KeyContext::new_with_defaults();
 2369        key_context.add("Editor");
 2370        let mode = match self.mode {
 2371            EditorMode::SingleLine { .. } => "single_line",
 2372            EditorMode::AutoHeight { .. } => "auto_height",
 2373            EditorMode::Minimap { .. } => "minimap",
 2374            EditorMode::Full { .. } => "full",
 2375        };
 2376
 2377        if EditorSettings::jupyter_enabled(cx) {
 2378            key_context.add("jupyter");
 2379        }
 2380
 2381        key_context.set("mode", mode);
 2382        if self.pending_rename.is_some() {
 2383            key_context.add("renaming");
 2384        }
 2385
 2386        match self.context_menu.borrow().as_ref() {
 2387            Some(CodeContextMenu::Completions(menu)) => {
 2388                if menu.visible() {
 2389                    key_context.add("menu");
 2390                    key_context.add("showing_completions");
 2391                }
 2392            }
 2393            Some(CodeContextMenu::CodeActions(menu)) => {
 2394                if menu.visible() {
 2395                    key_context.add("menu");
 2396                    key_context.add("showing_code_actions")
 2397                }
 2398            }
 2399            None => {}
 2400        }
 2401
 2402        if self.signature_help_state.has_multiple_signatures() {
 2403            key_context.add("showing_signature_help");
 2404        }
 2405
 2406        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2407        if !self.focus_handle(cx).contains_focused(window, cx)
 2408            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2409        {
 2410            for addon in self.addons.values() {
 2411                addon.extend_key_context(&mut key_context, cx)
 2412            }
 2413        }
 2414
 2415        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2416            if let Some(extension) = singleton_buffer
 2417                .read(cx)
 2418                .file()
 2419                .and_then(|file| file.path().extension()?.to_str())
 2420            {
 2421                key_context.set("extension", extension.to_string());
 2422            }
 2423        } else {
 2424            key_context.add("multibuffer");
 2425        }
 2426
 2427        if has_active_edit_prediction {
 2428            if self.edit_prediction_in_conflict() {
 2429                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2430            } else {
 2431                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2432                key_context.add("copilot_suggestion");
 2433            }
 2434        }
 2435
 2436        if self.selection_mark_mode {
 2437            key_context.add("selection_mode");
 2438        }
 2439
 2440        key_context
 2441    }
 2442
 2443    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2444        if self.mouse_cursor_hidden {
 2445            self.mouse_cursor_hidden = false;
 2446            cx.notify();
 2447        }
 2448    }
 2449
 2450    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2451        let hide_mouse_cursor = match origin {
 2452            HideMouseCursorOrigin::TypingAction => {
 2453                matches!(
 2454                    self.hide_mouse_mode,
 2455                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2456                )
 2457            }
 2458            HideMouseCursorOrigin::MovementAction => {
 2459                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2460            }
 2461        };
 2462        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2463            self.mouse_cursor_hidden = hide_mouse_cursor;
 2464            cx.notify();
 2465        }
 2466    }
 2467
 2468    pub fn edit_prediction_in_conflict(&self) -> bool {
 2469        if !self.show_edit_predictions_in_menu() {
 2470            return false;
 2471        }
 2472
 2473        let showing_completions = self
 2474            .context_menu
 2475            .borrow()
 2476            .as_ref()
 2477            .map_or(false, |context| {
 2478                matches!(context, CodeContextMenu::Completions(_))
 2479            });
 2480
 2481        showing_completions
 2482            || self.edit_prediction_requires_modifier()
 2483            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2484            // bindings to insert tab characters.
 2485            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2486    }
 2487
 2488    pub fn accept_edit_prediction_keybind(
 2489        &self,
 2490        accept_partial: bool,
 2491        window: &Window,
 2492        cx: &App,
 2493    ) -> AcceptEditPredictionBinding {
 2494        let key_context = self.key_context_internal(true, window, cx);
 2495        let in_conflict = self.edit_prediction_in_conflict();
 2496
 2497        let bindings = if accept_partial {
 2498            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2499        } else {
 2500            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2501        };
 2502
 2503        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2504        // just the first one.
 2505        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2506            !in_conflict
 2507                || binding
 2508                    .keystrokes()
 2509                    .first()
 2510                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2511        }))
 2512    }
 2513
 2514    pub fn new_file(
 2515        workspace: &mut Workspace,
 2516        _: &workspace::NewFile,
 2517        window: &mut Window,
 2518        cx: &mut Context<Workspace>,
 2519    ) {
 2520        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2521            "Failed to create buffer",
 2522            window,
 2523            cx,
 2524            |e, _, _| match e.error_code() {
 2525                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2526                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2527                e.error_tag("required").unwrap_or("the latest version")
 2528            )),
 2529                _ => None,
 2530            },
 2531        );
 2532    }
 2533
 2534    pub fn new_in_workspace(
 2535        workspace: &mut Workspace,
 2536        window: &mut Window,
 2537        cx: &mut Context<Workspace>,
 2538    ) -> Task<Result<Entity<Editor>>> {
 2539        let project = workspace.project().clone();
 2540        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2541
 2542        cx.spawn_in(window, async move |workspace, cx| {
 2543            let buffer = create.await?;
 2544            workspace.update_in(cx, |workspace, window, cx| {
 2545                let editor =
 2546                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2547                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2548                editor
 2549            })
 2550        })
 2551    }
 2552
 2553    fn new_file_vertical(
 2554        workspace: &mut Workspace,
 2555        _: &workspace::NewFileSplitVertical,
 2556        window: &mut Window,
 2557        cx: &mut Context<Workspace>,
 2558    ) {
 2559        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2560    }
 2561
 2562    fn new_file_horizontal(
 2563        workspace: &mut Workspace,
 2564        _: &workspace::NewFileSplitHorizontal,
 2565        window: &mut Window,
 2566        cx: &mut Context<Workspace>,
 2567    ) {
 2568        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2569    }
 2570
 2571    fn new_file_in_direction(
 2572        workspace: &mut Workspace,
 2573        direction: SplitDirection,
 2574        window: &mut Window,
 2575        cx: &mut Context<Workspace>,
 2576    ) {
 2577        let project = workspace.project().clone();
 2578        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2579
 2580        cx.spawn_in(window, async move |workspace, cx| {
 2581            let buffer = create.await?;
 2582            workspace.update_in(cx, move |workspace, window, cx| {
 2583                workspace.split_item(
 2584                    direction,
 2585                    Box::new(
 2586                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2587                    ),
 2588                    window,
 2589                    cx,
 2590                )
 2591            })?;
 2592            anyhow::Ok(())
 2593        })
 2594        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2595            match e.error_code() {
 2596                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2597                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2598                e.error_tag("required").unwrap_or("the latest version")
 2599            )),
 2600                _ => None,
 2601            }
 2602        });
 2603    }
 2604
 2605    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2606        self.leader_id
 2607    }
 2608
 2609    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2610        &self.buffer
 2611    }
 2612
 2613    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2614        self.workspace.as_ref()?.0.upgrade()
 2615    }
 2616
 2617    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2618        self.buffer().read(cx).title(cx)
 2619    }
 2620
 2621    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2622        let git_blame_gutter_max_author_length = self
 2623            .render_git_blame_gutter(cx)
 2624            .then(|| {
 2625                if let Some(blame) = self.blame.as_ref() {
 2626                    let max_author_length =
 2627                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2628                    Some(max_author_length)
 2629                } else {
 2630                    None
 2631                }
 2632            })
 2633            .flatten();
 2634
 2635        EditorSnapshot {
 2636            mode: self.mode.clone(),
 2637            show_gutter: self.show_gutter,
 2638            show_line_numbers: self.show_line_numbers,
 2639            show_git_diff_gutter: self.show_git_diff_gutter,
 2640            show_code_actions: self.show_code_actions,
 2641            show_runnables: self.show_runnables,
 2642            show_breakpoints: self.show_breakpoints,
 2643            git_blame_gutter_max_author_length,
 2644            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2645            scroll_anchor: self.scroll_manager.anchor(),
 2646            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2647            placeholder_text: self.placeholder_text.clone(),
 2648            is_focused: self.focus_handle.is_focused(window),
 2649            current_line_highlight: self
 2650                .current_line_highlight
 2651                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2652            gutter_hovered: self.gutter_hovered,
 2653        }
 2654    }
 2655
 2656    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2657        self.buffer.read(cx).language_at(point, cx)
 2658    }
 2659
 2660    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2661        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2662    }
 2663
 2664    pub fn active_excerpt(
 2665        &self,
 2666        cx: &App,
 2667    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2668        self.buffer
 2669            .read(cx)
 2670            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2671    }
 2672
 2673    pub fn mode(&self) -> &EditorMode {
 2674        &self.mode
 2675    }
 2676
 2677    pub fn set_mode(&mut self, mode: EditorMode) {
 2678        self.mode = mode;
 2679    }
 2680
 2681    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2682        self.collaboration_hub.as_deref()
 2683    }
 2684
 2685    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2686        self.collaboration_hub = Some(hub);
 2687    }
 2688
 2689    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2690        self.in_project_search = in_project_search;
 2691    }
 2692
 2693    pub fn set_custom_context_menu(
 2694        &mut self,
 2695        f: impl 'static
 2696        + Fn(
 2697            &mut Self,
 2698            DisplayPoint,
 2699            &mut Window,
 2700            &mut Context<Self>,
 2701        ) -> Option<Entity<ui::ContextMenu>>,
 2702    ) {
 2703        self.custom_context_menu = Some(Box::new(f))
 2704    }
 2705
 2706    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2707        self.completion_provider = provider;
 2708    }
 2709
 2710    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2711        self.semantics_provider.clone()
 2712    }
 2713
 2714    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2715        self.semantics_provider = provider;
 2716    }
 2717
 2718    pub fn set_edit_prediction_provider<T>(
 2719        &mut self,
 2720        provider: Option<Entity<T>>,
 2721        window: &mut Window,
 2722        cx: &mut Context<Self>,
 2723    ) where
 2724        T: EditPredictionProvider,
 2725    {
 2726        self.edit_prediction_provider =
 2727            provider.map(|provider| RegisteredInlineCompletionProvider {
 2728                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2729                    if this.focus_handle.is_focused(window) {
 2730                        this.update_visible_inline_completion(window, cx);
 2731                    }
 2732                }),
 2733                provider: Arc::new(provider),
 2734            });
 2735        self.update_edit_prediction_settings(cx);
 2736        self.refresh_inline_completion(false, false, window, cx);
 2737    }
 2738
 2739    pub fn placeholder_text(&self) -> Option<&str> {
 2740        self.placeholder_text.as_deref()
 2741    }
 2742
 2743    pub fn set_placeholder_text(
 2744        &mut self,
 2745        placeholder_text: impl Into<Arc<str>>,
 2746        cx: &mut Context<Self>,
 2747    ) {
 2748        let placeholder_text = Some(placeholder_text.into());
 2749        if self.placeholder_text != placeholder_text {
 2750            self.placeholder_text = placeholder_text;
 2751            cx.notify();
 2752        }
 2753    }
 2754
 2755    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2756        self.cursor_shape = cursor_shape;
 2757
 2758        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2759        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2760
 2761        cx.notify();
 2762    }
 2763
 2764    pub fn set_current_line_highlight(
 2765        &mut self,
 2766        current_line_highlight: Option<CurrentLineHighlight>,
 2767    ) {
 2768        self.current_line_highlight = current_line_highlight;
 2769    }
 2770
 2771    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2772        self.collapse_matches = collapse_matches;
 2773    }
 2774
 2775    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2776        let buffers = self.buffer.read(cx).all_buffers();
 2777        let Some(project) = self.project.as_ref() else {
 2778            return;
 2779        };
 2780        project.update(cx, |project, cx| {
 2781            for buffer in buffers {
 2782                self.registered_buffers
 2783                    .entry(buffer.read(cx).remote_id())
 2784                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2785            }
 2786        })
 2787    }
 2788
 2789    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2790        if self.collapse_matches {
 2791            return range.start..range.start;
 2792        }
 2793        range.clone()
 2794    }
 2795
 2796    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2797        if self.display_map.read(cx).clip_at_line_ends != clip {
 2798            self.display_map
 2799                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2800        }
 2801    }
 2802
 2803    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2804        self.input_enabled = input_enabled;
 2805    }
 2806
 2807    pub fn set_inline_completions_hidden_for_vim_mode(
 2808        &mut self,
 2809        hidden: bool,
 2810        window: &mut Window,
 2811        cx: &mut Context<Self>,
 2812    ) {
 2813        if hidden != self.inline_completions_hidden_for_vim_mode {
 2814            self.inline_completions_hidden_for_vim_mode = hidden;
 2815            if hidden {
 2816                self.update_visible_inline_completion(window, cx);
 2817            } else {
 2818                self.refresh_inline_completion(true, false, window, cx);
 2819            }
 2820        }
 2821    }
 2822
 2823    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2824        self.menu_inline_completions_policy = value;
 2825    }
 2826
 2827    pub fn set_autoindent(&mut self, autoindent: bool) {
 2828        if autoindent {
 2829            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2830        } else {
 2831            self.autoindent_mode = None;
 2832        }
 2833    }
 2834
 2835    pub fn read_only(&self, cx: &App) -> bool {
 2836        self.read_only || self.buffer.read(cx).read_only()
 2837    }
 2838
 2839    pub fn set_read_only(&mut self, read_only: bool) {
 2840        self.read_only = read_only;
 2841    }
 2842
 2843    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2844        self.use_autoclose = autoclose;
 2845    }
 2846
 2847    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2848        self.use_auto_surround = auto_surround;
 2849    }
 2850
 2851    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2852        self.auto_replace_emoji_shortcode = auto_replace;
 2853    }
 2854
 2855    pub fn toggle_edit_predictions(
 2856        &mut self,
 2857        _: &ToggleEditPrediction,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) {
 2861        if self.show_inline_completions_override.is_some() {
 2862            self.set_show_edit_predictions(None, window, cx);
 2863        } else {
 2864            let show_edit_predictions = !self.edit_predictions_enabled();
 2865            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2866        }
 2867    }
 2868
 2869    pub fn set_show_edit_predictions(
 2870        &mut self,
 2871        show_edit_predictions: Option<bool>,
 2872        window: &mut Window,
 2873        cx: &mut Context<Self>,
 2874    ) {
 2875        self.show_inline_completions_override = show_edit_predictions;
 2876        self.update_edit_prediction_settings(cx);
 2877
 2878        if let Some(false) = show_edit_predictions {
 2879            self.discard_inline_completion(false, cx);
 2880        } else {
 2881            self.refresh_inline_completion(false, true, window, cx);
 2882        }
 2883    }
 2884
 2885    fn inline_completions_disabled_in_scope(
 2886        &self,
 2887        buffer: &Entity<Buffer>,
 2888        buffer_position: language::Anchor,
 2889        cx: &App,
 2890    ) -> bool {
 2891        let snapshot = buffer.read(cx).snapshot();
 2892        let settings = snapshot.settings_at(buffer_position, cx);
 2893
 2894        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2895            return false;
 2896        };
 2897
 2898        scope.override_name().map_or(false, |scope_name| {
 2899            settings
 2900                .edit_predictions_disabled_in
 2901                .iter()
 2902                .any(|s| s == scope_name)
 2903        })
 2904    }
 2905
 2906    pub fn set_use_modal_editing(&mut self, to: bool) {
 2907        self.use_modal_editing = to;
 2908    }
 2909
 2910    pub fn use_modal_editing(&self) -> bool {
 2911        self.use_modal_editing
 2912    }
 2913
 2914    fn selections_did_change(
 2915        &mut self,
 2916        local: bool,
 2917        old_cursor_position: &Anchor,
 2918        effects: SelectionEffects,
 2919        window: &mut Window,
 2920        cx: &mut Context<Self>,
 2921    ) {
 2922        window.invalidate_character_coordinates();
 2923
 2924        // Copy selections to primary selection buffer
 2925        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2926        if local {
 2927            let selections = self.selections.all::<usize>(cx);
 2928            let buffer_handle = self.buffer.read(cx).read(cx);
 2929
 2930            let mut text = String::new();
 2931            for (index, selection) in selections.iter().enumerate() {
 2932                let text_for_selection = buffer_handle
 2933                    .text_for_range(selection.start..selection.end)
 2934                    .collect::<String>();
 2935
 2936                text.push_str(&text_for_selection);
 2937                if index != selections.len() - 1 {
 2938                    text.push('\n');
 2939                }
 2940            }
 2941
 2942            if !text.is_empty() {
 2943                cx.write_to_primary(ClipboardItem::new_string(text));
 2944            }
 2945        }
 2946
 2947        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2948            self.buffer.update(cx, |buffer, cx| {
 2949                buffer.set_active_selections(
 2950                    &self.selections.disjoint_anchors(),
 2951                    self.selections.line_mode,
 2952                    self.cursor_shape,
 2953                    cx,
 2954                )
 2955            });
 2956        }
 2957        let display_map = self
 2958            .display_map
 2959            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2960        let buffer = &display_map.buffer_snapshot;
 2961        if self.selections.count() == 1 {
 2962            self.add_selections_state = None;
 2963        }
 2964        self.select_next_state = None;
 2965        self.select_prev_state = None;
 2966        self.select_syntax_node_history.try_clear();
 2967        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2968        self.snippet_stack
 2969            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2970        self.take_rename(false, window, cx);
 2971
 2972        let newest_selection = self.selections.newest_anchor();
 2973        let new_cursor_position = newest_selection.head();
 2974        let selection_start = newest_selection.start;
 2975
 2976        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2977            self.push_to_nav_history(
 2978                *old_cursor_position,
 2979                Some(new_cursor_position.to_point(buffer)),
 2980                false,
 2981                effects.nav_history == Some(true),
 2982                cx,
 2983            );
 2984        }
 2985
 2986        if local {
 2987            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2988                if !self.registered_buffers.contains_key(&buffer_id) {
 2989                    if let Some(project) = self.project.as_ref() {
 2990                        project.update(cx, |project, cx| {
 2991                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2992                                return;
 2993                            };
 2994                            self.registered_buffers.insert(
 2995                                buffer_id,
 2996                                project.register_buffer_with_language_servers(&buffer, cx),
 2997                            );
 2998                        })
 2999                    }
 3000                }
 3001            }
 3002
 3003            let mut context_menu = self.context_menu.borrow_mut();
 3004            let completion_menu = match context_menu.as_ref() {
 3005                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3006                Some(CodeContextMenu::CodeActions(_)) => {
 3007                    *context_menu = None;
 3008                    None
 3009                }
 3010                None => None,
 3011            };
 3012            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3013            drop(context_menu);
 3014
 3015            if effects.completions {
 3016                if let Some(completion_position) = completion_position {
 3017                    let start_offset = selection_start.to_offset(buffer);
 3018                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3019                    let continue_showing = if position_matches {
 3020                        if self.snippet_stack.is_empty() {
 3021                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3022                        } else {
 3023                            // Snippet choices can be shown even when the cursor is in whitespace.
 3024                            // Dismissing the menu with actions like backspace is handled by
 3025                            // invalidation regions.
 3026                            true
 3027                        }
 3028                    } else {
 3029                        false
 3030                    };
 3031
 3032                    if continue_showing {
 3033                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3034                    } else {
 3035                        self.hide_context_menu(window, cx);
 3036                    }
 3037                }
 3038            }
 3039
 3040            hide_hover(self, cx);
 3041
 3042            if old_cursor_position.to_display_point(&display_map).row()
 3043                != new_cursor_position.to_display_point(&display_map).row()
 3044            {
 3045                self.available_code_actions.take();
 3046            }
 3047            self.refresh_code_actions(window, cx);
 3048            self.refresh_document_highlights(cx);
 3049            self.refresh_selected_text_highlights(false, window, cx);
 3050            refresh_matching_bracket_highlights(self, window, cx);
 3051            self.update_visible_inline_completion(window, cx);
 3052            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3053            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3054            self.inline_blame_popover.take();
 3055            if self.git_blame_inline_enabled {
 3056                self.start_inline_blame_timer(window, cx);
 3057            }
 3058        }
 3059
 3060        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3061        cx.emit(EditorEvent::SelectionsChanged { local });
 3062
 3063        let selections = &self.selections.disjoint;
 3064        if selections.len() == 1 {
 3065            cx.emit(SearchEvent::ActiveMatchChanged)
 3066        }
 3067        if local {
 3068            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3069                let inmemory_selections = selections
 3070                    .iter()
 3071                    .map(|s| {
 3072                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3073                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3074                    })
 3075                    .collect();
 3076                self.update_restoration_data(cx, |data| {
 3077                    data.selections = inmemory_selections;
 3078                });
 3079
 3080                if WorkspaceSettings::get(None, cx).restore_on_startup
 3081                    != RestoreOnStartupBehavior::None
 3082                {
 3083                    if let Some(workspace_id) =
 3084                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3085                    {
 3086                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3087                        let selections = selections.clone();
 3088                        let background_executor = cx.background_executor().clone();
 3089                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3090                        self.serialize_selections = cx.background_spawn(async move {
 3091                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3092                            let db_selections = selections
 3093                                .iter()
 3094                                .map(|selection| {
 3095                                    (
 3096                                        selection.start.to_offset(&snapshot),
 3097                                        selection.end.to_offset(&snapshot),
 3098                                    )
 3099                                })
 3100                                .collect();
 3101
 3102                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3103                                .await
 3104                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3105                                .log_err();
 3106                        });
 3107                    }
 3108                }
 3109            }
 3110        }
 3111
 3112        cx.notify();
 3113    }
 3114
 3115    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3116        use text::ToOffset as _;
 3117        use text::ToPoint as _;
 3118
 3119        if self.mode.is_minimap()
 3120            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3121        {
 3122            return;
 3123        }
 3124
 3125        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3126            return;
 3127        };
 3128
 3129        let snapshot = singleton.read(cx).snapshot();
 3130        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3131            let display_snapshot = display_map.snapshot(cx);
 3132
 3133            display_snapshot
 3134                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3135                .map(|fold| {
 3136                    fold.range.start.text_anchor.to_point(&snapshot)
 3137                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3138                })
 3139                .collect()
 3140        });
 3141        self.update_restoration_data(cx, |data| {
 3142            data.folds = inmemory_folds;
 3143        });
 3144
 3145        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3146            return;
 3147        };
 3148        let background_executor = cx.background_executor().clone();
 3149        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3150        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3151            display_map
 3152                .snapshot(cx)
 3153                .folds_in_range(0..snapshot.len())
 3154                .map(|fold| {
 3155                    (
 3156                        fold.range.start.text_anchor.to_offset(&snapshot),
 3157                        fold.range.end.text_anchor.to_offset(&snapshot),
 3158                    )
 3159                })
 3160                .collect()
 3161        });
 3162        self.serialize_folds = cx.background_spawn(async move {
 3163            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3164            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3165                .await
 3166                .with_context(|| {
 3167                    format!(
 3168                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3169                    )
 3170                })
 3171                .log_err();
 3172        });
 3173    }
 3174
 3175    pub fn sync_selections(
 3176        &mut self,
 3177        other: Entity<Editor>,
 3178        cx: &mut Context<Self>,
 3179    ) -> gpui::Subscription {
 3180        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3181        self.selections.change_with(cx, |selections| {
 3182            selections.select_anchors(other_selections);
 3183        });
 3184
 3185        let other_subscription =
 3186            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3187                EditorEvent::SelectionsChanged { local: true } => {
 3188                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3189                    if other_selections.is_empty() {
 3190                        return;
 3191                    }
 3192                    this.selections.change_with(cx, |selections| {
 3193                        selections.select_anchors(other_selections);
 3194                    });
 3195                }
 3196                _ => {}
 3197            });
 3198
 3199        let this_subscription =
 3200            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3201                EditorEvent::SelectionsChanged { local: true } => {
 3202                    let these_selections = this.selections.disjoint.to_vec();
 3203                    if these_selections.is_empty() {
 3204                        return;
 3205                    }
 3206                    other.update(cx, |other_editor, cx| {
 3207                        other_editor.selections.change_with(cx, |selections| {
 3208                            selections.select_anchors(these_selections);
 3209                        })
 3210                    });
 3211                }
 3212                _ => {}
 3213            });
 3214
 3215        Subscription::join(other_subscription, this_subscription)
 3216    }
 3217
 3218    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3219    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3220    /// effects of selection change occur at the end of the transaction.
 3221    pub fn change_selections<R>(
 3222        &mut self,
 3223        effects: SelectionEffects,
 3224        window: &mut Window,
 3225        cx: &mut Context<Self>,
 3226        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3227    ) -> R {
 3228        if let Some(state) = &mut self.deferred_selection_effects_state {
 3229            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3230            state.effects.completions = effects.completions;
 3231            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3232            let (changed, result) = self.selections.change_with(cx, change);
 3233            state.changed |= changed;
 3234            return result;
 3235        }
 3236        let mut state = DeferredSelectionEffectsState {
 3237            changed: false,
 3238            effects,
 3239            old_cursor_position: self.selections.newest_anchor().head(),
 3240            history_entry: SelectionHistoryEntry {
 3241                selections: self.selections.disjoint_anchors(),
 3242                select_next_state: self.select_next_state.clone(),
 3243                select_prev_state: self.select_prev_state.clone(),
 3244                add_selections_state: self.add_selections_state.clone(),
 3245            },
 3246        };
 3247        let (changed, result) = self.selections.change_with(cx, change);
 3248        state.changed = state.changed || changed;
 3249        if self.defer_selection_effects {
 3250            self.deferred_selection_effects_state = Some(state);
 3251        } else {
 3252            self.apply_selection_effects(state, window, cx);
 3253        }
 3254        result
 3255    }
 3256
 3257    /// Defers the effects of selection change, so that the effects of multiple calls to
 3258    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3259    /// to selection history and the state of popovers based on selection position aren't
 3260    /// erroneously updated.
 3261    pub fn with_selection_effects_deferred<R>(
 3262        &mut self,
 3263        window: &mut Window,
 3264        cx: &mut Context<Self>,
 3265        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3266    ) -> R {
 3267        let already_deferred = self.defer_selection_effects;
 3268        self.defer_selection_effects = true;
 3269        let result = update(self, window, cx);
 3270        if !already_deferred {
 3271            self.defer_selection_effects = false;
 3272            if let Some(state) = self.deferred_selection_effects_state.take() {
 3273                self.apply_selection_effects(state, window, cx);
 3274            }
 3275        }
 3276        result
 3277    }
 3278
 3279    fn apply_selection_effects(
 3280        &mut self,
 3281        state: DeferredSelectionEffectsState,
 3282        window: &mut Window,
 3283        cx: &mut Context<Self>,
 3284    ) {
 3285        if state.changed {
 3286            self.selection_history.push(state.history_entry);
 3287
 3288            if let Some(autoscroll) = state.effects.scroll {
 3289                self.request_autoscroll(autoscroll, cx);
 3290            }
 3291
 3292            let old_cursor_position = &state.old_cursor_position;
 3293
 3294            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3295
 3296            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3297                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3298            }
 3299        }
 3300    }
 3301
 3302    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3303    where
 3304        I: IntoIterator<Item = (Range<S>, T)>,
 3305        S: ToOffset,
 3306        T: Into<Arc<str>>,
 3307    {
 3308        if self.read_only(cx) {
 3309            return;
 3310        }
 3311
 3312        self.buffer
 3313            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3314    }
 3315
 3316    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3317    where
 3318        I: IntoIterator<Item = (Range<S>, T)>,
 3319        S: ToOffset,
 3320        T: Into<Arc<str>>,
 3321    {
 3322        if self.read_only(cx) {
 3323            return;
 3324        }
 3325
 3326        self.buffer.update(cx, |buffer, cx| {
 3327            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3328        });
 3329    }
 3330
 3331    pub fn edit_with_block_indent<I, S, T>(
 3332        &mut self,
 3333        edits: I,
 3334        original_indent_columns: Vec<Option<u32>>,
 3335        cx: &mut Context<Self>,
 3336    ) where
 3337        I: IntoIterator<Item = (Range<S>, T)>,
 3338        S: ToOffset,
 3339        T: Into<Arc<str>>,
 3340    {
 3341        if self.read_only(cx) {
 3342            return;
 3343        }
 3344
 3345        self.buffer.update(cx, |buffer, cx| {
 3346            buffer.edit(
 3347                edits,
 3348                Some(AutoindentMode::Block {
 3349                    original_indent_columns,
 3350                }),
 3351                cx,
 3352            )
 3353        });
 3354    }
 3355
 3356    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3357        self.hide_context_menu(window, cx);
 3358
 3359        match phase {
 3360            SelectPhase::Begin {
 3361                position,
 3362                add,
 3363                click_count,
 3364            } => self.begin_selection(position, add, click_count, window, cx),
 3365            SelectPhase::BeginColumnar {
 3366                position,
 3367                goal_column,
 3368                reset,
 3369                mode,
 3370            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3371            SelectPhase::Extend {
 3372                position,
 3373                click_count,
 3374            } => self.extend_selection(position, click_count, window, cx),
 3375            SelectPhase::Update {
 3376                position,
 3377                goal_column,
 3378                scroll_delta,
 3379            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3380            SelectPhase::End => self.end_selection(window, cx),
 3381        }
 3382    }
 3383
 3384    fn extend_selection(
 3385        &mut self,
 3386        position: DisplayPoint,
 3387        click_count: usize,
 3388        window: &mut Window,
 3389        cx: &mut Context<Self>,
 3390    ) {
 3391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3392        let tail = self.selections.newest::<usize>(cx).tail();
 3393        self.begin_selection(position, false, click_count, window, cx);
 3394
 3395        let position = position.to_offset(&display_map, Bias::Left);
 3396        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3397
 3398        let mut pending_selection = self
 3399            .selections
 3400            .pending_anchor()
 3401            .expect("extend_selection not called with pending selection");
 3402        if position >= tail {
 3403            pending_selection.start = tail_anchor;
 3404        } else {
 3405            pending_selection.end = tail_anchor;
 3406            pending_selection.reversed = true;
 3407        }
 3408
 3409        let mut pending_mode = self.selections.pending_mode().unwrap();
 3410        match &mut pending_mode {
 3411            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3412            _ => {}
 3413        }
 3414
 3415        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3416            SelectionEffects::scroll(Autoscroll::fit())
 3417        } else {
 3418            SelectionEffects::no_scroll()
 3419        };
 3420
 3421        self.change_selections(effects, window, cx, |s| {
 3422            s.set_pending(pending_selection, pending_mode)
 3423        });
 3424    }
 3425
 3426    fn begin_selection(
 3427        &mut self,
 3428        position: DisplayPoint,
 3429        add: bool,
 3430        click_count: usize,
 3431        window: &mut Window,
 3432        cx: &mut Context<Self>,
 3433    ) {
 3434        if !self.focus_handle.is_focused(window) {
 3435            self.last_focused_descendant = None;
 3436            window.focus(&self.focus_handle);
 3437        }
 3438
 3439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3440        let buffer = &display_map.buffer_snapshot;
 3441        let position = display_map.clip_point(position, Bias::Left);
 3442
 3443        let start;
 3444        let end;
 3445        let mode;
 3446        let mut auto_scroll;
 3447        match click_count {
 3448            1 => {
 3449                start = buffer.anchor_before(position.to_point(&display_map));
 3450                end = start;
 3451                mode = SelectMode::Character;
 3452                auto_scroll = true;
 3453            }
 3454            2 => {
 3455                let position = display_map
 3456                    .clip_point(position, Bias::Left)
 3457                    .to_offset(&display_map, Bias::Left);
 3458                let (range, _) = buffer.surrounding_word(position, false);
 3459                start = buffer.anchor_before(range.start);
 3460                end = buffer.anchor_before(range.end);
 3461                mode = SelectMode::Word(start..end);
 3462                auto_scroll = true;
 3463            }
 3464            3 => {
 3465                let position = display_map
 3466                    .clip_point(position, Bias::Left)
 3467                    .to_point(&display_map);
 3468                let line_start = display_map.prev_line_boundary(position).0;
 3469                let next_line_start = buffer.clip_point(
 3470                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3471                    Bias::Left,
 3472                );
 3473                start = buffer.anchor_before(line_start);
 3474                end = buffer.anchor_before(next_line_start);
 3475                mode = SelectMode::Line(start..end);
 3476                auto_scroll = true;
 3477            }
 3478            _ => {
 3479                start = buffer.anchor_before(0);
 3480                end = buffer.anchor_before(buffer.len());
 3481                mode = SelectMode::All;
 3482                auto_scroll = false;
 3483            }
 3484        }
 3485        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3486
 3487        let point_to_delete: Option<usize> = {
 3488            let selected_points: Vec<Selection<Point>> =
 3489                self.selections.disjoint_in_range(start..end, cx);
 3490
 3491            if !add || click_count > 1 {
 3492                None
 3493            } else if !selected_points.is_empty() {
 3494                Some(selected_points[0].id)
 3495            } else {
 3496                let clicked_point_already_selected =
 3497                    self.selections.disjoint.iter().find(|selection| {
 3498                        selection.start.to_point(buffer) == start.to_point(buffer)
 3499                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3500                    });
 3501
 3502                clicked_point_already_selected.map(|selection| selection.id)
 3503            }
 3504        };
 3505
 3506        let selections_count = self.selections.count();
 3507        let effects = if auto_scroll {
 3508            SelectionEffects::default()
 3509        } else {
 3510            SelectionEffects::no_scroll()
 3511        };
 3512
 3513        self.change_selections(effects, window, cx, |s| {
 3514            if let Some(point_to_delete) = point_to_delete {
 3515                s.delete(point_to_delete);
 3516
 3517                if selections_count == 1 {
 3518                    s.set_pending_anchor_range(start..end, mode);
 3519                }
 3520            } else {
 3521                if !add {
 3522                    s.clear_disjoint();
 3523                }
 3524
 3525                s.set_pending_anchor_range(start..end, mode);
 3526            }
 3527        });
 3528    }
 3529
 3530    fn begin_columnar_selection(
 3531        &mut self,
 3532        position: DisplayPoint,
 3533        goal_column: u32,
 3534        reset: bool,
 3535        mode: ColumnarMode,
 3536        window: &mut Window,
 3537        cx: &mut Context<Self>,
 3538    ) {
 3539        if !self.focus_handle.is_focused(window) {
 3540            self.last_focused_descendant = None;
 3541            window.focus(&self.focus_handle);
 3542        }
 3543
 3544        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3545
 3546        if reset {
 3547            let pointer_position = display_map
 3548                .buffer_snapshot
 3549                .anchor_before(position.to_point(&display_map));
 3550
 3551            self.change_selections(
 3552                SelectionEffects::scroll(Autoscroll::newest()),
 3553                window,
 3554                cx,
 3555                |s| {
 3556                    s.clear_disjoint();
 3557                    s.set_pending_anchor_range(
 3558                        pointer_position..pointer_position,
 3559                        SelectMode::Character,
 3560                    );
 3561                },
 3562            );
 3563        };
 3564
 3565        let tail = self.selections.newest::<Point>(cx).tail();
 3566        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3567        self.columnar_selection_state = match mode {
 3568            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3569                selection_tail: selection_anchor,
 3570                display_point: if reset {
 3571                    if position.column() != goal_column {
 3572                        Some(DisplayPoint::new(position.row(), goal_column))
 3573                    } else {
 3574                        None
 3575                    }
 3576                } else {
 3577                    None
 3578                },
 3579            }),
 3580            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3581                selection_tail: selection_anchor,
 3582            }),
 3583        };
 3584
 3585        if !reset {
 3586            self.select_columns(position, goal_column, &display_map, window, cx);
 3587        }
 3588    }
 3589
 3590    fn update_selection(
 3591        &mut self,
 3592        position: DisplayPoint,
 3593        goal_column: u32,
 3594        scroll_delta: gpui::Point<f32>,
 3595        window: &mut Window,
 3596        cx: &mut Context<Self>,
 3597    ) {
 3598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3599
 3600        if self.columnar_selection_state.is_some() {
 3601            self.select_columns(position, goal_column, &display_map, window, cx);
 3602        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3603            let buffer = &display_map.buffer_snapshot;
 3604            let head;
 3605            let tail;
 3606            let mode = self.selections.pending_mode().unwrap();
 3607            match &mode {
 3608                SelectMode::Character => {
 3609                    head = position.to_point(&display_map);
 3610                    tail = pending.tail().to_point(buffer);
 3611                }
 3612                SelectMode::Word(original_range) => {
 3613                    let offset = display_map
 3614                        .clip_point(position, Bias::Left)
 3615                        .to_offset(&display_map, Bias::Left);
 3616                    let original_range = original_range.to_offset(buffer);
 3617
 3618                    let head_offset = if buffer.is_inside_word(offset, false)
 3619                        || original_range.contains(&offset)
 3620                    {
 3621                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3622                        if word_range.start < original_range.start {
 3623                            word_range.start
 3624                        } else {
 3625                            word_range.end
 3626                        }
 3627                    } else {
 3628                        offset
 3629                    };
 3630
 3631                    head = head_offset.to_point(buffer);
 3632                    if head_offset <= original_range.start {
 3633                        tail = original_range.end.to_point(buffer);
 3634                    } else {
 3635                        tail = original_range.start.to_point(buffer);
 3636                    }
 3637                }
 3638                SelectMode::Line(original_range) => {
 3639                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3640
 3641                    let position = display_map
 3642                        .clip_point(position, Bias::Left)
 3643                        .to_point(&display_map);
 3644                    let line_start = display_map.prev_line_boundary(position).0;
 3645                    let next_line_start = buffer.clip_point(
 3646                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3647                        Bias::Left,
 3648                    );
 3649
 3650                    if line_start < original_range.start {
 3651                        head = line_start
 3652                    } else {
 3653                        head = next_line_start
 3654                    }
 3655
 3656                    if head <= original_range.start {
 3657                        tail = original_range.end;
 3658                    } else {
 3659                        tail = original_range.start;
 3660                    }
 3661                }
 3662                SelectMode::All => {
 3663                    return;
 3664                }
 3665            };
 3666
 3667            if head < tail {
 3668                pending.start = buffer.anchor_before(head);
 3669                pending.end = buffer.anchor_before(tail);
 3670                pending.reversed = true;
 3671            } else {
 3672                pending.start = buffer.anchor_before(tail);
 3673                pending.end = buffer.anchor_before(head);
 3674                pending.reversed = false;
 3675            }
 3676
 3677            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3678                s.set_pending(pending, mode);
 3679            });
 3680        } else {
 3681            log::error!("update_selection dispatched with no pending selection");
 3682            return;
 3683        }
 3684
 3685        self.apply_scroll_delta(scroll_delta, window, cx);
 3686        cx.notify();
 3687    }
 3688
 3689    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3690        self.columnar_selection_state.take();
 3691        if self.selections.pending_anchor().is_some() {
 3692            let selections = self.selections.all::<usize>(cx);
 3693            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3694                s.select(selections);
 3695                s.clear_pending();
 3696            });
 3697        }
 3698    }
 3699
 3700    fn select_columns(
 3701        &mut self,
 3702        head: DisplayPoint,
 3703        goal_column: u32,
 3704        display_map: &DisplaySnapshot,
 3705        window: &mut Window,
 3706        cx: &mut Context<Self>,
 3707    ) {
 3708        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3709            return;
 3710        };
 3711
 3712        let tail = match columnar_state {
 3713            ColumnarSelectionState::FromMouse {
 3714                selection_tail,
 3715                display_point,
 3716            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3717            ColumnarSelectionState::FromSelection { selection_tail } => {
 3718                selection_tail.to_display_point(&display_map)
 3719            }
 3720        };
 3721
 3722        let start_row = cmp::min(tail.row(), head.row());
 3723        let end_row = cmp::max(tail.row(), head.row());
 3724        let start_column = cmp::min(tail.column(), goal_column);
 3725        let end_column = cmp::max(tail.column(), goal_column);
 3726        let reversed = start_column < tail.column();
 3727
 3728        let selection_ranges = (start_row.0..=end_row.0)
 3729            .map(DisplayRow)
 3730            .filter_map(|row| {
 3731                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3732                    || start_column <= display_map.line_len(row))
 3733                    && !display_map.is_block_line(row)
 3734                {
 3735                    let start = display_map
 3736                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3737                        .to_point(display_map);
 3738                    let end = display_map
 3739                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3740                        .to_point(display_map);
 3741                    if reversed {
 3742                        Some(end..start)
 3743                    } else {
 3744                        Some(start..end)
 3745                    }
 3746                } else {
 3747                    None
 3748                }
 3749            })
 3750            .collect::<Vec<_>>();
 3751
 3752        let ranges = match columnar_state {
 3753            ColumnarSelectionState::FromMouse { .. } => {
 3754                let mut non_empty_ranges = selection_ranges
 3755                    .iter()
 3756                    .filter(|selection_range| selection_range.start != selection_range.end)
 3757                    .peekable();
 3758                if non_empty_ranges.peek().is_some() {
 3759                    non_empty_ranges.cloned().collect()
 3760                } else {
 3761                    selection_ranges
 3762                }
 3763            }
 3764            _ => selection_ranges,
 3765        };
 3766
 3767        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3768            s.select_ranges(ranges);
 3769        });
 3770        cx.notify();
 3771    }
 3772
 3773    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3774        self.selections
 3775            .all_adjusted(cx)
 3776            .iter()
 3777            .any(|selection| !selection.is_empty())
 3778    }
 3779
 3780    pub fn has_pending_nonempty_selection(&self) -> bool {
 3781        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3782            Some(Selection { start, end, .. }) => start != end,
 3783            None => false,
 3784        };
 3785
 3786        pending_nonempty_selection
 3787            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3788    }
 3789
 3790    pub fn has_pending_selection(&self) -> bool {
 3791        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3792    }
 3793
 3794    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3795        self.selection_mark_mode = false;
 3796        self.selection_drag_state = SelectionDragState::None;
 3797
 3798        if self.clear_expanded_diff_hunks(cx) {
 3799            cx.notify();
 3800            return;
 3801        }
 3802        if self.dismiss_menus_and_popups(true, window, cx) {
 3803            return;
 3804        }
 3805
 3806        if self.mode.is_full()
 3807            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3808        {
 3809            return;
 3810        }
 3811
 3812        cx.propagate();
 3813    }
 3814
 3815    pub fn dismiss_menus_and_popups(
 3816        &mut self,
 3817        is_user_requested: bool,
 3818        window: &mut Window,
 3819        cx: &mut Context<Self>,
 3820    ) -> bool {
 3821        if self.take_rename(false, window, cx).is_some() {
 3822            return true;
 3823        }
 3824
 3825        if hide_hover(self, cx) {
 3826            return true;
 3827        }
 3828
 3829        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3830            return true;
 3831        }
 3832
 3833        if self.hide_context_menu(window, cx).is_some() {
 3834            return true;
 3835        }
 3836
 3837        if self.mouse_context_menu.take().is_some() {
 3838            return true;
 3839        }
 3840
 3841        if is_user_requested && self.discard_inline_completion(true, cx) {
 3842            return true;
 3843        }
 3844
 3845        if self.snippet_stack.pop().is_some() {
 3846            return true;
 3847        }
 3848
 3849        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3850            self.dismiss_diagnostics(cx);
 3851            return true;
 3852        }
 3853
 3854        false
 3855    }
 3856
 3857    fn linked_editing_ranges_for(
 3858        &self,
 3859        selection: Range<text::Anchor>,
 3860        cx: &App,
 3861    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3862        if self.linked_edit_ranges.is_empty() {
 3863            return None;
 3864        }
 3865        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3866            selection.end.buffer_id.and_then(|end_buffer_id| {
 3867                if selection.start.buffer_id != Some(end_buffer_id) {
 3868                    return None;
 3869                }
 3870                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3871                let snapshot = buffer.read(cx).snapshot();
 3872                self.linked_edit_ranges
 3873                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3874                    .map(|ranges| (ranges, snapshot, buffer))
 3875            })?;
 3876        use text::ToOffset as TO;
 3877        // find offset from the start of current range to current cursor position
 3878        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3879
 3880        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3881        let start_difference = start_offset - start_byte_offset;
 3882        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3883        let end_difference = end_offset - start_byte_offset;
 3884        // Current range has associated linked ranges.
 3885        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3886        for range in linked_ranges.iter() {
 3887            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3888            let end_offset = start_offset + end_difference;
 3889            let start_offset = start_offset + start_difference;
 3890            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3891                continue;
 3892            }
 3893            if self.selections.disjoint_anchor_ranges().any(|s| {
 3894                if s.start.buffer_id != selection.start.buffer_id
 3895                    || s.end.buffer_id != selection.end.buffer_id
 3896                {
 3897                    return false;
 3898                }
 3899                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3900                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3901            }) {
 3902                continue;
 3903            }
 3904            let start = buffer_snapshot.anchor_after(start_offset);
 3905            let end = buffer_snapshot.anchor_after(end_offset);
 3906            linked_edits
 3907                .entry(buffer.clone())
 3908                .or_default()
 3909                .push(start..end);
 3910        }
 3911        Some(linked_edits)
 3912    }
 3913
 3914    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3915        let text: Arc<str> = text.into();
 3916
 3917        if self.read_only(cx) {
 3918            return;
 3919        }
 3920
 3921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3922
 3923        let selections = self.selections.all_adjusted(cx);
 3924        let mut bracket_inserted = false;
 3925        let mut edits = Vec::new();
 3926        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3927        let mut new_selections = Vec::with_capacity(selections.len());
 3928        let mut new_autoclose_regions = Vec::new();
 3929        let snapshot = self.buffer.read(cx).read(cx);
 3930        let mut clear_linked_edit_ranges = false;
 3931
 3932        for (selection, autoclose_region) in
 3933            self.selections_with_autoclose_regions(selections, &snapshot)
 3934        {
 3935            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3936                // Determine if the inserted text matches the opening or closing
 3937                // bracket of any of this language's bracket pairs.
 3938                let mut bracket_pair = None;
 3939                let mut is_bracket_pair_start = false;
 3940                let mut is_bracket_pair_end = false;
 3941                if !text.is_empty() {
 3942                    let mut bracket_pair_matching_end = None;
 3943                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3944                    //  and they are removing the character that triggered IME popup.
 3945                    for (pair, enabled) in scope.brackets() {
 3946                        if !pair.close && !pair.surround {
 3947                            continue;
 3948                        }
 3949
 3950                        if enabled && pair.start.ends_with(text.as_ref()) {
 3951                            let prefix_len = pair.start.len() - text.len();
 3952                            let preceding_text_matches_prefix = prefix_len == 0
 3953                                || (selection.start.column >= (prefix_len as u32)
 3954                                    && snapshot.contains_str_at(
 3955                                        Point::new(
 3956                                            selection.start.row,
 3957                                            selection.start.column - (prefix_len as u32),
 3958                                        ),
 3959                                        &pair.start[..prefix_len],
 3960                                    ));
 3961                            if preceding_text_matches_prefix {
 3962                                bracket_pair = Some(pair.clone());
 3963                                is_bracket_pair_start = true;
 3964                                break;
 3965                            }
 3966                        }
 3967                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3968                        {
 3969                            // take first bracket pair matching end, but don't break in case a later bracket
 3970                            // pair matches start
 3971                            bracket_pair_matching_end = Some(pair.clone());
 3972                        }
 3973                    }
 3974                    if let Some(end) = bracket_pair_matching_end
 3975                        && bracket_pair.is_none()
 3976                    {
 3977                        bracket_pair = Some(end);
 3978                        is_bracket_pair_end = true;
 3979                    }
 3980                }
 3981
 3982                if let Some(bracket_pair) = bracket_pair {
 3983                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3984                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3985                    let auto_surround =
 3986                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3987                    if selection.is_empty() {
 3988                        if is_bracket_pair_start {
 3989                            // If the inserted text is a suffix of an opening bracket and the
 3990                            // selection is preceded by the rest of the opening bracket, then
 3991                            // insert the closing bracket.
 3992                            let following_text_allows_autoclose = snapshot
 3993                                .chars_at(selection.start)
 3994                                .next()
 3995                                .map_or(true, |c| scope.should_autoclose_before(c));
 3996
 3997                            let preceding_text_allows_autoclose = selection.start.column == 0
 3998                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3999                                    true,
 4000                                    |c| {
 4001                                        bracket_pair.start != bracket_pair.end
 4002                                            || !snapshot
 4003                                                .char_classifier_at(selection.start)
 4004                                                .is_word(c)
 4005                                    },
 4006                                );
 4007
 4008                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4009                                && bracket_pair.start.len() == 1
 4010                            {
 4011                                let target = bracket_pair.start.chars().next().unwrap();
 4012                                let current_line_count = snapshot
 4013                                    .reversed_chars_at(selection.start)
 4014                                    .take_while(|&c| c != '\n')
 4015                                    .filter(|&c| c == target)
 4016                                    .count();
 4017                                current_line_count % 2 == 1
 4018                            } else {
 4019                                false
 4020                            };
 4021
 4022                            if autoclose
 4023                                && bracket_pair.close
 4024                                && following_text_allows_autoclose
 4025                                && preceding_text_allows_autoclose
 4026                                && !is_closing_quote
 4027                            {
 4028                                let anchor = snapshot.anchor_before(selection.end);
 4029                                new_selections.push((selection.map(|_| anchor), text.len()));
 4030                                new_autoclose_regions.push((
 4031                                    anchor,
 4032                                    text.len(),
 4033                                    selection.id,
 4034                                    bracket_pair.clone(),
 4035                                ));
 4036                                edits.push((
 4037                                    selection.range(),
 4038                                    format!("{}{}", text, bracket_pair.end).into(),
 4039                                ));
 4040                                bracket_inserted = true;
 4041                                continue;
 4042                            }
 4043                        }
 4044
 4045                        if let Some(region) = autoclose_region {
 4046                            // If the selection is followed by an auto-inserted closing bracket,
 4047                            // then don't insert that closing bracket again; just move the selection
 4048                            // past the closing bracket.
 4049                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4050                                && text.as_ref() == region.pair.end.as_str();
 4051                            if should_skip {
 4052                                let anchor = snapshot.anchor_after(selection.end);
 4053                                new_selections
 4054                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4055                                continue;
 4056                            }
 4057                        }
 4058
 4059                        let always_treat_brackets_as_autoclosed = snapshot
 4060                            .language_settings_at(selection.start, cx)
 4061                            .always_treat_brackets_as_autoclosed;
 4062                        if always_treat_brackets_as_autoclosed
 4063                            && is_bracket_pair_end
 4064                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4065                        {
 4066                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4067                            // and the inserted text is a closing bracket and the selection is followed
 4068                            // by the closing bracket then move the selection past the closing bracket.
 4069                            let anchor = snapshot.anchor_after(selection.end);
 4070                            new_selections.push((selection.map(|_| anchor), text.len()));
 4071                            continue;
 4072                        }
 4073                    }
 4074                    // If an opening bracket is 1 character long and is typed while
 4075                    // text is selected, then surround that text with the bracket pair.
 4076                    else if auto_surround
 4077                        && bracket_pair.surround
 4078                        && is_bracket_pair_start
 4079                        && bracket_pair.start.chars().count() == 1
 4080                    {
 4081                        edits.push((selection.start..selection.start, text.clone()));
 4082                        edits.push((
 4083                            selection.end..selection.end,
 4084                            bracket_pair.end.as_str().into(),
 4085                        ));
 4086                        bracket_inserted = true;
 4087                        new_selections.push((
 4088                            Selection {
 4089                                id: selection.id,
 4090                                start: snapshot.anchor_after(selection.start),
 4091                                end: snapshot.anchor_before(selection.end),
 4092                                reversed: selection.reversed,
 4093                                goal: selection.goal,
 4094                            },
 4095                            0,
 4096                        ));
 4097                        continue;
 4098                    }
 4099                }
 4100            }
 4101
 4102            if self.auto_replace_emoji_shortcode
 4103                && selection.is_empty()
 4104                && text.as_ref().ends_with(':')
 4105            {
 4106                if let Some(possible_emoji_short_code) =
 4107                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4108                {
 4109                    if !possible_emoji_short_code.is_empty() {
 4110                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4111                            let emoji_shortcode_start = Point::new(
 4112                                selection.start.row,
 4113                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4114                            );
 4115
 4116                            // Remove shortcode from buffer
 4117                            edits.push((
 4118                                emoji_shortcode_start..selection.start,
 4119                                "".to_string().into(),
 4120                            ));
 4121                            new_selections.push((
 4122                                Selection {
 4123                                    id: selection.id,
 4124                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4125                                    end: snapshot.anchor_before(selection.start),
 4126                                    reversed: selection.reversed,
 4127                                    goal: selection.goal,
 4128                                },
 4129                                0,
 4130                            ));
 4131
 4132                            // Insert emoji
 4133                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4134                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4135                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4136
 4137                            continue;
 4138                        }
 4139                    }
 4140                }
 4141            }
 4142
 4143            // If not handling any auto-close operation, then just replace the selected
 4144            // text with the given input and move the selection to the end of the
 4145            // newly inserted text.
 4146            let anchor = snapshot.anchor_after(selection.end);
 4147            if !self.linked_edit_ranges.is_empty() {
 4148                let start_anchor = snapshot.anchor_before(selection.start);
 4149
 4150                let is_word_char = text.chars().next().map_or(true, |char| {
 4151                    let classifier = snapshot
 4152                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4153                        .ignore_punctuation(true);
 4154                    classifier.is_word(char)
 4155                });
 4156
 4157                if is_word_char {
 4158                    if let Some(ranges) = self
 4159                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4160                    {
 4161                        for (buffer, edits) in ranges {
 4162                            linked_edits
 4163                                .entry(buffer.clone())
 4164                                .or_default()
 4165                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4166                        }
 4167                    }
 4168                } else {
 4169                    clear_linked_edit_ranges = true;
 4170                }
 4171            }
 4172
 4173            new_selections.push((selection.map(|_| anchor), 0));
 4174            edits.push((selection.start..selection.end, text.clone()));
 4175        }
 4176
 4177        drop(snapshot);
 4178
 4179        self.transact(window, cx, |this, window, cx| {
 4180            if clear_linked_edit_ranges {
 4181                this.linked_edit_ranges.clear();
 4182            }
 4183            let initial_buffer_versions =
 4184                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4185
 4186            this.buffer.update(cx, |buffer, cx| {
 4187                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4188            });
 4189            for (buffer, edits) in linked_edits {
 4190                buffer.update(cx, |buffer, cx| {
 4191                    let snapshot = buffer.snapshot();
 4192                    let edits = edits
 4193                        .into_iter()
 4194                        .map(|(range, text)| {
 4195                            use text::ToPoint as TP;
 4196                            let end_point = TP::to_point(&range.end, &snapshot);
 4197                            let start_point = TP::to_point(&range.start, &snapshot);
 4198                            (start_point..end_point, text)
 4199                        })
 4200                        .sorted_by_key(|(range, _)| range.start);
 4201                    buffer.edit(edits, None, cx);
 4202                })
 4203            }
 4204            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4205            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4206            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4207            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4208                .zip(new_selection_deltas)
 4209                .map(|(selection, delta)| Selection {
 4210                    id: selection.id,
 4211                    start: selection.start + delta,
 4212                    end: selection.end + delta,
 4213                    reversed: selection.reversed,
 4214                    goal: SelectionGoal::None,
 4215                })
 4216                .collect::<Vec<_>>();
 4217
 4218            let mut i = 0;
 4219            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4220                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4221                let start = map.buffer_snapshot.anchor_before(position);
 4222                let end = map.buffer_snapshot.anchor_after(position);
 4223                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4224                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4225                        Ordering::Less => i += 1,
 4226                        Ordering::Greater => break,
 4227                        Ordering::Equal => {
 4228                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4229                                Ordering::Less => i += 1,
 4230                                Ordering::Equal => break,
 4231                                Ordering::Greater => break,
 4232                            }
 4233                        }
 4234                    }
 4235                }
 4236                this.autoclose_regions.insert(
 4237                    i,
 4238                    AutocloseRegion {
 4239                        selection_id,
 4240                        range: start..end,
 4241                        pair,
 4242                    },
 4243                );
 4244            }
 4245
 4246            let had_active_inline_completion = this.has_active_inline_completion();
 4247            this.change_selections(
 4248                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4249                window,
 4250                cx,
 4251                |s| s.select(new_selections),
 4252            );
 4253
 4254            if !bracket_inserted {
 4255                if let Some(on_type_format_task) =
 4256                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4257                {
 4258                    on_type_format_task.detach_and_log_err(cx);
 4259                }
 4260            }
 4261
 4262            let editor_settings = EditorSettings::get_global(cx);
 4263            if bracket_inserted
 4264                && (editor_settings.auto_signature_help
 4265                    || editor_settings.show_signature_help_after_edits)
 4266            {
 4267                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4268            }
 4269
 4270            let trigger_in_words =
 4271                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4272            if this.hard_wrap.is_some() {
 4273                let latest: Range<Point> = this.selections.newest(cx).range();
 4274                if latest.is_empty()
 4275                    && this
 4276                        .buffer()
 4277                        .read(cx)
 4278                        .snapshot(cx)
 4279                        .line_len(MultiBufferRow(latest.start.row))
 4280                        == latest.start.column
 4281                {
 4282                    this.rewrap_impl(
 4283                        RewrapOptions {
 4284                            override_language_settings: true,
 4285                            preserve_existing_whitespace: true,
 4286                        },
 4287                        cx,
 4288                    )
 4289                }
 4290            }
 4291            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4292            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4293            this.refresh_inline_completion(true, false, window, cx);
 4294            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4295        });
 4296    }
 4297
 4298    fn find_possible_emoji_shortcode_at_position(
 4299        snapshot: &MultiBufferSnapshot,
 4300        position: Point,
 4301    ) -> Option<String> {
 4302        let mut chars = Vec::new();
 4303        let mut found_colon = false;
 4304        for char in snapshot.reversed_chars_at(position).take(100) {
 4305            // Found a possible emoji shortcode in the middle of the buffer
 4306            if found_colon {
 4307                if char.is_whitespace() {
 4308                    chars.reverse();
 4309                    return Some(chars.iter().collect());
 4310                }
 4311                // If the previous character is not a whitespace, we are in the middle of a word
 4312                // and we only want to complete the shortcode if the word is made up of other emojis
 4313                let mut containing_word = String::new();
 4314                for ch in snapshot
 4315                    .reversed_chars_at(position)
 4316                    .skip(chars.len() + 1)
 4317                    .take(100)
 4318                {
 4319                    if ch.is_whitespace() {
 4320                        break;
 4321                    }
 4322                    containing_word.push(ch);
 4323                }
 4324                let containing_word = containing_word.chars().rev().collect::<String>();
 4325                if util::word_consists_of_emojis(containing_word.as_str()) {
 4326                    chars.reverse();
 4327                    return Some(chars.iter().collect());
 4328                }
 4329            }
 4330
 4331            if char.is_whitespace() || !char.is_ascii() {
 4332                return None;
 4333            }
 4334            if char == ':' {
 4335                found_colon = true;
 4336            } else {
 4337                chars.push(char);
 4338            }
 4339        }
 4340        // Found a possible emoji shortcode at the beginning of the buffer
 4341        chars.reverse();
 4342        Some(chars.iter().collect())
 4343    }
 4344
 4345    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4347        self.transact(window, cx, |this, window, cx| {
 4348            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4349                let selections = this.selections.all::<usize>(cx);
 4350                let multi_buffer = this.buffer.read(cx);
 4351                let buffer = multi_buffer.snapshot(cx);
 4352                selections
 4353                    .iter()
 4354                    .map(|selection| {
 4355                        let start_point = selection.start.to_point(&buffer);
 4356                        let mut existing_indent =
 4357                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4358                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4359                        let start = selection.start;
 4360                        let end = selection.end;
 4361                        let selection_is_empty = start == end;
 4362                        let language_scope = buffer.language_scope_at(start);
 4363                        let (
 4364                            comment_delimiter,
 4365                            doc_delimiter,
 4366                            insert_extra_newline,
 4367                            indent_on_newline,
 4368                            indent_on_extra_newline,
 4369                        ) = if let Some(language) = &language_scope {
 4370                            let mut insert_extra_newline =
 4371                                insert_extra_newline_brackets(&buffer, start..end, language)
 4372                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4373
 4374                            // Comment extension on newline is allowed only for cursor selections
 4375                            let comment_delimiter = maybe!({
 4376                                if !selection_is_empty {
 4377                                    return None;
 4378                                }
 4379
 4380                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4381                                    return None;
 4382                                }
 4383
 4384                                let delimiters = language.line_comment_prefixes();
 4385                                let max_len_of_delimiter =
 4386                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4387                                let (snapshot, range) =
 4388                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4389
 4390                                let num_of_whitespaces = snapshot
 4391                                    .chars_for_range(range.clone())
 4392                                    .take_while(|c| c.is_whitespace())
 4393                                    .count();
 4394                                let comment_candidate = snapshot
 4395                                    .chars_for_range(range.clone())
 4396                                    .skip(num_of_whitespaces)
 4397                                    .take(max_len_of_delimiter)
 4398                                    .collect::<String>();
 4399                                let (delimiter, trimmed_len) = delimiters
 4400                                    .iter()
 4401                                    .filter_map(|delimiter| {
 4402                                        let prefix = delimiter.trim_end();
 4403                                        if comment_candidate.starts_with(prefix) {
 4404                                            Some((delimiter, prefix.len()))
 4405                                        } else {
 4406                                            None
 4407                                        }
 4408                                    })
 4409                                    .max_by_key(|(_, len)| *len)?;
 4410
 4411                                if let Some(BlockCommentConfig {
 4412                                    start: block_start, ..
 4413                                }) = language.block_comment()
 4414                                {
 4415                                    let block_start_trimmed = block_start.trim_end();
 4416                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4417                                        let line_content = snapshot
 4418                                            .chars_for_range(range)
 4419                                            .skip(num_of_whitespaces)
 4420                                            .take(block_start_trimmed.len())
 4421                                            .collect::<String>();
 4422
 4423                                        if line_content.starts_with(block_start_trimmed) {
 4424                                            return None;
 4425                                        }
 4426                                    }
 4427                                }
 4428
 4429                                let cursor_is_placed_after_comment_marker =
 4430                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4431                                if cursor_is_placed_after_comment_marker {
 4432                                    Some(delimiter.clone())
 4433                                } else {
 4434                                    None
 4435                                }
 4436                            });
 4437
 4438                            let mut indent_on_newline = IndentSize::spaces(0);
 4439                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4440
 4441                            let doc_delimiter = maybe!({
 4442                                if !selection_is_empty {
 4443                                    return None;
 4444                                }
 4445
 4446                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4447                                    return None;
 4448                                }
 4449
 4450                                let BlockCommentConfig {
 4451                                    start: start_tag,
 4452                                    end: end_tag,
 4453                                    prefix: delimiter,
 4454                                    tab_size: len,
 4455                                } = language.documentation_comment()?;
 4456                                let is_within_block_comment = buffer
 4457                                    .language_scope_at(start_point)
 4458                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4459                                if !is_within_block_comment {
 4460                                    return None;
 4461                                }
 4462
 4463                                let (snapshot, range) =
 4464                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4465
 4466                                let num_of_whitespaces = snapshot
 4467                                    .chars_for_range(range.clone())
 4468                                    .take_while(|c| c.is_whitespace())
 4469                                    .count();
 4470
 4471                                // 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.
 4472                                let column = start_point.column;
 4473                                let cursor_is_after_start_tag = {
 4474                                    let start_tag_len = start_tag.len();
 4475                                    let start_tag_line = snapshot
 4476                                        .chars_for_range(range.clone())
 4477                                        .skip(num_of_whitespaces)
 4478                                        .take(start_tag_len)
 4479                                        .collect::<String>();
 4480                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4481                                        num_of_whitespaces + start_tag_len <= column as usize
 4482                                    } else {
 4483                                        false
 4484                                    }
 4485                                };
 4486
 4487                                let cursor_is_after_delimiter = {
 4488                                    let delimiter_trim = delimiter.trim_end();
 4489                                    let delimiter_line = snapshot
 4490                                        .chars_for_range(range.clone())
 4491                                        .skip(num_of_whitespaces)
 4492                                        .take(delimiter_trim.len())
 4493                                        .collect::<String>();
 4494                                    if delimiter_line.starts_with(delimiter_trim) {
 4495                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4496                                    } else {
 4497                                        false
 4498                                    }
 4499                                };
 4500
 4501                                let cursor_is_before_end_tag_if_exists = {
 4502                                    let mut char_position = 0u32;
 4503                                    let mut end_tag_offset = None;
 4504
 4505                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4506                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4507                                            let chars_before_match =
 4508                                                chunk[..byte_pos].chars().count() as u32;
 4509                                            end_tag_offset =
 4510                                                Some(char_position + chars_before_match);
 4511                                            break 'outer;
 4512                                        }
 4513                                        char_position += chunk.chars().count() as u32;
 4514                                    }
 4515
 4516                                    if let Some(end_tag_offset) = end_tag_offset {
 4517                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4518                                        if cursor_is_after_start_tag {
 4519                                            if cursor_is_before_end_tag {
 4520                                                insert_extra_newline = true;
 4521                                            }
 4522                                            let cursor_is_at_start_of_end_tag =
 4523                                                column == end_tag_offset;
 4524                                            if cursor_is_at_start_of_end_tag {
 4525                                                indent_on_extra_newline.len = *len;
 4526                                            }
 4527                                        }
 4528                                        cursor_is_before_end_tag
 4529                                    } else {
 4530                                        true
 4531                                    }
 4532                                };
 4533
 4534                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4535                                    && cursor_is_before_end_tag_if_exists
 4536                                {
 4537                                    if cursor_is_after_start_tag {
 4538                                        indent_on_newline.len = *len;
 4539                                    }
 4540                                    Some(delimiter.clone())
 4541                                } else {
 4542                                    None
 4543                                }
 4544                            });
 4545
 4546                            (
 4547                                comment_delimiter,
 4548                                doc_delimiter,
 4549                                insert_extra_newline,
 4550                                indent_on_newline,
 4551                                indent_on_extra_newline,
 4552                            )
 4553                        } else {
 4554                            (
 4555                                None,
 4556                                None,
 4557                                false,
 4558                                IndentSize::default(),
 4559                                IndentSize::default(),
 4560                            )
 4561                        };
 4562
 4563                        let prevent_auto_indent = doc_delimiter.is_some();
 4564                        let delimiter = comment_delimiter.or(doc_delimiter);
 4565
 4566                        let capacity_for_delimiter =
 4567                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4568                        let mut new_text = String::with_capacity(
 4569                            1 + capacity_for_delimiter
 4570                                + existing_indent.len as usize
 4571                                + indent_on_newline.len as usize
 4572                                + indent_on_extra_newline.len as usize,
 4573                        );
 4574                        new_text.push('\n');
 4575                        new_text.extend(existing_indent.chars());
 4576                        new_text.extend(indent_on_newline.chars());
 4577
 4578                        if let Some(delimiter) = &delimiter {
 4579                            new_text.push_str(delimiter);
 4580                        }
 4581
 4582                        if insert_extra_newline {
 4583                            new_text.push('\n');
 4584                            new_text.extend(existing_indent.chars());
 4585                            new_text.extend(indent_on_extra_newline.chars());
 4586                        }
 4587
 4588                        let anchor = buffer.anchor_after(end);
 4589                        let new_selection = selection.map(|_| anchor);
 4590                        (
 4591                            ((start..end, new_text), prevent_auto_indent),
 4592                            (insert_extra_newline, new_selection),
 4593                        )
 4594                    })
 4595                    .unzip()
 4596            };
 4597
 4598            let mut auto_indent_edits = Vec::new();
 4599            let mut edits = Vec::new();
 4600            for (edit, prevent_auto_indent) in edits_with_flags {
 4601                if prevent_auto_indent {
 4602                    edits.push(edit);
 4603                } else {
 4604                    auto_indent_edits.push(edit);
 4605                }
 4606            }
 4607            if !edits.is_empty() {
 4608                this.edit(edits, cx);
 4609            }
 4610            if !auto_indent_edits.is_empty() {
 4611                this.edit_with_autoindent(auto_indent_edits, cx);
 4612            }
 4613
 4614            let buffer = this.buffer.read(cx).snapshot(cx);
 4615            let new_selections = selection_info
 4616                .into_iter()
 4617                .map(|(extra_newline_inserted, new_selection)| {
 4618                    let mut cursor = new_selection.end.to_point(&buffer);
 4619                    if extra_newline_inserted {
 4620                        cursor.row -= 1;
 4621                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4622                    }
 4623                    new_selection.map(|_| cursor)
 4624                })
 4625                .collect();
 4626
 4627            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4628            this.refresh_inline_completion(true, false, window, cx);
 4629        });
 4630    }
 4631
 4632    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4634
 4635        let buffer = self.buffer.read(cx);
 4636        let snapshot = buffer.snapshot(cx);
 4637
 4638        let mut edits = Vec::new();
 4639        let mut rows = Vec::new();
 4640
 4641        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4642            let cursor = selection.head();
 4643            let row = cursor.row;
 4644
 4645            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4646
 4647            let newline = "\n".to_string();
 4648            edits.push((start_of_line..start_of_line, newline));
 4649
 4650            rows.push(row + rows_inserted as u32);
 4651        }
 4652
 4653        self.transact(window, cx, |editor, window, cx| {
 4654            editor.edit(edits, cx);
 4655
 4656            editor.change_selections(Default::default(), window, cx, |s| {
 4657                let mut index = 0;
 4658                s.move_cursors_with(|map, _, _| {
 4659                    let row = rows[index];
 4660                    index += 1;
 4661
 4662                    let point = Point::new(row, 0);
 4663                    let boundary = map.next_line_boundary(point).1;
 4664                    let clipped = map.clip_point(boundary, Bias::Left);
 4665
 4666                    (clipped, SelectionGoal::None)
 4667                });
 4668            });
 4669
 4670            let mut indent_edits = Vec::new();
 4671            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4672            for row in rows {
 4673                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4674                for (row, indent) in indents {
 4675                    if indent.len == 0 {
 4676                        continue;
 4677                    }
 4678
 4679                    let text = match indent.kind {
 4680                        IndentKind::Space => " ".repeat(indent.len as usize),
 4681                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4682                    };
 4683                    let point = Point::new(row.0, 0);
 4684                    indent_edits.push((point..point, text));
 4685                }
 4686            }
 4687            editor.edit(indent_edits, cx);
 4688        });
 4689    }
 4690
 4691    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4693
 4694        let buffer = self.buffer.read(cx);
 4695        let snapshot = buffer.snapshot(cx);
 4696
 4697        let mut edits = Vec::new();
 4698        let mut rows = Vec::new();
 4699        let mut rows_inserted = 0;
 4700
 4701        for selection in self.selections.all_adjusted(cx) {
 4702            let cursor = selection.head();
 4703            let row = cursor.row;
 4704
 4705            let point = Point::new(row + 1, 0);
 4706            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4707
 4708            let newline = "\n".to_string();
 4709            edits.push((start_of_line..start_of_line, newline));
 4710
 4711            rows_inserted += 1;
 4712            rows.push(row + rows_inserted);
 4713        }
 4714
 4715        self.transact(window, cx, |editor, window, cx| {
 4716            editor.edit(edits, cx);
 4717
 4718            editor.change_selections(Default::default(), window, cx, |s| {
 4719                let mut index = 0;
 4720                s.move_cursors_with(|map, _, _| {
 4721                    let row = rows[index];
 4722                    index += 1;
 4723
 4724                    let point = Point::new(row, 0);
 4725                    let boundary = map.next_line_boundary(point).1;
 4726                    let clipped = map.clip_point(boundary, Bias::Left);
 4727
 4728                    (clipped, SelectionGoal::None)
 4729                });
 4730            });
 4731
 4732            let mut indent_edits = Vec::new();
 4733            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4734            for row in rows {
 4735                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4736                for (row, indent) in indents {
 4737                    if indent.len == 0 {
 4738                        continue;
 4739                    }
 4740
 4741                    let text = match indent.kind {
 4742                        IndentKind::Space => " ".repeat(indent.len as usize),
 4743                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4744                    };
 4745                    let point = Point::new(row.0, 0);
 4746                    indent_edits.push((point..point, text));
 4747                }
 4748            }
 4749            editor.edit(indent_edits, cx);
 4750        });
 4751    }
 4752
 4753    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4754        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4755            original_indent_columns: Vec::new(),
 4756        });
 4757        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4758    }
 4759
 4760    fn insert_with_autoindent_mode(
 4761        &mut self,
 4762        text: &str,
 4763        autoindent_mode: Option<AutoindentMode>,
 4764        window: &mut Window,
 4765        cx: &mut Context<Self>,
 4766    ) {
 4767        if self.read_only(cx) {
 4768            return;
 4769        }
 4770
 4771        let text: Arc<str> = text.into();
 4772        self.transact(window, cx, |this, window, cx| {
 4773            let old_selections = this.selections.all_adjusted(cx);
 4774            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4775                let anchors = {
 4776                    let snapshot = buffer.read(cx);
 4777                    old_selections
 4778                        .iter()
 4779                        .map(|s| {
 4780                            let anchor = snapshot.anchor_after(s.head());
 4781                            s.map(|_| anchor)
 4782                        })
 4783                        .collect::<Vec<_>>()
 4784                };
 4785                buffer.edit(
 4786                    old_selections
 4787                        .iter()
 4788                        .map(|s| (s.start..s.end, text.clone())),
 4789                    autoindent_mode,
 4790                    cx,
 4791                );
 4792                anchors
 4793            });
 4794
 4795            this.change_selections(Default::default(), window, cx, |s| {
 4796                s.select_anchors(selection_anchors);
 4797            });
 4798
 4799            cx.notify();
 4800        });
 4801    }
 4802
 4803    fn trigger_completion_on_input(
 4804        &mut self,
 4805        text: &str,
 4806        trigger_in_words: bool,
 4807        window: &mut Window,
 4808        cx: &mut Context<Self>,
 4809    ) {
 4810        let completions_source = self
 4811            .context_menu
 4812            .borrow()
 4813            .as_ref()
 4814            .and_then(|menu| match menu {
 4815                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4816                CodeContextMenu::CodeActions(_) => None,
 4817            });
 4818
 4819        match completions_source {
 4820            Some(CompletionsMenuSource::Words) => {
 4821                self.show_word_completions(&ShowWordCompletions, window, cx)
 4822            }
 4823            Some(CompletionsMenuSource::Normal)
 4824            | Some(CompletionsMenuSource::SnippetChoices)
 4825            | None
 4826                if self.is_completion_trigger(
 4827                    text,
 4828                    trigger_in_words,
 4829                    completions_source.is_some(),
 4830                    cx,
 4831                ) =>
 4832            {
 4833                self.show_completions(
 4834                    &ShowCompletions {
 4835                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4836                    },
 4837                    window,
 4838                    cx,
 4839                )
 4840            }
 4841            _ => {
 4842                self.hide_context_menu(window, cx);
 4843            }
 4844        }
 4845    }
 4846
 4847    fn is_completion_trigger(
 4848        &self,
 4849        text: &str,
 4850        trigger_in_words: bool,
 4851        menu_is_open: bool,
 4852        cx: &mut Context<Self>,
 4853    ) -> bool {
 4854        let position = self.selections.newest_anchor().head();
 4855        let multibuffer = self.buffer.read(cx);
 4856        let Some(buffer) = position
 4857            .buffer_id
 4858            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4859        else {
 4860            return false;
 4861        };
 4862
 4863        if let Some(completion_provider) = &self.completion_provider {
 4864            completion_provider.is_completion_trigger(
 4865                &buffer,
 4866                position.text_anchor,
 4867                text,
 4868                trigger_in_words,
 4869                menu_is_open,
 4870                cx,
 4871            )
 4872        } else {
 4873            false
 4874        }
 4875    }
 4876
 4877    /// If any empty selections is touching the start of its innermost containing autoclose
 4878    /// region, expand it to select the brackets.
 4879    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4880        let selections = self.selections.all::<usize>(cx);
 4881        let buffer = self.buffer.read(cx).read(cx);
 4882        let new_selections = self
 4883            .selections_with_autoclose_regions(selections, &buffer)
 4884            .map(|(mut selection, region)| {
 4885                if !selection.is_empty() {
 4886                    return selection;
 4887                }
 4888
 4889                if let Some(region) = region {
 4890                    let mut range = region.range.to_offset(&buffer);
 4891                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4892                        range.start -= region.pair.start.len();
 4893                        if buffer.contains_str_at(range.start, &region.pair.start)
 4894                            && buffer.contains_str_at(range.end, &region.pair.end)
 4895                        {
 4896                            range.end += region.pair.end.len();
 4897                            selection.start = range.start;
 4898                            selection.end = range.end;
 4899
 4900                            return selection;
 4901                        }
 4902                    }
 4903                }
 4904
 4905                let always_treat_brackets_as_autoclosed = buffer
 4906                    .language_settings_at(selection.start, cx)
 4907                    .always_treat_brackets_as_autoclosed;
 4908
 4909                if !always_treat_brackets_as_autoclosed {
 4910                    return selection;
 4911                }
 4912
 4913                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4914                    for (pair, enabled) in scope.brackets() {
 4915                        if !enabled || !pair.close {
 4916                            continue;
 4917                        }
 4918
 4919                        if buffer.contains_str_at(selection.start, &pair.end) {
 4920                            let pair_start_len = pair.start.len();
 4921                            if buffer.contains_str_at(
 4922                                selection.start.saturating_sub(pair_start_len),
 4923                                &pair.start,
 4924                            ) {
 4925                                selection.start -= pair_start_len;
 4926                                selection.end += pair.end.len();
 4927
 4928                                return selection;
 4929                            }
 4930                        }
 4931                    }
 4932                }
 4933
 4934                selection
 4935            })
 4936            .collect();
 4937
 4938        drop(buffer);
 4939        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4940            selections.select(new_selections)
 4941        });
 4942    }
 4943
 4944    /// Iterate the given selections, and for each one, find the smallest surrounding
 4945    /// autoclose region. This uses the ordering of the selections and the autoclose
 4946    /// regions to avoid repeated comparisons.
 4947    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4948        &'a self,
 4949        selections: impl IntoIterator<Item = Selection<D>>,
 4950        buffer: &'a MultiBufferSnapshot,
 4951    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4952        let mut i = 0;
 4953        let mut regions = self.autoclose_regions.as_slice();
 4954        selections.into_iter().map(move |selection| {
 4955            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4956
 4957            let mut enclosing = None;
 4958            while let Some(pair_state) = regions.get(i) {
 4959                if pair_state.range.end.to_offset(buffer) < range.start {
 4960                    regions = &regions[i + 1..];
 4961                    i = 0;
 4962                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4963                    break;
 4964                } else {
 4965                    if pair_state.selection_id == selection.id {
 4966                        enclosing = Some(pair_state);
 4967                    }
 4968                    i += 1;
 4969                }
 4970            }
 4971
 4972            (selection, enclosing)
 4973        })
 4974    }
 4975
 4976    /// Remove any autoclose regions that no longer contain their selection.
 4977    fn invalidate_autoclose_regions(
 4978        &mut self,
 4979        mut selections: &[Selection<Anchor>],
 4980        buffer: &MultiBufferSnapshot,
 4981    ) {
 4982        self.autoclose_regions.retain(|state| {
 4983            let mut i = 0;
 4984            while let Some(selection) = selections.get(i) {
 4985                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4986                    selections = &selections[1..];
 4987                    continue;
 4988                }
 4989                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4990                    break;
 4991                }
 4992                if selection.id == state.selection_id {
 4993                    return true;
 4994                } else {
 4995                    i += 1;
 4996                }
 4997            }
 4998            false
 4999        });
 5000    }
 5001
 5002    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5003        let offset = position.to_offset(buffer);
 5004        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5005        if offset > word_range.start && kind == Some(CharKind::Word) {
 5006            Some(
 5007                buffer
 5008                    .text_for_range(word_range.start..offset)
 5009                    .collect::<String>(),
 5010            )
 5011        } else {
 5012            None
 5013        }
 5014    }
 5015
 5016    pub fn toggle_inline_values(
 5017        &mut self,
 5018        _: &ToggleInlineValues,
 5019        _: &mut Window,
 5020        cx: &mut Context<Self>,
 5021    ) {
 5022        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5023
 5024        self.refresh_inline_values(cx);
 5025    }
 5026
 5027    pub fn toggle_inlay_hints(
 5028        &mut self,
 5029        _: &ToggleInlayHints,
 5030        _: &mut Window,
 5031        cx: &mut Context<Self>,
 5032    ) {
 5033        self.refresh_inlay_hints(
 5034            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5035            cx,
 5036        );
 5037    }
 5038
 5039    pub fn inlay_hints_enabled(&self) -> bool {
 5040        self.inlay_hint_cache.enabled
 5041    }
 5042
 5043    pub fn inline_values_enabled(&self) -> bool {
 5044        self.inline_value_cache.enabled
 5045    }
 5046
 5047    #[cfg(any(test, feature = "test-support"))]
 5048    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5049        self.display_map
 5050            .read(cx)
 5051            .current_inlays()
 5052            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5053            .cloned()
 5054            .collect()
 5055    }
 5056
 5057    #[cfg(any(test, feature = "test-support"))]
 5058    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5059        self.display_map
 5060            .read(cx)
 5061            .current_inlays()
 5062            .cloned()
 5063            .collect()
 5064    }
 5065
 5066    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5067        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5068            return;
 5069        }
 5070
 5071        let reason_description = reason.description();
 5072        let ignore_debounce = matches!(
 5073            reason,
 5074            InlayHintRefreshReason::SettingsChange(_)
 5075                | InlayHintRefreshReason::Toggle(_)
 5076                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5077                | InlayHintRefreshReason::ModifiersChanged(_)
 5078        );
 5079        let (invalidate_cache, required_languages) = match reason {
 5080            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5081                match self.inlay_hint_cache.modifiers_override(enabled) {
 5082                    Some(enabled) => {
 5083                        if enabled {
 5084                            (InvalidationStrategy::RefreshRequested, None)
 5085                        } else {
 5086                            self.splice_inlays(
 5087                                &self
 5088                                    .visible_inlay_hints(cx)
 5089                                    .iter()
 5090                                    .map(|inlay| inlay.id)
 5091                                    .collect::<Vec<InlayId>>(),
 5092                                Vec::new(),
 5093                                cx,
 5094                            );
 5095                            return;
 5096                        }
 5097                    }
 5098                    None => return,
 5099                }
 5100            }
 5101            InlayHintRefreshReason::Toggle(enabled) => {
 5102                if self.inlay_hint_cache.toggle(enabled) {
 5103                    if enabled {
 5104                        (InvalidationStrategy::RefreshRequested, None)
 5105                    } else {
 5106                        self.splice_inlays(
 5107                            &self
 5108                                .visible_inlay_hints(cx)
 5109                                .iter()
 5110                                .map(|inlay| inlay.id)
 5111                                .collect::<Vec<InlayId>>(),
 5112                            Vec::new(),
 5113                            cx,
 5114                        );
 5115                        return;
 5116                    }
 5117                } else {
 5118                    return;
 5119                }
 5120            }
 5121            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5122                match self.inlay_hint_cache.update_settings(
 5123                    &self.buffer,
 5124                    new_settings,
 5125                    self.visible_inlay_hints(cx),
 5126                    cx,
 5127                ) {
 5128                    ControlFlow::Break(Some(InlaySplice {
 5129                        to_remove,
 5130                        to_insert,
 5131                    })) => {
 5132                        self.splice_inlays(&to_remove, to_insert, cx);
 5133                        return;
 5134                    }
 5135                    ControlFlow::Break(None) => return,
 5136                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5137                }
 5138            }
 5139            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5140                if let Some(InlaySplice {
 5141                    to_remove,
 5142                    to_insert,
 5143                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5144                {
 5145                    self.splice_inlays(&to_remove, to_insert, cx);
 5146                }
 5147                self.display_map.update(cx, |display_map, _| {
 5148                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5149                });
 5150                return;
 5151            }
 5152            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5153            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5154                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5155            }
 5156            InlayHintRefreshReason::RefreshRequested => {
 5157                (InvalidationStrategy::RefreshRequested, None)
 5158            }
 5159        };
 5160
 5161        if let Some(InlaySplice {
 5162            to_remove,
 5163            to_insert,
 5164        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5165            reason_description,
 5166            self.visible_excerpts(required_languages.as_ref(), cx),
 5167            invalidate_cache,
 5168            ignore_debounce,
 5169            cx,
 5170        ) {
 5171            self.splice_inlays(&to_remove, to_insert, cx);
 5172        }
 5173    }
 5174
 5175    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5180            .cloned()
 5181            .collect()
 5182    }
 5183
 5184    pub fn visible_excerpts(
 5185        &self,
 5186        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5187        cx: &mut Context<Editor>,
 5188    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5189        let Some(project) = self.project.as_ref() else {
 5190            return HashMap::default();
 5191        };
 5192        let project = project.read(cx);
 5193        let multi_buffer = self.buffer().read(cx);
 5194        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5195        let multi_buffer_visible_start = self
 5196            .scroll_manager
 5197            .anchor()
 5198            .anchor
 5199            .to_point(&multi_buffer_snapshot);
 5200        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5201            multi_buffer_visible_start
 5202                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5203            Bias::Left,
 5204        );
 5205        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5206        multi_buffer_snapshot
 5207            .range_to_buffer_ranges(multi_buffer_visible_range)
 5208            .into_iter()
 5209            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5210            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5211                let buffer_file = project::File::from_dyn(buffer.file())?;
 5212                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5213                let worktree_entry = buffer_worktree
 5214                    .read(cx)
 5215                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5216                if worktree_entry.is_ignored {
 5217                    return None;
 5218                }
 5219
 5220                let language = buffer.language()?;
 5221                if let Some(restrict_to_languages) = restrict_to_languages {
 5222                    if !restrict_to_languages.contains(language) {
 5223                        return None;
 5224                    }
 5225                }
 5226                Some((
 5227                    excerpt_id,
 5228                    (
 5229                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5230                        buffer.version().clone(),
 5231                        excerpt_visible_range,
 5232                    ),
 5233                ))
 5234            })
 5235            .collect()
 5236    }
 5237
 5238    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5239        TextLayoutDetails {
 5240            text_system: window.text_system().clone(),
 5241            editor_style: self.style.clone().unwrap(),
 5242            rem_size: window.rem_size(),
 5243            scroll_anchor: self.scroll_manager.anchor(),
 5244            visible_rows: self.visible_line_count(),
 5245            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5246        }
 5247    }
 5248
 5249    pub fn splice_inlays(
 5250        &self,
 5251        to_remove: &[InlayId],
 5252        to_insert: Vec<Inlay>,
 5253        cx: &mut Context<Self>,
 5254    ) {
 5255        self.display_map.update(cx, |display_map, cx| {
 5256            display_map.splice_inlays(to_remove, to_insert, cx)
 5257        });
 5258        cx.notify();
 5259    }
 5260
 5261    fn trigger_on_type_formatting(
 5262        &self,
 5263        input: String,
 5264        window: &mut Window,
 5265        cx: &mut Context<Self>,
 5266    ) -> Option<Task<Result<()>>> {
 5267        if input.len() != 1 {
 5268            return None;
 5269        }
 5270
 5271        let project = self.project.as_ref()?;
 5272        let position = self.selections.newest_anchor().head();
 5273        let (buffer, buffer_position) = self
 5274            .buffer
 5275            .read(cx)
 5276            .text_anchor_for_position(position, cx)?;
 5277
 5278        let settings = language_settings::language_settings(
 5279            buffer
 5280                .read(cx)
 5281                .language_at(buffer_position)
 5282                .map(|l| l.name()),
 5283            buffer.read(cx).file(),
 5284            cx,
 5285        );
 5286        if !settings.use_on_type_format {
 5287            return None;
 5288        }
 5289
 5290        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5291        // hence we do LSP request & edit on host side only — add formats to host's history.
 5292        let push_to_lsp_host_history = true;
 5293        // If this is not the host, append its history with new edits.
 5294        let push_to_client_history = project.read(cx).is_via_collab();
 5295
 5296        let on_type_formatting = project.update(cx, |project, cx| {
 5297            project.on_type_format(
 5298                buffer.clone(),
 5299                buffer_position,
 5300                input,
 5301                push_to_lsp_host_history,
 5302                cx,
 5303            )
 5304        });
 5305        Some(cx.spawn_in(window, async move |editor, cx| {
 5306            if let Some(transaction) = on_type_formatting.await? {
 5307                if push_to_client_history {
 5308                    buffer
 5309                        .update(cx, |buffer, _| {
 5310                            buffer.push_transaction(transaction, Instant::now());
 5311                            buffer.finalize_last_transaction();
 5312                        })
 5313                        .ok();
 5314                }
 5315                editor.update(cx, |editor, cx| {
 5316                    editor.refresh_document_highlights(cx);
 5317                })?;
 5318            }
 5319            Ok(())
 5320        }))
 5321    }
 5322
 5323    pub fn show_word_completions(
 5324        &mut self,
 5325        _: &ShowWordCompletions,
 5326        window: &mut Window,
 5327        cx: &mut Context<Self>,
 5328    ) {
 5329        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5330    }
 5331
 5332    pub fn show_completions(
 5333        &mut self,
 5334        options: &ShowCompletions,
 5335        window: &mut Window,
 5336        cx: &mut Context<Self>,
 5337    ) {
 5338        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5339    }
 5340
 5341    fn open_or_update_completions_menu(
 5342        &mut self,
 5343        requested_source: Option<CompletionsMenuSource>,
 5344        trigger: Option<&str>,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) {
 5348        if self.pending_rename.is_some() {
 5349            return;
 5350        }
 5351
 5352        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5353
 5354        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5355        // inserted and selected. To handle that case, the start of the selection is used so that
 5356        // the menu starts with all choices.
 5357        let position = self
 5358            .selections
 5359            .newest_anchor()
 5360            .start
 5361            .bias_right(&multibuffer_snapshot);
 5362        if position.diff_base_anchor.is_some() {
 5363            return;
 5364        }
 5365        let (buffer, buffer_position) =
 5366            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5367                output
 5368            } else {
 5369                return;
 5370            };
 5371        let buffer_snapshot = buffer.read(cx).snapshot();
 5372
 5373        let query: Option<Arc<String>> =
 5374            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5375
 5376        drop(multibuffer_snapshot);
 5377
 5378        let provider = match requested_source {
 5379            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5380            Some(CompletionsMenuSource::Words) => None,
 5381            Some(CompletionsMenuSource::SnippetChoices) => {
 5382                log::error!("bug: SnippetChoices requested_source is not handled");
 5383                None
 5384            }
 5385        };
 5386
 5387        let sort_completions = provider
 5388            .as_ref()
 5389            .map_or(false, |provider| provider.sort_completions());
 5390
 5391        let filter_completions = provider
 5392            .as_ref()
 5393            .map_or(true, |provider| provider.filter_completions());
 5394
 5395        let trigger_kind = match trigger {
 5396            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5397                CompletionTriggerKind::TRIGGER_CHARACTER
 5398            }
 5399            _ => CompletionTriggerKind::INVOKED,
 5400        };
 5401        let completion_context = CompletionContext {
 5402            trigger_character: trigger.and_then(|trigger| {
 5403                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5404                    Some(String::from(trigger))
 5405                } else {
 5406                    None
 5407                }
 5408            }),
 5409            trigger_kind,
 5410        };
 5411
 5412        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5413        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5414        // involve trigger chars, so this is skipped in that case.
 5415        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5416        {
 5417            let menu_is_open = matches!(
 5418                self.context_menu.borrow().as_ref(),
 5419                Some(CodeContextMenu::Completions(_))
 5420            );
 5421            if menu_is_open {
 5422                self.hide_context_menu(window, cx);
 5423            }
 5424        }
 5425
 5426        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5427            if filter_completions {
 5428                menu.filter(query.clone(), provider.clone(), window, cx);
 5429            }
 5430            // When `is_incomplete` is false, no need to re-query completions when the current query
 5431            // is a suffix of the initial query.
 5432            if !menu.is_incomplete {
 5433                // If the new query is a suffix of the old query (typing more characters) and
 5434                // the previous result was complete, the existing completions can be filtered.
 5435                //
 5436                // Note that this is always true for snippet completions.
 5437                let query_matches = match (&menu.initial_query, &query) {
 5438                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5439                    (None, _) => true,
 5440                    _ => false,
 5441                };
 5442                if query_matches {
 5443                    let position_matches = if menu.initial_position == position {
 5444                        true
 5445                    } else {
 5446                        let snapshot = self.buffer.read(cx).read(cx);
 5447                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5448                    };
 5449                    if position_matches {
 5450                        return;
 5451                    }
 5452                }
 5453            }
 5454        };
 5455
 5456        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5457            buffer_snapshot.surrounding_word(buffer_position, false)
 5458        {
 5459            let word_to_exclude = buffer_snapshot
 5460                .text_for_range(word_range.clone())
 5461                .collect::<String>();
 5462            (
 5463                buffer_snapshot.anchor_before(word_range.start)
 5464                    ..buffer_snapshot.anchor_after(buffer_position),
 5465                Some(word_to_exclude),
 5466            )
 5467        } else {
 5468            (buffer_position..buffer_position, None)
 5469        };
 5470
 5471        let language = buffer_snapshot
 5472            .language_at(buffer_position)
 5473            .map(|language| language.name());
 5474
 5475        let completion_settings =
 5476            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5477
 5478        let show_completion_documentation = buffer_snapshot
 5479            .settings_at(buffer_position, cx)
 5480            .show_completion_documentation;
 5481
 5482        // The document can be large, so stay in reasonable bounds when searching for words,
 5483        // otherwise completion pop-up might be slow to appear.
 5484        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5485        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5486        let min_word_search = buffer_snapshot.clip_point(
 5487            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5488            Bias::Left,
 5489        );
 5490        let max_word_search = buffer_snapshot.clip_point(
 5491            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5492            Bias::Right,
 5493        );
 5494        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5495            ..buffer_snapshot.point_to_offset(max_word_search);
 5496
 5497        let skip_digits = query
 5498            .as_ref()
 5499            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5500
 5501        let (mut words, provider_responses) = match &provider {
 5502            Some(provider) => {
 5503                let provider_responses = provider.completions(
 5504                    position.excerpt_id,
 5505                    &buffer,
 5506                    buffer_position,
 5507                    completion_context,
 5508                    window,
 5509                    cx,
 5510                );
 5511
 5512                let words = match completion_settings.words {
 5513                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5514                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5515                        .background_spawn(async move {
 5516                            buffer_snapshot.words_in_range(WordsQuery {
 5517                                fuzzy_contents: None,
 5518                                range: word_search_range,
 5519                                skip_digits,
 5520                            })
 5521                        }),
 5522                };
 5523
 5524                (words, provider_responses)
 5525            }
 5526            None => (
 5527                cx.background_spawn(async move {
 5528                    buffer_snapshot.words_in_range(WordsQuery {
 5529                        fuzzy_contents: None,
 5530                        range: word_search_range,
 5531                        skip_digits,
 5532                    })
 5533                }),
 5534                Task::ready(Ok(Vec::new())),
 5535            ),
 5536        };
 5537
 5538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5539
 5540        let id = post_inc(&mut self.next_completion_id);
 5541        let task = cx.spawn_in(window, async move |editor, cx| {
 5542            let Ok(()) = editor.update(cx, |this, _| {
 5543                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5544            }) else {
 5545                return;
 5546            };
 5547
 5548            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5549            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5550            let mut completions = Vec::new();
 5551            let mut is_incomplete = false;
 5552            if let Some(provider_responses) = provider_responses.await.log_err() {
 5553                if !provider_responses.is_empty() {
 5554                    for response in provider_responses {
 5555                        completions.extend(response.completions);
 5556                        is_incomplete = is_incomplete || response.is_incomplete;
 5557                    }
 5558                    if completion_settings.words == WordsCompletionMode::Fallback {
 5559                        words = Task::ready(BTreeMap::default());
 5560                    }
 5561                }
 5562            }
 5563
 5564            let mut words = words.await;
 5565            if let Some(word_to_exclude) = &word_to_exclude {
 5566                words.remove(word_to_exclude);
 5567            }
 5568            for lsp_completion in &completions {
 5569                words.remove(&lsp_completion.new_text);
 5570            }
 5571            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5572                replace_range: word_replace_range.clone(),
 5573                new_text: word.clone(),
 5574                label: CodeLabel::plain(word, None),
 5575                icon_path: None,
 5576                documentation: None,
 5577                source: CompletionSource::BufferWord {
 5578                    word_range,
 5579                    resolved: false,
 5580                },
 5581                insert_text_mode: Some(InsertTextMode::AS_IS),
 5582                confirm: None,
 5583            }));
 5584
 5585            let menu = if completions.is_empty() {
 5586                None
 5587            } else {
 5588                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5589                    let languages = editor
 5590                        .workspace
 5591                        .as_ref()
 5592                        .and_then(|(workspace, _)| workspace.upgrade())
 5593                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5594                    let menu = CompletionsMenu::new(
 5595                        id,
 5596                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5597                        sort_completions,
 5598                        show_completion_documentation,
 5599                        position,
 5600                        query.clone(),
 5601                        is_incomplete,
 5602                        buffer.clone(),
 5603                        completions.into(),
 5604                        snippet_sort_order,
 5605                        languages,
 5606                        language,
 5607                        cx,
 5608                    );
 5609
 5610                    let query = if filter_completions { query } else { None };
 5611                    let matches_task = if let Some(query) = query {
 5612                        menu.do_async_filtering(query, cx)
 5613                    } else {
 5614                        Task::ready(menu.unfiltered_matches())
 5615                    };
 5616                    (menu, matches_task)
 5617                }) else {
 5618                    return;
 5619                };
 5620
 5621                let matches = matches_task.await;
 5622
 5623                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5624                    // Newer menu already set, so exit.
 5625                    match editor.context_menu.borrow().as_ref() {
 5626                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5627                            if prev_menu.id > id {
 5628                                return;
 5629                            }
 5630                        }
 5631                        _ => {}
 5632                    };
 5633
 5634                    // Only valid to take prev_menu because it the new menu is immediately set
 5635                    // below, or the menu is hidden.
 5636                    match editor.context_menu.borrow_mut().take() {
 5637                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5638                            let position_matches =
 5639                                if prev_menu.initial_position == menu.initial_position {
 5640                                    true
 5641                                } else {
 5642                                    let snapshot = editor.buffer.read(cx).read(cx);
 5643                                    prev_menu.initial_position.to_offset(&snapshot)
 5644                                        == menu.initial_position.to_offset(&snapshot)
 5645                                };
 5646                            if position_matches {
 5647                                // Preserve markdown cache before `set_filter_results` because it will
 5648                                // try to populate the documentation cache.
 5649                                menu.preserve_markdown_cache(prev_menu);
 5650                            }
 5651                        }
 5652                        _ => {}
 5653                    };
 5654
 5655                    menu.set_filter_results(matches, provider, window, cx);
 5656                }) else {
 5657                    return;
 5658                };
 5659
 5660                menu.visible().then_some(menu)
 5661            };
 5662
 5663            editor
 5664                .update_in(cx, |editor, window, cx| {
 5665                    if editor.focus_handle.is_focused(window) {
 5666                        if let Some(menu) = menu {
 5667                            *editor.context_menu.borrow_mut() =
 5668                                Some(CodeContextMenu::Completions(menu));
 5669
 5670                            crate::hover_popover::hide_hover(editor, cx);
 5671                            if editor.show_edit_predictions_in_menu() {
 5672                                editor.update_visible_inline_completion(window, cx);
 5673                            } else {
 5674                                editor.discard_inline_completion(false, cx);
 5675                            }
 5676
 5677                            cx.notify();
 5678                            return;
 5679                        }
 5680                    }
 5681
 5682                    if editor.completion_tasks.len() <= 1 {
 5683                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5684                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5685                        // If it was already hidden and we don't show inline completions in the menu, we should
 5686                        // also show the inline-completion when available.
 5687                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5688                            editor.update_visible_inline_completion(window, cx);
 5689                        }
 5690                    }
 5691                })
 5692                .ok();
 5693        });
 5694
 5695        self.completion_tasks.push((id, task));
 5696    }
 5697
 5698    #[cfg(feature = "test-support")]
 5699    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5700        let menu = self.context_menu.borrow();
 5701        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5702            let completions = menu.completions.borrow();
 5703            Some(completions.to_vec())
 5704        } else {
 5705            None
 5706        }
 5707    }
 5708
 5709    pub fn with_completions_menu_matching_id<R>(
 5710        &self,
 5711        id: CompletionId,
 5712        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5713    ) -> R {
 5714        let mut context_menu = self.context_menu.borrow_mut();
 5715        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5716            return f(None);
 5717        };
 5718        if completions_menu.id != id {
 5719            return f(None);
 5720        }
 5721        f(Some(completions_menu))
 5722    }
 5723
 5724    pub fn confirm_completion(
 5725        &mut self,
 5726        action: &ConfirmCompletion,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) -> Option<Task<Result<()>>> {
 5730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5731        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5732    }
 5733
 5734    pub fn confirm_completion_insert(
 5735        &mut self,
 5736        _: &ConfirmCompletionInsert,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) -> Option<Task<Result<()>>> {
 5740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5741        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5742    }
 5743
 5744    pub fn confirm_completion_replace(
 5745        &mut self,
 5746        _: &ConfirmCompletionReplace,
 5747        window: &mut Window,
 5748        cx: &mut Context<Self>,
 5749    ) -> Option<Task<Result<()>>> {
 5750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5751        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5752    }
 5753
 5754    pub fn compose_completion(
 5755        &mut self,
 5756        action: &ComposeCompletion,
 5757        window: &mut Window,
 5758        cx: &mut Context<Self>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5761        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5762    }
 5763
 5764    fn do_completion(
 5765        &mut self,
 5766        item_ix: Option<usize>,
 5767        intent: CompletionIntent,
 5768        window: &mut Window,
 5769        cx: &mut Context<Editor>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        use language::ToOffset as _;
 5772
 5773        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5774        else {
 5775            return None;
 5776        };
 5777
 5778        let candidate_id = {
 5779            let entries = completions_menu.entries.borrow();
 5780            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5781            if self.show_edit_predictions_in_menu() {
 5782                self.discard_inline_completion(true, cx);
 5783            }
 5784            mat.candidate_id
 5785        };
 5786
 5787        let completion = completions_menu
 5788            .completions
 5789            .borrow()
 5790            .get(candidate_id)?
 5791            .clone();
 5792        cx.stop_propagation();
 5793
 5794        let buffer_handle = completions_menu.buffer.clone();
 5795
 5796        let CompletionEdit {
 5797            new_text,
 5798            snippet,
 5799            replace_range,
 5800        } = process_completion_for_edit(
 5801            &completion,
 5802            intent,
 5803            &buffer_handle,
 5804            &completions_menu.initial_position.text_anchor,
 5805            cx,
 5806        );
 5807
 5808        let buffer = buffer_handle.read(cx);
 5809        let snapshot = self.buffer.read(cx).snapshot(cx);
 5810        let newest_anchor = self.selections.newest_anchor();
 5811        let replace_range_multibuffer = {
 5812            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5813            let multibuffer_anchor = snapshot
 5814                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5815                .unwrap()
 5816                ..snapshot
 5817                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5818                    .unwrap();
 5819            multibuffer_anchor.start.to_offset(&snapshot)
 5820                ..multibuffer_anchor.end.to_offset(&snapshot)
 5821        };
 5822        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5823            return None;
 5824        }
 5825
 5826        let old_text = buffer
 5827            .text_for_range(replace_range.clone())
 5828            .collect::<String>();
 5829        let lookbehind = newest_anchor
 5830            .start
 5831            .text_anchor
 5832            .to_offset(buffer)
 5833            .saturating_sub(replace_range.start);
 5834        let lookahead = replace_range
 5835            .end
 5836            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5837        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5838        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5839
 5840        let selections = self.selections.all::<usize>(cx);
 5841        let mut ranges = Vec::new();
 5842        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5843
 5844        for selection in &selections {
 5845            let range = if selection.id == newest_anchor.id {
 5846                replace_range_multibuffer.clone()
 5847            } else {
 5848                let mut range = selection.range();
 5849
 5850                // if prefix is present, don't duplicate it
 5851                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5852                    range.start = range.start.saturating_sub(lookbehind);
 5853
 5854                    // if suffix is also present, mimic the newest cursor and replace it
 5855                    if selection.id != newest_anchor.id
 5856                        && snapshot.contains_str_at(range.end, suffix)
 5857                    {
 5858                        range.end += lookahead;
 5859                    }
 5860                }
 5861                range
 5862            };
 5863
 5864            ranges.push(range.clone());
 5865
 5866            if !self.linked_edit_ranges.is_empty() {
 5867                let start_anchor = snapshot.anchor_before(range.start);
 5868                let end_anchor = snapshot.anchor_after(range.end);
 5869                if let Some(ranges) = self
 5870                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5871                {
 5872                    for (buffer, edits) in ranges {
 5873                        linked_edits
 5874                            .entry(buffer.clone())
 5875                            .or_default()
 5876                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5877                    }
 5878                }
 5879            }
 5880        }
 5881
 5882        let common_prefix_len = old_text
 5883            .chars()
 5884            .zip(new_text.chars())
 5885            .take_while(|(a, b)| a == b)
 5886            .map(|(a, _)| a.len_utf8())
 5887            .sum::<usize>();
 5888
 5889        cx.emit(EditorEvent::InputHandled {
 5890            utf16_range_to_replace: None,
 5891            text: new_text[common_prefix_len..].into(),
 5892        });
 5893
 5894        self.transact(window, cx, |this, window, cx| {
 5895            if let Some(mut snippet) = snippet {
 5896                snippet.text = new_text.to_string();
 5897                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5898            } else {
 5899                this.buffer.update(cx, |buffer, cx| {
 5900                    let auto_indent = match completion.insert_text_mode {
 5901                        Some(InsertTextMode::AS_IS) => None,
 5902                        _ => this.autoindent_mode.clone(),
 5903                    };
 5904                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5905                    buffer.edit(edits, auto_indent, cx);
 5906                });
 5907            }
 5908            for (buffer, edits) in linked_edits {
 5909                buffer.update(cx, |buffer, cx| {
 5910                    let snapshot = buffer.snapshot();
 5911                    let edits = edits
 5912                        .into_iter()
 5913                        .map(|(range, text)| {
 5914                            use text::ToPoint as TP;
 5915                            let end_point = TP::to_point(&range.end, &snapshot);
 5916                            let start_point = TP::to_point(&range.start, &snapshot);
 5917                            (start_point..end_point, text)
 5918                        })
 5919                        .sorted_by_key(|(range, _)| range.start);
 5920                    buffer.edit(edits, None, cx);
 5921                })
 5922            }
 5923
 5924            this.refresh_inline_completion(true, false, window, cx);
 5925        });
 5926
 5927        let show_new_completions_on_confirm = completion
 5928            .confirm
 5929            .as_ref()
 5930            .map_or(false, |confirm| confirm(intent, window, cx));
 5931        if show_new_completions_on_confirm {
 5932            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5933        }
 5934
 5935        let provider = self.completion_provider.as_ref()?;
 5936        drop(completion);
 5937        let apply_edits = provider.apply_additional_edits_for_completion(
 5938            buffer_handle,
 5939            completions_menu.completions.clone(),
 5940            candidate_id,
 5941            true,
 5942            cx,
 5943        );
 5944
 5945        let editor_settings = EditorSettings::get_global(cx);
 5946        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5947            // After the code completion is finished, users often want to know what signatures are needed.
 5948            // so we should automatically call signature_help
 5949            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5950        }
 5951
 5952        Some(cx.foreground_executor().spawn(async move {
 5953            apply_edits.await?;
 5954            Ok(())
 5955        }))
 5956    }
 5957
 5958    pub fn toggle_code_actions(
 5959        &mut self,
 5960        action: &ToggleCodeActions,
 5961        window: &mut Window,
 5962        cx: &mut Context<Self>,
 5963    ) {
 5964        let quick_launch = action.quick_launch;
 5965        let mut context_menu = self.context_menu.borrow_mut();
 5966        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5967            if code_actions.deployed_from == action.deployed_from {
 5968                // Toggle if we're selecting the same one
 5969                *context_menu = None;
 5970                cx.notify();
 5971                return;
 5972            } else {
 5973                // Otherwise, clear it and start a new one
 5974                *context_menu = None;
 5975                cx.notify();
 5976            }
 5977        }
 5978        drop(context_menu);
 5979        let snapshot = self.snapshot(window, cx);
 5980        let deployed_from = action.deployed_from.clone();
 5981        let action = action.clone();
 5982        self.completion_tasks.clear();
 5983        self.discard_inline_completion(false, cx);
 5984
 5985        let multibuffer_point = match &action.deployed_from {
 5986            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5987                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5988            }
 5989            _ => self.selections.newest::<Point>(cx).head(),
 5990        };
 5991        let Some((buffer, buffer_row)) = snapshot
 5992            .buffer_snapshot
 5993            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5994            .and_then(|(buffer_snapshot, range)| {
 5995                self.buffer()
 5996                    .read(cx)
 5997                    .buffer(buffer_snapshot.remote_id())
 5998                    .map(|buffer| (buffer, range.start.row))
 5999            })
 6000        else {
 6001            return;
 6002        };
 6003        let buffer_id = buffer.read(cx).remote_id();
 6004        let tasks = self
 6005            .tasks
 6006            .get(&(buffer_id, buffer_row))
 6007            .map(|t| Arc::new(t.to_owned()));
 6008
 6009        if !self.focus_handle.is_focused(window) {
 6010            return;
 6011        }
 6012        let project = self.project.clone();
 6013
 6014        let code_actions_task = match deployed_from {
 6015            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6016            _ => self.code_actions(buffer_row, window, cx),
 6017        };
 6018
 6019        let runnable_task = match deployed_from {
 6020            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6021            _ => {
 6022                let mut task_context_task = Task::ready(None);
 6023                if let Some(tasks) = &tasks {
 6024                    if let Some(project) = project {
 6025                        task_context_task =
 6026                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6027                    }
 6028                }
 6029
 6030                cx.spawn_in(window, {
 6031                    let buffer = buffer.clone();
 6032                    async move |editor, cx| {
 6033                        let task_context = task_context_task.await;
 6034
 6035                        let resolved_tasks =
 6036                            tasks
 6037                                .zip(task_context.clone())
 6038                                .map(|(tasks, task_context)| ResolvedTasks {
 6039                                    templates: tasks.resolve(&task_context).collect(),
 6040                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6041                                        multibuffer_point.row,
 6042                                        tasks.column,
 6043                                    )),
 6044                                });
 6045                        let debug_scenarios = editor
 6046                            .update(cx, |editor, cx| {
 6047                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6048                            })?
 6049                            .await;
 6050                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6051                    }
 6052                })
 6053            }
 6054        };
 6055
 6056        cx.spawn_in(window, async move |editor, cx| {
 6057            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6058            let code_actions = code_actions_task.await;
 6059            let spawn_straight_away = quick_launch
 6060                && resolved_tasks
 6061                    .as_ref()
 6062                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6063                && code_actions
 6064                    .as_ref()
 6065                    .map_or(true, |actions| actions.is_empty())
 6066                && debug_scenarios.is_empty();
 6067
 6068            editor.update_in(cx, |editor, window, cx| {
 6069                crate::hover_popover::hide_hover(editor, cx);
 6070                let actions = CodeActionContents::new(
 6071                    resolved_tasks,
 6072                    code_actions,
 6073                    debug_scenarios,
 6074                    task_context.unwrap_or_default(),
 6075                );
 6076
 6077                // Don't show the menu if there are no actions available
 6078                if actions.is_empty() {
 6079                    cx.notify();
 6080                    return Task::ready(Ok(()));
 6081                }
 6082
 6083                *editor.context_menu.borrow_mut() =
 6084                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6085                        buffer,
 6086                        actions,
 6087                        selected_item: Default::default(),
 6088                        scroll_handle: UniformListScrollHandle::default(),
 6089                        deployed_from,
 6090                    }));
 6091                cx.notify();
 6092                if spawn_straight_away {
 6093                    if let Some(task) = editor.confirm_code_action(
 6094                        &ConfirmCodeAction { item_ix: Some(0) },
 6095                        window,
 6096                        cx,
 6097                    ) {
 6098                        return task;
 6099                    }
 6100                }
 6101
 6102                Task::ready(Ok(()))
 6103            })
 6104        })
 6105        .detach_and_log_err(cx);
 6106    }
 6107
 6108    fn debug_scenarios(
 6109        &mut self,
 6110        resolved_tasks: &Option<ResolvedTasks>,
 6111        buffer: &Entity<Buffer>,
 6112        cx: &mut App,
 6113    ) -> Task<Vec<task::DebugScenario>> {
 6114        maybe!({
 6115            let project = self.project.as_ref()?;
 6116            let dap_store = project.read(cx).dap_store();
 6117            let mut scenarios = vec![];
 6118            let resolved_tasks = resolved_tasks.as_ref()?;
 6119            let buffer = buffer.read(cx);
 6120            let language = buffer.language()?;
 6121            let file = buffer.file();
 6122            let debug_adapter = language_settings(language.name().into(), file, cx)
 6123                .debuggers
 6124                .first()
 6125                .map(SharedString::from)
 6126                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6127
 6128            dap_store.update(cx, |dap_store, cx| {
 6129                for (_, task) in &resolved_tasks.templates {
 6130                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6131                        task.original_task().clone(),
 6132                        debug_adapter.clone().into(),
 6133                        task.display_label().to_owned().into(),
 6134                        cx,
 6135                    );
 6136                    scenarios.push(maybe_scenario);
 6137                }
 6138            });
 6139            Some(cx.background_spawn(async move {
 6140                let scenarios = futures::future::join_all(scenarios)
 6141                    .await
 6142                    .into_iter()
 6143                    .flatten()
 6144                    .collect::<Vec<_>>();
 6145                scenarios
 6146            }))
 6147        })
 6148        .unwrap_or_else(|| Task::ready(vec![]))
 6149    }
 6150
 6151    fn code_actions(
 6152        &mut self,
 6153        buffer_row: u32,
 6154        window: &mut Window,
 6155        cx: &mut Context<Self>,
 6156    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6157        let mut task = self.code_actions_task.take();
 6158        cx.spawn_in(window, async move |editor, cx| {
 6159            while let Some(prev_task) = task {
 6160                prev_task.await.log_err();
 6161                task = editor
 6162                    .update(cx, |this, _| this.code_actions_task.take())
 6163                    .ok()?;
 6164            }
 6165
 6166            editor
 6167                .update(cx, |editor, cx| {
 6168                    editor
 6169                        .available_code_actions
 6170                        .clone()
 6171                        .and_then(|(location, code_actions)| {
 6172                            let snapshot = location.buffer.read(cx).snapshot();
 6173                            let point_range = location.range.to_point(&snapshot);
 6174                            let point_range = point_range.start.row..=point_range.end.row;
 6175                            if point_range.contains(&buffer_row) {
 6176                                Some(code_actions)
 6177                            } else {
 6178                                None
 6179                            }
 6180                        })
 6181                })
 6182                .ok()
 6183                .flatten()
 6184        })
 6185    }
 6186
 6187    pub fn confirm_code_action(
 6188        &mut self,
 6189        action: &ConfirmCodeAction,
 6190        window: &mut Window,
 6191        cx: &mut Context<Self>,
 6192    ) -> Option<Task<Result<()>>> {
 6193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6194
 6195        let actions_menu =
 6196            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6197                menu
 6198            } else {
 6199                return None;
 6200            };
 6201
 6202        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6203        let action = actions_menu.actions.get(action_ix)?;
 6204        let title = action.label();
 6205        let buffer = actions_menu.buffer;
 6206        let workspace = self.workspace()?;
 6207
 6208        match action {
 6209            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6210                workspace.update(cx, |workspace, cx| {
 6211                    workspace.schedule_resolved_task(
 6212                        task_source_kind,
 6213                        resolved_task,
 6214                        false,
 6215                        window,
 6216                        cx,
 6217                    );
 6218
 6219                    Some(Task::ready(Ok(())))
 6220                })
 6221            }
 6222            CodeActionsItem::CodeAction {
 6223                excerpt_id,
 6224                action,
 6225                provider,
 6226            } => {
 6227                let apply_code_action =
 6228                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6229                let workspace = workspace.downgrade();
 6230                Some(cx.spawn_in(window, async move |editor, cx| {
 6231                    let project_transaction = apply_code_action.await?;
 6232                    Self::open_project_transaction(
 6233                        &editor,
 6234                        workspace,
 6235                        project_transaction,
 6236                        title,
 6237                        cx,
 6238                    )
 6239                    .await
 6240                }))
 6241            }
 6242            CodeActionsItem::DebugScenario(scenario) => {
 6243                let context = actions_menu.actions.context.clone();
 6244
 6245                workspace.update(cx, |workspace, cx| {
 6246                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6247                    workspace.start_debug_session(
 6248                        scenario,
 6249                        context,
 6250                        Some(buffer),
 6251                        None,
 6252                        window,
 6253                        cx,
 6254                    );
 6255                });
 6256                Some(Task::ready(Ok(())))
 6257            }
 6258        }
 6259    }
 6260
 6261    pub async fn open_project_transaction(
 6262        this: &WeakEntity<Editor>,
 6263        workspace: WeakEntity<Workspace>,
 6264        transaction: ProjectTransaction,
 6265        title: String,
 6266        cx: &mut AsyncWindowContext,
 6267    ) -> Result<()> {
 6268        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6269        cx.update(|_, cx| {
 6270            entries.sort_unstable_by_key(|(buffer, _)| {
 6271                buffer.read(cx).file().map(|f| f.path().clone())
 6272            });
 6273        })?;
 6274
 6275        // If the project transaction's edits are all contained within this editor, then
 6276        // avoid opening a new editor to display them.
 6277
 6278        if let Some((buffer, transaction)) = entries.first() {
 6279            if entries.len() == 1 {
 6280                let excerpt = this.update(cx, |editor, cx| {
 6281                    editor
 6282                        .buffer()
 6283                        .read(cx)
 6284                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6285                })?;
 6286                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6287                    if excerpted_buffer == *buffer {
 6288                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6289                            let excerpt_range = excerpt_range.to_offset(buffer);
 6290                            buffer
 6291                                .edited_ranges_for_transaction::<usize>(transaction)
 6292                                .all(|range| {
 6293                                    excerpt_range.start <= range.start
 6294                                        && excerpt_range.end >= range.end
 6295                                })
 6296                        })?;
 6297
 6298                        if all_edits_within_excerpt {
 6299                            return Ok(());
 6300                        }
 6301                    }
 6302                }
 6303            }
 6304        } else {
 6305            return Ok(());
 6306        }
 6307
 6308        let mut ranges_to_highlight = Vec::new();
 6309        let excerpt_buffer = cx.new(|cx| {
 6310            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6311            for (buffer_handle, transaction) in &entries {
 6312                let edited_ranges = buffer_handle
 6313                    .read(cx)
 6314                    .edited_ranges_for_transaction::<Point>(transaction)
 6315                    .collect::<Vec<_>>();
 6316                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6317                    PathKey::for_buffer(buffer_handle, cx),
 6318                    buffer_handle.clone(),
 6319                    edited_ranges,
 6320                    DEFAULT_MULTIBUFFER_CONTEXT,
 6321                    cx,
 6322                );
 6323
 6324                ranges_to_highlight.extend(ranges);
 6325            }
 6326            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6327            multibuffer
 6328        })?;
 6329
 6330        workspace.update_in(cx, |workspace, window, cx| {
 6331            let project = workspace.project().clone();
 6332            let editor =
 6333                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6334            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6335            editor.update(cx, |editor, cx| {
 6336                editor.highlight_background::<Self>(
 6337                    &ranges_to_highlight,
 6338                    |theme| theme.colors().editor_highlighted_line_background,
 6339                    cx,
 6340                );
 6341            });
 6342        })?;
 6343
 6344        Ok(())
 6345    }
 6346
 6347    pub fn clear_code_action_providers(&mut self) {
 6348        self.code_action_providers.clear();
 6349        self.available_code_actions.take();
 6350    }
 6351
 6352    pub fn add_code_action_provider(
 6353        &mut self,
 6354        provider: Rc<dyn CodeActionProvider>,
 6355        window: &mut Window,
 6356        cx: &mut Context<Self>,
 6357    ) {
 6358        if self
 6359            .code_action_providers
 6360            .iter()
 6361            .any(|existing_provider| existing_provider.id() == provider.id())
 6362        {
 6363            return;
 6364        }
 6365
 6366        self.code_action_providers.push(provider);
 6367        self.refresh_code_actions(window, cx);
 6368    }
 6369
 6370    pub fn remove_code_action_provider(
 6371        &mut self,
 6372        id: Arc<str>,
 6373        window: &mut Window,
 6374        cx: &mut Context<Self>,
 6375    ) {
 6376        self.code_action_providers
 6377            .retain(|provider| provider.id() != id);
 6378        self.refresh_code_actions(window, cx);
 6379    }
 6380
 6381    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6382        !self.code_action_providers.is_empty()
 6383            && EditorSettings::get_global(cx).toolbar.code_actions
 6384    }
 6385
 6386    pub fn has_available_code_actions(&self) -> bool {
 6387        self.available_code_actions
 6388            .as_ref()
 6389            .is_some_and(|(_, actions)| !actions.is_empty())
 6390    }
 6391
 6392    fn render_inline_code_actions(
 6393        &self,
 6394        icon_size: ui::IconSize,
 6395        display_row: DisplayRow,
 6396        is_active: bool,
 6397        cx: &mut Context<Self>,
 6398    ) -> AnyElement {
 6399        let show_tooltip = !self.context_menu_visible();
 6400        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6401            .icon_size(icon_size)
 6402            .shape(ui::IconButtonShape::Square)
 6403            .style(ButtonStyle::Transparent)
 6404            .icon_color(ui::Color::Hidden)
 6405            .toggle_state(is_active)
 6406            .when(show_tooltip, |this| {
 6407                this.tooltip({
 6408                    let focus_handle = self.focus_handle.clone();
 6409                    move |window, cx| {
 6410                        Tooltip::for_action_in(
 6411                            "Toggle Code Actions",
 6412                            &ToggleCodeActions {
 6413                                deployed_from: None,
 6414                                quick_launch: false,
 6415                            },
 6416                            &focus_handle,
 6417                            window,
 6418                            cx,
 6419                        )
 6420                    }
 6421                })
 6422            })
 6423            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6424                window.focus(&editor.focus_handle(cx));
 6425                editor.toggle_code_actions(
 6426                    &crate::actions::ToggleCodeActions {
 6427                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6428                            display_row,
 6429                        )),
 6430                        quick_launch: false,
 6431                    },
 6432                    window,
 6433                    cx,
 6434                );
 6435            }))
 6436            .into_any_element()
 6437    }
 6438
 6439    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6440        &self.context_menu
 6441    }
 6442
 6443    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6444        let newest_selection = self.selections.newest_anchor().clone();
 6445        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6446        let buffer = self.buffer.read(cx);
 6447        if newest_selection.head().diff_base_anchor.is_some() {
 6448            return None;
 6449        }
 6450        let (start_buffer, start) =
 6451            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6452        let (end_buffer, end) =
 6453            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6454        if start_buffer != end_buffer {
 6455            return None;
 6456        }
 6457
 6458        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6459            cx.background_executor()
 6460                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6461                .await;
 6462
 6463            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6464                let providers = this.code_action_providers.clone();
 6465                let tasks = this
 6466                    .code_action_providers
 6467                    .iter()
 6468                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6469                    .collect::<Vec<_>>();
 6470                (providers, tasks)
 6471            })?;
 6472
 6473            let mut actions = Vec::new();
 6474            for (provider, provider_actions) in
 6475                providers.into_iter().zip(future::join_all(tasks).await)
 6476            {
 6477                if let Some(provider_actions) = provider_actions.log_err() {
 6478                    actions.extend(provider_actions.into_iter().map(|action| {
 6479                        AvailableCodeAction {
 6480                            excerpt_id: newest_selection.start.excerpt_id,
 6481                            action,
 6482                            provider: provider.clone(),
 6483                        }
 6484                    }));
 6485                }
 6486            }
 6487
 6488            this.update(cx, |this, cx| {
 6489                this.available_code_actions = if actions.is_empty() {
 6490                    None
 6491                } else {
 6492                    Some((
 6493                        Location {
 6494                            buffer: start_buffer,
 6495                            range: start..end,
 6496                        },
 6497                        actions.into(),
 6498                    ))
 6499                };
 6500                cx.notify();
 6501            })
 6502        }));
 6503        None
 6504    }
 6505
 6506    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6507        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6508            self.show_git_blame_inline = false;
 6509
 6510            self.show_git_blame_inline_delay_task =
 6511                Some(cx.spawn_in(window, async move |this, cx| {
 6512                    cx.background_executor().timer(delay).await;
 6513
 6514                    this.update(cx, |this, cx| {
 6515                        this.show_git_blame_inline = true;
 6516                        cx.notify();
 6517                    })
 6518                    .log_err();
 6519                }));
 6520        }
 6521    }
 6522
 6523    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6524        let snapshot = self.snapshot(window, cx);
 6525        let cursor = self.selections.newest::<Point>(cx).head();
 6526        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6527        else {
 6528            return;
 6529        };
 6530
 6531        let Some(blame) = self.blame.as_ref() else {
 6532            return;
 6533        };
 6534
 6535        let row_info = RowInfo {
 6536            buffer_id: Some(buffer.remote_id()),
 6537            buffer_row: Some(point.row),
 6538            ..Default::default()
 6539        };
 6540        let Some(blame_entry) = blame
 6541            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6542            .flatten()
 6543        else {
 6544            return;
 6545        };
 6546
 6547        let anchor = self.selections.newest_anchor().head();
 6548        let position = self.to_pixel_point(anchor, &snapshot, window);
 6549        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6550            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6551        };
 6552    }
 6553
 6554    fn show_blame_popover(
 6555        &mut self,
 6556        blame_entry: &BlameEntry,
 6557        position: gpui::Point<Pixels>,
 6558        ignore_timeout: bool,
 6559        cx: &mut Context<Self>,
 6560    ) {
 6561        if let Some(state) = &mut self.inline_blame_popover {
 6562            state.hide_task.take();
 6563        } else {
 6564            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6565            let blame_entry = blame_entry.clone();
 6566            let show_task = cx.spawn(async move |editor, cx| {
 6567                if !ignore_timeout {
 6568                    cx.background_executor()
 6569                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6570                        .await;
 6571                }
 6572                editor
 6573                    .update(cx, |editor, cx| {
 6574                        editor.inline_blame_popover_show_task.take();
 6575                        let Some(blame) = editor.blame.as_ref() else {
 6576                            return;
 6577                        };
 6578                        let blame = blame.read(cx);
 6579                        let details = blame.details_for_entry(&blame_entry);
 6580                        let markdown = cx.new(|cx| {
 6581                            Markdown::new(
 6582                                details
 6583                                    .as_ref()
 6584                                    .map(|message| message.message.clone())
 6585                                    .unwrap_or_default(),
 6586                                None,
 6587                                None,
 6588                                cx,
 6589                            )
 6590                        });
 6591                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6592                            position,
 6593                            hide_task: None,
 6594                            popover_bounds: None,
 6595                            popover_state: InlineBlamePopoverState {
 6596                                scroll_handle: ScrollHandle::new(),
 6597                                commit_message: details,
 6598                                markdown,
 6599                            },
 6600                            keyboard_grace: ignore_timeout,
 6601                        });
 6602                        cx.notify();
 6603                    })
 6604                    .ok();
 6605            });
 6606            self.inline_blame_popover_show_task = Some(show_task);
 6607        }
 6608    }
 6609
 6610    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6611        self.inline_blame_popover_show_task.take();
 6612        if let Some(state) = &mut self.inline_blame_popover {
 6613            let hide_task = cx.spawn(async move |editor, cx| {
 6614                cx.background_executor()
 6615                    .timer(std::time::Duration::from_millis(100))
 6616                    .await;
 6617                editor
 6618                    .update(cx, |editor, cx| {
 6619                        editor.inline_blame_popover.take();
 6620                        cx.notify();
 6621                    })
 6622                    .ok();
 6623            });
 6624            state.hide_task = Some(hide_task);
 6625        }
 6626    }
 6627
 6628    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6629        if self.pending_rename.is_some() {
 6630            return None;
 6631        }
 6632
 6633        let provider = self.semantics_provider.clone()?;
 6634        let buffer = self.buffer.read(cx);
 6635        let newest_selection = self.selections.newest_anchor().clone();
 6636        let cursor_position = newest_selection.head();
 6637        let (cursor_buffer, cursor_buffer_position) =
 6638            buffer.text_anchor_for_position(cursor_position, cx)?;
 6639        let (tail_buffer, tail_buffer_position) =
 6640            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6641        if cursor_buffer != tail_buffer {
 6642            return None;
 6643        }
 6644
 6645        let snapshot = cursor_buffer.read(cx).snapshot();
 6646        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6647        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6648        if start_word_range != end_word_range {
 6649            self.document_highlights_task.take();
 6650            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6651            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6652            return None;
 6653        }
 6654
 6655        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6656        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6657            cx.background_executor()
 6658                .timer(Duration::from_millis(debounce))
 6659                .await;
 6660
 6661            let highlights = if let Some(highlights) = cx
 6662                .update(|cx| {
 6663                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6664                })
 6665                .ok()
 6666                .flatten()
 6667            {
 6668                highlights.await.log_err()
 6669            } else {
 6670                None
 6671            };
 6672
 6673            if let Some(highlights) = highlights {
 6674                this.update(cx, |this, cx| {
 6675                    if this.pending_rename.is_some() {
 6676                        return;
 6677                    }
 6678
 6679                    let buffer_id = cursor_position.buffer_id;
 6680                    let buffer = this.buffer.read(cx);
 6681                    if !buffer
 6682                        .text_anchor_for_position(cursor_position, cx)
 6683                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6684                    {
 6685                        return;
 6686                    }
 6687
 6688                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6689                    let mut write_ranges = Vec::new();
 6690                    let mut read_ranges = Vec::new();
 6691                    for highlight in highlights {
 6692                        for (excerpt_id, excerpt_range) in
 6693                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6694                        {
 6695                            let start = highlight
 6696                                .range
 6697                                .start
 6698                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6699                            let end = highlight
 6700                                .range
 6701                                .end
 6702                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6703                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6704                                continue;
 6705                            }
 6706
 6707                            let range = Anchor {
 6708                                buffer_id,
 6709                                excerpt_id,
 6710                                text_anchor: start,
 6711                                diff_base_anchor: None,
 6712                            }..Anchor {
 6713                                buffer_id,
 6714                                excerpt_id,
 6715                                text_anchor: end,
 6716                                diff_base_anchor: None,
 6717                            };
 6718                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6719                                write_ranges.push(range);
 6720                            } else {
 6721                                read_ranges.push(range);
 6722                            }
 6723                        }
 6724                    }
 6725
 6726                    this.highlight_background::<DocumentHighlightRead>(
 6727                        &read_ranges,
 6728                        |theme| theme.colors().editor_document_highlight_read_background,
 6729                        cx,
 6730                    );
 6731                    this.highlight_background::<DocumentHighlightWrite>(
 6732                        &write_ranges,
 6733                        |theme| theme.colors().editor_document_highlight_write_background,
 6734                        cx,
 6735                    );
 6736                    cx.notify();
 6737                })
 6738                .log_err();
 6739            }
 6740        }));
 6741        None
 6742    }
 6743
 6744    fn prepare_highlight_query_from_selection(
 6745        &mut self,
 6746        cx: &mut Context<Editor>,
 6747    ) -> Option<(String, Range<Anchor>)> {
 6748        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6749            return None;
 6750        }
 6751        if !EditorSettings::get_global(cx).selection_highlight {
 6752            return None;
 6753        }
 6754        if self.selections.count() != 1 || self.selections.line_mode {
 6755            return None;
 6756        }
 6757        let selection = self.selections.newest::<Point>(cx);
 6758        if selection.is_empty() || selection.start.row != selection.end.row {
 6759            return None;
 6760        }
 6761        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6762        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6763        let query = multi_buffer_snapshot
 6764            .text_for_range(selection_anchor_range.clone())
 6765            .collect::<String>();
 6766        if query.trim().is_empty() {
 6767            return None;
 6768        }
 6769        Some((query, selection_anchor_range))
 6770    }
 6771
 6772    fn update_selection_occurrence_highlights(
 6773        &mut self,
 6774        query_text: String,
 6775        query_range: Range<Anchor>,
 6776        multi_buffer_range_to_query: Range<Point>,
 6777        use_debounce: bool,
 6778        window: &mut Window,
 6779        cx: &mut Context<Editor>,
 6780    ) -> Task<()> {
 6781        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6782        cx.spawn_in(window, async move |editor, cx| {
 6783            if use_debounce {
 6784                cx.background_executor()
 6785                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6786                    .await;
 6787            }
 6788            let match_task = cx.background_spawn(async move {
 6789                let buffer_ranges = multi_buffer_snapshot
 6790                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6791                    .into_iter()
 6792                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6793                let mut match_ranges = Vec::new();
 6794                let Ok(regex) = project::search::SearchQuery::text(
 6795                    query_text.clone(),
 6796                    false,
 6797                    false,
 6798                    false,
 6799                    Default::default(),
 6800                    Default::default(),
 6801                    false,
 6802                    None,
 6803                ) else {
 6804                    return Vec::default();
 6805                };
 6806                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6807                    match_ranges.extend(
 6808                        regex
 6809                            .search(&buffer_snapshot, Some(search_range.clone()))
 6810                            .await
 6811                            .into_iter()
 6812                            .filter_map(|match_range| {
 6813                                let match_start = buffer_snapshot
 6814                                    .anchor_after(search_range.start + match_range.start);
 6815                                let match_end = buffer_snapshot
 6816                                    .anchor_before(search_range.start + match_range.end);
 6817                                let match_anchor_range = Anchor::range_in_buffer(
 6818                                    excerpt_id,
 6819                                    buffer_snapshot.remote_id(),
 6820                                    match_start..match_end,
 6821                                );
 6822                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6823                            }),
 6824                    );
 6825                }
 6826                match_ranges
 6827            });
 6828            let match_ranges = match_task.await;
 6829            editor
 6830                .update_in(cx, |editor, _, cx| {
 6831                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6832                    if !match_ranges.is_empty() {
 6833                        editor.highlight_background::<SelectedTextHighlight>(
 6834                            &match_ranges,
 6835                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6836                            cx,
 6837                        )
 6838                    }
 6839                })
 6840                .log_err();
 6841        })
 6842    }
 6843
 6844    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6845        struct NewlineFold;
 6846        let type_id = std::any::TypeId::of::<NewlineFold>();
 6847        if !self.mode.is_single_line() {
 6848            return;
 6849        }
 6850        let snapshot = self.snapshot(window, cx);
 6851        if snapshot.buffer_snapshot.max_point().row == 0 {
 6852            return;
 6853        }
 6854        let task = cx.background_spawn(async move {
 6855            let new_newlines = snapshot
 6856                .buffer_chars_at(0)
 6857                .filter_map(|(c, i)| {
 6858                    if c == '\n' {
 6859                        Some(
 6860                            snapshot.buffer_snapshot.anchor_after(i)
 6861                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6862                        )
 6863                    } else {
 6864                        None
 6865                    }
 6866                })
 6867                .collect::<Vec<_>>();
 6868            let existing_newlines = snapshot
 6869                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6870                .filter_map(|fold| {
 6871                    if fold.placeholder.type_tag == Some(type_id) {
 6872                        Some(fold.range.start..fold.range.end)
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878
 6879            (new_newlines, existing_newlines)
 6880        });
 6881        self.folding_newlines = cx.spawn(async move |this, cx| {
 6882            let (new_newlines, existing_newlines) = task.await;
 6883            if new_newlines == existing_newlines {
 6884                return;
 6885            }
 6886            let placeholder = FoldPlaceholder {
 6887                render: Arc::new(move |_, _, cx| {
 6888                    div()
 6889                        .bg(cx.theme().status().hint_background)
 6890                        .border_b_1()
 6891                        .size_full()
 6892                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6893                        .border_color(cx.theme().status().hint)
 6894                        .child("\\n")
 6895                        .into_any()
 6896                }),
 6897                constrain_width: false,
 6898                merge_adjacent: false,
 6899                type_tag: Some(type_id),
 6900            };
 6901            let creases = new_newlines
 6902                .into_iter()
 6903                .map(|range| Crease::simple(range, placeholder.clone()))
 6904                .collect();
 6905            this.update(cx, |this, cx| {
 6906                this.display_map.update(cx, |display_map, cx| {
 6907                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6908                    display_map.fold(creases, cx);
 6909                });
 6910            })
 6911            .ok();
 6912        });
 6913    }
 6914
 6915    fn refresh_selected_text_highlights(
 6916        &mut self,
 6917        on_buffer_edit: bool,
 6918        window: &mut Window,
 6919        cx: &mut Context<Editor>,
 6920    ) {
 6921        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6922        else {
 6923            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6924            self.quick_selection_highlight_task.take();
 6925            self.debounced_selection_highlight_task.take();
 6926            return;
 6927        };
 6928        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6929        if on_buffer_edit
 6930            || self
 6931                .quick_selection_highlight_task
 6932                .as_ref()
 6933                .map_or(true, |(prev_anchor_range, _)| {
 6934                    prev_anchor_range != &query_range
 6935                })
 6936        {
 6937            let multi_buffer_visible_start = self
 6938                .scroll_manager
 6939                .anchor()
 6940                .anchor
 6941                .to_point(&multi_buffer_snapshot);
 6942            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6943                multi_buffer_visible_start
 6944                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6945                Bias::Left,
 6946            );
 6947            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6948            self.quick_selection_highlight_task = Some((
 6949                query_range.clone(),
 6950                self.update_selection_occurrence_highlights(
 6951                    query_text.clone(),
 6952                    query_range.clone(),
 6953                    multi_buffer_visible_range,
 6954                    false,
 6955                    window,
 6956                    cx,
 6957                ),
 6958            ));
 6959        }
 6960        if on_buffer_edit
 6961            || self
 6962                .debounced_selection_highlight_task
 6963                .as_ref()
 6964                .map_or(true, |(prev_anchor_range, _)| {
 6965                    prev_anchor_range != &query_range
 6966                })
 6967        {
 6968            let multi_buffer_start = multi_buffer_snapshot
 6969                .anchor_before(0)
 6970                .to_point(&multi_buffer_snapshot);
 6971            let multi_buffer_end = multi_buffer_snapshot
 6972                .anchor_after(multi_buffer_snapshot.len())
 6973                .to_point(&multi_buffer_snapshot);
 6974            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6975            self.debounced_selection_highlight_task = Some((
 6976                query_range.clone(),
 6977                self.update_selection_occurrence_highlights(
 6978                    query_text,
 6979                    query_range,
 6980                    multi_buffer_full_range,
 6981                    true,
 6982                    window,
 6983                    cx,
 6984                ),
 6985            ));
 6986        }
 6987    }
 6988
 6989    pub fn refresh_inline_completion(
 6990        &mut self,
 6991        debounce: bool,
 6992        user_requested: bool,
 6993        window: &mut Window,
 6994        cx: &mut Context<Self>,
 6995    ) -> Option<()> {
 6996        let provider = self.edit_prediction_provider()?;
 6997        let cursor = self.selections.newest_anchor().head();
 6998        let (buffer, cursor_buffer_position) =
 6999            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7000
 7001        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7002            self.discard_inline_completion(false, cx);
 7003            return None;
 7004        }
 7005
 7006        if !user_requested
 7007            && (!self.should_show_edit_predictions()
 7008                || !self.is_focused(window)
 7009                || buffer.read(cx).is_empty())
 7010        {
 7011            self.discard_inline_completion(false, cx);
 7012            return None;
 7013        }
 7014
 7015        self.update_visible_inline_completion(window, cx);
 7016        provider.refresh(
 7017            self.project.clone(),
 7018            buffer,
 7019            cursor_buffer_position,
 7020            debounce,
 7021            cx,
 7022        );
 7023        Some(())
 7024    }
 7025
 7026    fn show_edit_predictions_in_menu(&self) -> bool {
 7027        match self.edit_prediction_settings {
 7028            EditPredictionSettings::Disabled => false,
 7029            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7030        }
 7031    }
 7032
 7033    pub fn edit_predictions_enabled(&self) -> bool {
 7034        match self.edit_prediction_settings {
 7035            EditPredictionSettings::Disabled => false,
 7036            EditPredictionSettings::Enabled { .. } => true,
 7037        }
 7038    }
 7039
 7040    fn edit_prediction_requires_modifier(&self) -> bool {
 7041        match self.edit_prediction_settings {
 7042            EditPredictionSettings::Disabled => false,
 7043            EditPredictionSettings::Enabled {
 7044                preview_requires_modifier,
 7045                ..
 7046            } => preview_requires_modifier,
 7047        }
 7048    }
 7049
 7050    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7051        if self.edit_prediction_provider.is_none() {
 7052            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7053        } else {
 7054            let selection = self.selections.newest_anchor();
 7055            let cursor = selection.head();
 7056
 7057            if let Some((buffer, cursor_buffer_position)) =
 7058                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7059            {
 7060                self.edit_prediction_settings =
 7061                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7062            }
 7063        }
 7064    }
 7065
 7066    fn edit_prediction_settings_at_position(
 7067        &self,
 7068        buffer: &Entity<Buffer>,
 7069        buffer_position: language::Anchor,
 7070        cx: &App,
 7071    ) -> EditPredictionSettings {
 7072        if !self.mode.is_full()
 7073            || !self.show_inline_completions_override.unwrap_or(true)
 7074            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7075        {
 7076            return EditPredictionSettings::Disabled;
 7077        }
 7078
 7079        let buffer = buffer.read(cx);
 7080
 7081        let file = buffer.file();
 7082
 7083        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7084            return EditPredictionSettings::Disabled;
 7085        };
 7086
 7087        let by_provider = matches!(
 7088            self.menu_inline_completions_policy,
 7089            MenuInlineCompletionsPolicy::ByProvider
 7090        );
 7091
 7092        let show_in_menu = by_provider
 7093            && self
 7094                .edit_prediction_provider
 7095                .as_ref()
 7096                .map_or(false, |provider| {
 7097                    provider.provider.show_completions_in_menu()
 7098                });
 7099
 7100        let preview_requires_modifier =
 7101            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7102
 7103        EditPredictionSettings::Enabled {
 7104            show_in_menu,
 7105            preview_requires_modifier,
 7106        }
 7107    }
 7108
 7109    fn should_show_edit_predictions(&self) -> bool {
 7110        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7111    }
 7112
 7113    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7114        matches!(
 7115            self.edit_prediction_preview,
 7116            EditPredictionPreview::Active { .. }
 7117        )
 7118    }
 7119
 7120    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7121        let cursor = self.selections.newest_anchor().head();
 7122        if let Some((buffer, cursor_position)) =
 7123            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7124        {
 7125            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7126        } else {
 7127            false
 7128        }
 7129    }
 7130
 7131    pub fn supports_minimap(&self, cx: &App) -> bool {
 7132        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7133    }
 7134
 7135    fn edit_predictions_enabled_in_buffer(
 7136        &self,
 7137        buffer: &Entity<Buffer>,
 7138        buffer_position: language::Anchor,
 7139        cx: &App,
 7140    ) -> bool {
 7141        maybe!({
 7142            if self.read_only(cx) {
 7143                return Some(false);
 7144            }
 7145            let provider = self.edit_prediction_provider()?;
 7146            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7147                return Some(false);
 7148            }
 7149            let buffer = buffer.read(cx);
 7150            let Some(file) = buffer.file() else {
 7151                return Some(true);
 7152            };
 7153            let settings = all_language_settings(Some(file), cx);
 7154            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7155        })
 7156        .unwrap_or(false)
 7157    }
 7158
 7159    fn cycle_inline_completion(
 7160        &mut self,
 7161        direction: Direction,
 7162        window: &mut Window,
 7163        cx: &mut Context<Self>,
 7164    ) -> Option<()> {
 7165        let provider = self.edit_prediction_provider()?;
 7166        let cursor = self.selections.newest_anchor().head();
 7167        let (buffer, cursor_buffer_position) =
 7168            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7169        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7170            return None;
 7171        }
 7172
 7173        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7174        self.update_visible_inline_completion(window, cx);
 7175
 7176        Some(())
 7177    }
 7178
 7179    pub fn show_inline_completion(
 7180        &mut self,
 7181        _: &ShowEditPrediction,
 7182        window: &mut Window,
 7183        cx: &mut Context<Self>,
 7184    ) {
 7185        if !self.has_active_inline_completion() {
 7186            self.refresh_inline_completion(false, true, window, cx);
 7187            return;
 7188        }
 7189
 7190        self.update_visible_inline_completion(window, cx);
 7191    }
 7192
 7193    pub fn display_cursor_names(
 7194        &mut self,
 7195        _: &DisplayCursorNames,
 7196        window: &mut Window,
 7197        cx: &mut Context<Self>,
 7198    ) {
 7199        self.show_cursor_names(window, cx);
 7200    }
 7201
 7202    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7203        self.show_cursor_names = true;
 7204        cx.notify();
 7205        cx.spawn_in(window, async move |this, cx| {
 7206            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7207            this.update(cx, |this, cx| {
 7208                this.show_cursor_names = false;
 7209                cx.notify()
 7210            })
 7211            .ok()
 7212        })
 7213        .detach();
 7214    }
 7215
 7216    pub fn next_edit_prediction(
 7217        &mut self,
 7218        _: &NextEditPrediction,
 7219        window: &mut Window,
 7220        cx: &mut Context<Self>,
 7221    ) {
 7222        if self.has_active_inline_completion() {
 7223            self.cycle_inline_completion(Direction::Next, window, cx);
 7224        } else {
 7225            let is_copilot_disabled = self
 7226                .refresh_inline_completion(false, true, window, cx)
 7227                .is_none();
 7228            if is_copilot_disabled {
 7229                cx.propagate();
 7230            }
 7231        }
 7232    }
 7233
 7234    pub fn previous_edit_prediction(
 7235        &mut self,
 7236        _: &PreviousEditPrediction,
 7237        window: &mut Window,
 7238        cx: &mut Context<Self>,
 7239    ) {
 7240        if self.has_active_inline_completion() {
 7241            self.cycle_inline_completion(Direction::Prev, window, cx);
 7242        } else {
 7243            let is_copilot_disabled = self
 7244                .refresh_inline_completion(false, true, window, cx)
 7245                .is_none();
 7246            if is_copilot_disabled {
 7247                cx.propagate();
 7248            }
 7249        }
 7250    }
 7251
 7252    pub fn accept_edit_prediction(
 7253        &mut self,
 7254        _: &AcceptEditPrediction,
 7255        window: &mut Window,
 7256        cx: &mut Context<Self>,
 7257    ) {
 7258        if self.show_edit_predictions_in_menu() {
 7259            self.hide_context_menu(window, cx);
 7260        }
 7261
 7262        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7263            return;
 7264        };
 7265
 7266        self.report_inline_completion_event(
 7267            active_inline_completion.completion_id.clone(),
 7268            true,
 7269            cx,
 7270        );
 7271
 7272        match &active_inline_completion.completion {
 7273            InlineCompletion::Move { target, .. } => {
 7274                let target = *target;
 7275
 7276                if let Some(position_map) = &self.last_position_map {
 7277                    if position_map
 7278                        .visible_row_range
 7279                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7280                        || !self.edit_prediction_requires_modifier()
 7281                    {
 7282                        self.unfold_ranges(&[target..target], true, false, cx);
 7283                        // Note that this is also done in vim's handler of the Tab action.
 7284                        self.change_selections(
 7285                            SelectionEffects::scroll(Autoscroll::newest()),
 7286                            window,
 7287                            cx,
 7288                            |selections| {
 7289                                selections.select_anchor_ranges([target..target]);
 7290                            },
 7291                        );
 7292                        self.clear_row_highlights::<EditPredictionPreview>();
 7293
 7294                        self.edit_prediction_preview
 7295                            .set_previous_scroll_position(None);
 7296                    } else {
 7297                        self.edit_prediction_preview
 7298                            .set_previous_scroll_position(Some(
 7299                                position_map.snapshot.scroll_anchor,
 7300                            ));
 7301
 7302                        self.highlight_rows::<EditPredictionPreview>(
 7303                            target..target,
 7304                            cx.theme().colors().editor_highlighted_line_background,
 7305                            RowHighlightOptions {
 7306                                autoscroll: true,
 7307                                ..Default::default()
 7308                            },
 7309                            cx,
 7310                        );
 7311                        self.request_autoscroll(Autoscroll::fit(), cx);
 7312                    }
 7313                }
 7314            }
 7315            InlineCompletion::Edit { edits, .. } => {
 7316                if let Some(provider) = self.edit_prediction_provider() {
 7317                    provider.accept(cx);
 7318                }
 7319
 7320                // Store the transaction ID and selections before applying the edit
 7321                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7322
 7323                let snapshot = self.buffer.read(cx).snapshot(cx);
 7324                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7325
 7326                self.buffer.update(cx, |buffer, cx| {
 7327                    buffer.edit(edits.iter().cloned(), None, cx)
 7328                });
 7329
 7330                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7331                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7332                });
 7333
 7334                let selections = self.selections.disjoint_anchors();
 7335                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7336                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7337                    if has_new_transaction {
 7338                        self.selection_history
 7339                            .insert_transaction(transaction_id_now, selections);
 7340                    }
 7341                }
 7342
 7343                self.update_visible_inline_completion(window, cx);
 7344                if self.active_inline_completion.is_none() {
 7345                    self.refresh_inline_completion(true, true, window, cx);
 7346                }
 7347
 7348                cx.notify();
 7349            }
 7350        }
 7351
 7352        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7353    }
 7354
 7355    pub fn accept_partial_inline_completion(
 7356        &mut self,
 7357        _: &AcceptPartialEditPrediction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) {
 7361        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7362            return;
 7363        };
 7364        if self.selections.count() != 1 {
 7365            return;
 7366        }
 7367
 7368        self.report_inline_completion_event(
 7369            active_inline_completion.completion_id.clone(),
 7370            true,
 7371            cx,
 7372        );
 7373
 7374        match &active_inline_completion.completion {
 7375            InlineCompletion::Move { target, .. } => {
 7376                let target = *target;
 7377                self.change_selections(
 7378                    SelectionEffects::scroll(Autoscroll::newest()),
 7379                    window,
 7380                    cx,
 7381                    |selections| {
 7382                        selections.select_anchor_ranges([target..target]);
 7383                    },
 7384                );
 7385            }
 7386            InlineCompletion::Edit { edits, .. } => {
 7387                // Find an insertion that starts at the cursor position.
 7388                let snapshot = self.buffer.read(cx).snapshot(cx);
 7389                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7390                let insertion = edits.iter().find_map(|(range, text)| {
 7391                    let range = range.to_offset(&snapshot);
 7392                    if range.is_empty() && range.start == cursor_offset {
 7393                        Some(text)
 7394                    } else {
 7395                        None
 7396                    }
 7397                });
 7398
 7399                if let Some(text) = insertion {
 7400                    let mut partial_completion = text
 7401                        .chars()
 7402                        .by_ref()
 7403                        .take_while(|c| c.is_alphabetic())
 7404                        .collect::<String>();
 7405                    if partial_completion.is_empty() {
 7406                        partial_completion = text
 7407                            .chars()
 7408                            .by_ref()
 7409                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7410                            .collect::<String>();
 7411                    }
 7412
 7413                    cx.emit(EditorEvent::InputHandled {
 7414                        utf16_range_to_replace: None,
 7415                        text: partial_completion.clone().into(),
 7416                    });
 7417
 7418                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7419
 7420                    self.refresh_inline_completion(true, true, window, cx);
 7421                    cx.notify();
 7422                } else {
 7423                    self.accept_edit_prediction(&Default::default(), window, cx);
 7424                }
 7425            }
 7426        }
 7427    }
 7428
 7429    fn discard_inline_completion(
 7430        &mut self,
 7431        should_report_inline_completion_event: bool,
 7432        cx: &mut Context<Self>,
 7433    ) -> bool {
 7434        if should_report_inline_completion_event {
 7435            let completion_id = self
 7436                .active_inline_completion
 7437                .as_ref()
 7438                .and_then(|active_completion| active_completion.completion_id.clone());
 7439
 7440            self.report_inline_completion_event(completion_id, false, cx);
 7441        }
 7442
 7443        if let Some(provider) = self.edit_prediction_provider() {
 7444            provider.discard(cx);
 7445        }
 7446
 7447        self.take_active_inline_completion(cx)
 7448    }
 7449
 7450    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7451        let Some(provider) = self.edit_prediction_provider() else {
 7452            return;
 7453        };
 7454
 7455        let Some((_, buffer, _)) = self
 7456            .buffer
 7457            .read(cx)
 7458            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7459        else {
 7460            return;
 7461        };
 7462
 7463        let extension = buffer
 7464            .read(cx)
 7465            .file()
 7466            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7467
 7468        let event_type = match accepted {
 7469            true => "Edit Prediction Accepted",
 7470            false => "Edit Prediction Discarded",
 7471        };
 7472        telemetry::event!(
 7473            event_type,
 7474            provider = provider.name(),
 7475            prediction_id = id,
 7476            suggestion_accepted = accepted,
 7477            file_extension = extension,
 7478        );
 7479    }
 7480
 7481    pub fn has_active_inline_completion(&self) -> bool {
 7482        self.active_inline_completion.is_some()
 7483    }
 7484
 7485    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7486        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7487            return false;
 7488        };
 7489
 7490        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7491        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7492        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7493        true
 7494    }
 7495
 7496    /// Returns true when we're displaying the edit prediction popover below the cursor
 7497    /// like we are not previewing and the LSP autocomplete menu is visible
 7498    /// or we are in `when_holding_modifier` mode.
 7499    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7500        if self.edit_prediction_preview_is_active()
 7501            || !self.show_edit_predictions_in_menu()
 7502            || !self.edit_predictions_enabled()
 7503        {
 7504            return false;
 7505        }
 7506
 7507        if self.has_visible_completions_menu() {
 7508            return true;
 7509        }
 7510
 7511        has_completion && self.edit_prediction_requires_modifier()
 7512    }
 7513
 7514    fn handle_modifiers_changed(
 7515        &mut self,
 7516        modifiers: Modifiers,
 7517        position_map: &PositionMap,
 7518        window: &mut Window,
 7519        cx: &mut Context<Self>,
 7520    ) {
 7521        if self.show_edit_predictions_in_menu() {
 7522            self.update_edit_prediction_preview(&modifiers, window, cx);
 7523        }
 7524
 7525        self.update_selection_mode(&modifiers, position_map, window, cx);
 7526
 7527        let mouse_position = window.mouse_position();
 7528        if !position_map.text_hitbox.is_hovered(window) {
 7529            return;
 7530        }
 7531
 7532        self.update_hovered_link(
 7533            position_map.point_for_position(mouse_position),
 7534            &position_map.snapshot,
 7535            modifiers,
 7536            window,
 7537            cx,
 7538        )
 7539    }
 7540
 7541    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7542        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7543        if invert {
 7544            match multi_cursor_setting {
 7545                MultiCursorModifier::Alt => modifiers.alt,
 7546                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7547            }
 7548        } else {
 7549            match multi_cursor_setting {
 7550                MultiCursorModifier::Alt => modifiers.secondary(),
 7551                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7552            }
 7553        }
 7554    }
 7555
 7556    fn columnar_selection_mode(
 7557        modifiers: &Modifiers,
 7558        cx: &mut Context<Self>,
 7559    ) -> Option<ColumnarMode> {
 7560        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7561            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7562                Some(ColumnarMode::FromMouse)
 7563            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7564                Some(ColumnarMode::FromSelection)
 7565            } else {
 7566                None
 7567            }
 7568        } else {
 7569            None
 7570        }
 7571    }
 7572
 7573    fn update_selection_mode(
 7574        &mut self,
 7575        modifiers: &Modifiers,
 7576        position_map: &PositionMap,
 7577        window: &mut Window,
 7578        cx: &mut Context<Self>,
 7579    ) {
 7580        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7581            return;
 7582        };
 7583        if self.selections.pending.is_none() {
 7584            return;
 7585        }
 7586
 7587        let mouse_position = window.mouse_position();
 7588        let point_for_position = position_map.point_for_position(mouse_position);
 7589        let position = point_for_position.previous_valid;
 7590
 7591        self.select(
 7592            SelectPhase::BeginColumnar {
 7593                position,
 7594                reset: false,
 7595                mode,
 7596                goal_column: point_for_position.exact_unclipped.column(),
 7597            },
 7598            window,
 7599            cx,
 7600        );
 7601    }
 7602
 7603    fn update_edit_prediction_preview(
 7604        &mut self,
 7605        modifiers: &Modifiers,
 7606        window: &mut Window,
 7607        cx: &mut Context<Self>,
 7608    ) {
 7609        let mut modifiers_held = false;
 7610        if let Some(accept_keystroke) = self
 7611            .accept_edit_prediction_keybind(false, window, cx)
 7612            .keystroke()
 7613        {
 7614            modifiers_held = modifiers_held
 7615                || (&accept_keystroke.modifiers == modifiers
 7616                    && accept_keystroke.modifiers.modified());
 7617        };
 7618        if let Some(accept_partial_keystroke) = self
 7619            .accept_edit_prediction_keybind(true, window, cx)
 7620            .keystroke()
 7621        {
 7622            modifiers_held = modifiers_held
 7623                || (&accept_partial_keystroke.modifiers == modifiers
 7624                    && accept_partial_keystroke.modifiers.modified());
 7625        }
 7626
 7627        if modifiers_held {
 7628            if matches!(
 7629                self.edit_prediction_preview,
 7630                EditPredictionPreview::Inactive { .. }
 7631            ) {
 7632                self.edit_prediction_preview = EditPredictionPreview::Active {
 7633                    previous_scroll_position: None,
 7634                    since: Instant::now(),
 7635                };
 7636
 7637                self.update_visible_inline_completion(window, cx);
 7638                cx.notify();
 7639            }
 7640        } else if let EditPredictionPreview::Active {
 7641            previous_scroll_position,
 7642            since,
 7643        } = self.edit_prediction_preview
 7644        {
 7645            if let (Some(previous_scroll_position), Some(position_map)) =
 7646                (previous_scroll_position, self.last_position_map.as_ref())
 7647            {
 7648                self.set_scroll_position(
 7649                    previous_scroll_position
 7650                        .scroll_position(&position_map.snapshot.display_snapshot),
 7651                    window,
 7652                    cx,
 7653                );
 7654            }
 7655
 7656            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7657                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7658            };
 7659            self.clear_row_highlights::<EditPredictionPreview>();
 7660            self.update_visible_inline_completion(window, cx);
 7661            cx.notify();
 7662        }
 7663    }
 7664
 7665    fn update_visible_inline_completion(
 7666        &mut self,
 7667        _window: &mut Window,
 7668        cx: &mut Context<Self>,
 7669    ) -> Option<()> {
 7670        let selection = self.selections.newest_anchor();
 7671        let cursor = selection.head();
 7672        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7673        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7674        let excerpt_id = cursor.excerpt_id;
 7675
 7676        let show_in_menu = self.show_edit_predictions_in_menu();
 7677        let completions_menu_has_precedence = !show_in_menu
 7678            && (self.context_menu.borrow().is_some()
 7679                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7680
 7681        if completions_menu_has_precedence
 7682            || !offset_selection.is_empty()
 7683            || self
 7684                .active_inline_completion
 7685                .as_ref()
 7686                .map_or(false, |completion| {
 7687                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7688                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7689                    !invalidation_range.contains(&offset_selection.head())
 7690                })
 7691        {
 7692            self.discard_inline_completion(false, cx);
 7693            return None;
 7694        }
 7695
 7696        self.take_active_inline_completion(cx);
 7697        let Some(provider) = self.edit_prediction_provider() else {
 7698            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7699            return None;
 7700        };
 7701
 7702        let (buffer, cursor_buffer_position) =
 7703            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7704
 7705        self.edit_prediction_settings =
 7706            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7707
 7708        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7709
 7710        if self.edit_prediction_indent_conflict {
 7711            let cursor_point = cursor.to_point(&multibuffer);
 7712
 7713            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7714
 7715            if let Some((_, indent)) = indents.iter().next() {
 7716                if indent.len == cursor_point.column {
 7717                    self.edit_prediction_indent_conflict = false;
 7718                }
 7719            }
 7720        }
 7721
 7722        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7723        let edits = inline_completion
 7724            .edits
 7725            .into_iter()
 7726            .flat_map(|(range, new_text)| {
 7727                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7728                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7729                Some((start..end, new_text))
 7730            })
 7731            .collect::<Vec<_>>();
 7732        if edits.is_empty() {
 7733            return None;
 7734        }
 7735
 7736        let first_edit_start = edits.first().unwrap().0.start;
 7737        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7738        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7739
 7740        let last_edit_end = edits.last().unwrap().0.end;
 7741        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7742        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7743
 7744        let cursor_row = cursor.to_point(&multibuffer).row;
 7745
 7746        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7747
 7748        let mut inlay_ids = Vec::new();
 7749        let invalidation_row_range;
 7750        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7751            Some(cursor_row..edit_end_row)
 7752        } else if cursor_row > edit_end_row {
 7753            Some(edit_start_row..cursor_row)
 7754        } else {
 7755            None
 7756        };
 7757        let is_move =
 7758            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7759        let completion = if is_move {
 7760            invalidation_row_range =
 7761                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7762            let target = first_edit_start;
 7763            InlineCompletion::Move { target, snapshot }
 7764        } else {
 7765            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7766                && !self.inline_completions_hidden_for_vim_mode;
 7767
 7768            if show_completions_in_buffer {
 7769                if edits
 7770                    .iter()
 7771                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7772                {
 7773                    let mut inlays = Vec::new();
 7774                    for (range, new_text) in &edits {
 7775                        let inlay = Inlay::inline_completion(
 7776                            post_inc(&mut self.next_inlay_id),
 7777                            range.start,
 7778                            new_text.as_str(),
 7779                        );
 7780                        inlay_ids.push(inlay.id);
 7781                        inlays.push(inlay);
 7782                    }
 7783
 7784                    self.splice_inlays(&[], inlays, cx);
 7785                } else {
 7786                    let background_color = cx.theme().status().deleted_background;
 7787                    self.highlight_text::<InlineCompletionHighlight>(
 7788                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7789                        HighlightStyle {
 7790                            background_color: Some(background_color),
 7791                            ..Default::default()
 7792                        },
 7793                        cx,
 7794                    );
 7795                }
 7796            }
 7797
 7798            invalidation_row_range = edit_start_row..edit_end_row;
 7799
 7800            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7801                if provider.show_tab_accept_marker() {
 7802                    EditDisplayMode::TabAccept
 7803                } else {
 7804                    EditDisplayMode::Inline
 7805                }
 7806            } else {
 7807                EditDisplayMode::DiffPopover
 7808            };
 7809
 7810            InlineCompletion::Edit {
 7811                edits,
 7812                edit_preview: inline_completion.edit_preview,
 7813                display_mode,
 7814                snapshot,
 7815            }
 7816        };
 7817
 7818        let invalidation_range = multibuffer
 7819            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7820            ..multibuffer.anchor_after(Point::new(
 7821                invalidation_row_range.end,
 7822                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7823            ));
 7824
 7825        self.stale_inline_completion_in_menu = None;
 7826        self.active_inline_completion = Some(InlineCompletionState {
 7827            inlay_ids,
 7828            completion,
 7829            completion_id: inline_completion.id,
 7830            invalidation_range,
 7831        });
 7832
 7833        cx.notify();
 7834
 7835        Some(())
 7836    }
 7837
 7838    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7839        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7840    }
 7841
 7842    fn clear_tasks(&mut self) {
 7843        self.tasks.clear()
 7844    }
 7845
 7846    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7847        if self.tasks.insert(key, value).is_some() {
 7848            // This case should hopefully be rare, but just in case...
 7849            log::error!(
 7850                "multiple different run targets found on a single line, only the last target will be rendered"
 7851            )
 7852        }
 7853    }
 7854
 7855    /// Get all display points of breakpoints that will be rendered within editor
 7856    ///
 7857    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7858    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7859    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7860    fn active_breakpoints(
 7861        &self,
 7862        range: Range<DisplayRow>,
 7863        window: &mut Window,
 7864        cx: &mut Context<Self>,
 7865    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7866        let mut breakpoint_display_points = HashMap::default();
 7867
 7868        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7869            return breakpoint_display_points;
 7870        };
 7871
 7872        let snapshot = self.snapshot(window, cx);
 7873
 7874        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7875        let Some(project) = self.project.as_ref() else {
 7876            return breakpoint_display_points;
 7877        };
 7878
 7879        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7880            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7881
 7882        for (buffer_snapshot, range, excerpt_id) in
 7883            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7884        {
 7885            let Some(buffer) = project
 7886                .read(cx)
 7887                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7888            else {
 7889                continue;
 7890            };
 7891            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7892                &buffer,
 7893                Some(
 7894                    buffer_snapshot.anchor_before(range.start)
 7895                        ..buffer_snapshot.anchor_after(range.end),
 7896                ),
 7897                buffer_snapshot,
 7898                cx,
 7899            );
 7900            for (breakpoint, state) in breakpoints {
 7901                let multi_buffer_anchor =
 7902                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7903                let position = multi_buffer_anchor
 7904                    .to_point(&multi_buffer_snapshot)
 7905                    .to_display_point(&snapshot);
 7906
 7907                breakpoint_display_points.insert(
 7908                    position.row(),
 7909                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7910                );
 7911            }
 7912        }
 7913
 7914        breakpoint_display_points
 7915    }
 7916
 7917    fn breakpoint_context_menu(
 7918        &self,
 7919        anchor: Anchor,
 7920        window: &mut Window,
 7921        cx: &mut Context<Self>,
 7922    ) -> Entity<ui::ContextMenu> {
 7923        let weak_editor = cx.weak_entity();
 7924        let focus_handle = self.focus_handle(cx);
 7925
 7926        let row = self
 7927            .buffer
 7928            .read(cx)
 7929            .snapshot(cx)
 7930            .summary_for_anchor::<Point>(&anchor)
 7931            .row;
 7932
 7933        let breakpoint = self
 7934            .breakpoint_at_row(row, window, cx)
 7935            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7936
 7937        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7938            "Edit Log Breakpoint"
 7939        } else {
 7940            "Set Log Breakpoint"
 7941        };
 7942
 7943        let condition_breakpoint_msg = if breakpoint
 7944            .as_ref()
 7945            .is_some_and(|bp| bp.1.condition.is_some())
 7946        {
 7947            "Edit Condition Breakpoint"
 7948        } else {
 7949            "Set Condition Breakpoint"
 7950        };
 7951
 7952        let hit_condition_breakpoint_msg = if breakpoint
 7953            .as_ref()
 7954            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7955        {
 7956            "Edit Hit Condition Breakpoint"
 7957        } else {
 7958            "Set Hit Condition Breakpoint"
 7959        };
 7960
 7961        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7962            "Unset Breakpoint"
 7963        } else {
 7964            "Set Breakpoint"
 7965        };
 7966
 7967        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7968
 7969        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7970            BreakpointState::Enabled => Some("Disable"),
 7971            BreakpointState::Disabled => Some("Enable"),
 7972        });
 7973
 7974        let (anchor, breakpoint) =
 7975            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7976
 7977        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7978            menu.on_blur_subscription(Subscription::new(|| {}))
 7979                .context(focus_handle)
 7980                .when(run_to_cursor, |this| {
 7981                    let weak_editor = weak_editor.clone();
 7982                    this.entry("Run to cursor", None, move |window, cx| {
 7983                        weak_editor
 7984                            .update(cx, |editor, cx| {
 7985                                editor.change_selections(
 7986                                    SelectionEffects::no_scroll(),
 7987                                    window,
 7988                                    cx,
 7989                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7990                                );
 7991                            })
 7992                            .ok();
 7993
 7994                        window.dispatch_action(Box::new(RunToCursor), cx);
 7995                    })
 7996                    .separator()
 7997                })
 7998                .when_some(toggle_state_msg, |this, msg| {
 7999                    this.entry(msg, None, {
 8000                        let weak_editor = weak_editor.clone();
 8001                        let breakpoint = breakpoint.clone();
 8002                        move |_window, cx| {
 8003                            weak_editor
 8004                                .update(cx, |this, cx| {
 8005                                    this.edit_breakpoint_at_anchor(
 8006                                        anchor,
 8007                                        breakpoint.as_ref().clone(),
 8008                                        BreakpointEditAction::InvertState,
 8009                                        cx,
 8010                                    );
 8011                                })
 8012                                .log_err();
 8013                        }
 8014                    })
 8015                })
 8016                .entry(set_breakpoint_msg, None, {
 8017                    let weak_editor = weak_editor.clone();
 8018                    let breakpoint = breakpoint.clone();
 8019                    move |_window, cx| {
 8020                        weak_editor
 8021                            .update(cx, |this, cx| {
 8022                                this.edit_breakpoint_at_anchor(
 8023                                    anchor,
 8024                                    breakpoint.as_ref().clone(),
 8025                                    BreakpointEditAction::Toggle,
 8026                                    cx,
 8027                                );
 8028                            })
 8029                            .log_err();
 8030                    }
 8031                })
 8032                .entry(log_breakpoint_msg, None, {
 8033                    let breakpoint = breakpoint.clone();
 8034                    let weak_editor = weak_editor.clone();
 8035                    move |window, cx| {
 8036                        weak_editor
 8037                            .update(cx, |this, cx| {
 8038                                this.add_edit_breakpoint_block(
 8039                                    anchor,
 8040                                    breakpoint.as_ref(),
 8041                                    BreakpointPromptEditAction::Log,
 8042                                    window,
 8043                                    cx,
 8044                                );
 8045                            })
 8046                            .log_err();
 8047                    }
 8048                })
 8049                .entry(condition_breakpoint_msg, None, {
 8050                    let breakpoint = breakpoint.clone();
 8051                    let weak_editor = weak_editor.clone();
 8052                    move |window, cx| {
 8053                        weak_editor
 8054                            .update(cx, |this, cx| {
 8055                                this.add_edit_breakpoint_block(
 8056                                    anchor,
 8057                                    breakpoint.as_ref(),
 8058                                    BreakpointPromptEditAction::Condition,
 8059                                    window,
 8060                                    cx,
 8061                                );
 8062                            })
 8063                            .log_err();
 8064                    }
 8065                })
 8066                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8067                    weak_editor
 8068                        .update(cx, |this, cx| {
 8069                            this.add_edit_breakpoint_block(
 8070                                anchor,
 8071                                breakpoint.as_ref(),
 8072                                BreakpointPromptEditAction::HitCondition,
 8073                                window,
 8074                                cx,
 8075                            );
 8076                        })
 8077                        .log_err();
 8078                })
 8079        })
 8080    }
 8081
 8082    fn render_breakpoint(
 8083        &self,
 8084        position: Anchor,
 8085        row: DisplayRow,
 8086        breakpoint: &Breakpoint,
 8087        state: Option<BreakpointSessionState>,
 8088        cx: &mut Context<Self>,
 8089    ) -> IconButton {
 8090        let is_rejected = state.is_some_and(|s| !s.verified);
 8091        // Is it a breakpoint that shows up when hovering over gutter?
 8092        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8093            (false, false),
 8094            |PhantomBreakpointIndicator {
 8095                 is_active,
 8096                 display_row,
 8097                 collides_with_existing_breakpoint,
 8098             }| {
 8099                (
 8100                    is_active && display_row == row,
 8101                    collides_with_existing_breakpoint,
 8102                )
 8103            },
 8104        );
 8105
 8106        let (color, icon) = {
 8107            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8108                (false, false) => ui::IconName::DebugBreakpoint,
 8109                (true, false) => ui::IconName::DebugLogBreakpoint,
 8110                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8111                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8112            };
 8113
 8114            let color = if is_phantom {
 8115                Color::Hint
 8116            } else if is_rejected {
 8117                Color::Disabled
 8118            } else {
 8119                Color::Debugger
 8120            };
 8121
 8122            (color, icon)
 8123        };
 8124
 8125        let breakpoint = Arc::from(breakpoint.clone());
 8126
 8127        let alt_as_text = gpui::Keystroke {
 8128            modifiers: Modifiers::secondary_key(),
 8129            ..Default::default()
 8130        };
 8131        let primary_action_text = if breakpoint.is_disabled() {
 8132            "Enable breakpoint"
 8133        } else if is_phantom && !collides_with_existing {
 8134            "Set breakpoint"
 8135        } else {
 8136            "Unset breakpoint"
 8137        };
 8138        let focus_handle = self.focus_handle.clone();
 8139
 8140        let meta = if is_rejected {
 8141            SharedString::from("No executable code is associated with this line.")
 8142        } else if collides_with_existing && !breakpoint.is_disabled() {
 8143            SharedString::from(format!(
 8144                "{alt_as_text}-click to disable,\nright-click for more options."
 8145            ))
 8146        } else {
 8147            SharedString::from("Right-click for more options.")
 8148        };
 8149        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8150            .icon_size(IconSize::XSmall)
 8151            .size(ui::ButtonSize::None)
 8152            .when(is_rejected, |this| {
 8153                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8154            })
 8155            .icon_color(color)
 8156            .style(ButtonStyle::Transparent)
 8157            .on_click(cx.listener({
 8158                let breakpoint = breakpoint.clone();
 8159
 8160                move |editor, event: &ClickEvent, window, cx| {
 8161                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8162                        BreakpointEditAction::InvertState
 8163                    } else {
 8164                        BreakpointEditAction::Toggle
 8165                    };
 8166
 8167                    window.focus(&editor.focus_handle(cx));
 8168                    editor.edit_breakpoint_at_anchor(
 8169                        position,
 8170                        breakpoint.as_ref().clone(),
 8171                        edit_action,
 8172                        cx,
 8173                    );
 8174                }
 8175            }))
 8176            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8177                editor.set_breakpoint_context_menu(
 8178                    row,
 8179                    Some(position),
 8180                    event.down.position,
 8181                    window,
 8182                    cx,
 8183                );
 8184            }))
 8185            .tooltip(move |window, cx| {
 8186                Tooltip::with_meta_in(
 8187                    primary_action_text,
 8188                    Some(&ToggleBreakpoint),
 8189                    meta.clone(),
 8190                    &focus_handle,
 8191                    window,
 8192                    cx,
 8193                )
 8194            })
 8195    }
 8196
 8197    fn build_tasks_context(
 8198        project: &Entity<Project>,
 8199        buffer: &Entity<Buffer>,
 8200        buffer_row: u32,
 8201        tasks: &Arc<RunnableTasks>,
 8202        cx: &mut Context<Self>,
 8203    ) -> Task<Option<task::TaskContext>> {
 8204        let position = Point::new(buffer_row, tasks.column);
 8205        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8206        let location = Location {
 8207            buffer: buffer.clone(),
 8208            range: range_start..range_start,
 8209        };
 8210        // Fill in the environmental variables from the tree-sitter captures
 8211        let mut captured_task_variables = TaskVariables::default();
 8212        for (capture_name, value) in tasks.extra_variables.clone() {
 8213            captured_task_variables.insert(
 8214                task::VariableName::Custom(capture_name.into()),
 8215                value.clone(),
 8216            );
 8217        }
 8218        project.update(cx, |project, cx| {
 8219            project.task_store().update(cx, |task_store, cx| {
 8220                task_store.task_context_for_location(captured_task_variables, location, cx)
 8221            })
 8222        })
 8223    }
 8224
 8225    pub fn spawn_nearest_task(
 8226        &mut self,
 8227        action: &SpawnNearestTask,
 8228        window: &mut Window,
 8229        cx: &mut Context<Self>,
 8230    ) {
 8231        let Some((workspace, _)) = self.workspace.clone() else {
 8232            return;
 8233        };
 8234        let Some(project) = self.project.clone() else {
 8235            return;
 8236        };
 8237
 8238        // Try to find a closest, enclosing node using tree-sitter that has a
 8239        // task
 8240        let Some((buffer, buffer_row, tasks)) = self
 8241            .find_enclosing_node_task(cx)
 8242            // Or find the task that's closest in row-distance.
 8243            .or_else(|| self.find_closest_task(cx))
 8244        else {
 8245            return;
 8246        };
 8247
 8248        let reveal_strategy = action.reveal;
 8249        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8250        cx.spawn_in(window, async move |_, cx| {
 8251            let context = task_context.await?;
 8252            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8253
 8254            let resolved = &mut resolved_task.resolved;
 8255            resolved.reveal = reveal_strategy;
 8256
 8257            workspace
 8258                .update_in(cx, |workspace, window, cx| {
 8259                    workspace.schedule_resolved_task(
 8260                        task_source_kind,
 8261                        resolved_task,
 8262                        false,
 8263                        window,
 8264                        cx,
 8265                    );
 8266                })
 8267                .ok()
 8268        })
 8269        .detach();
 8270    }
 8271
 8272    fn find_closest_task(
 8273        &mut self,
 8274        cx: &mut Context<Self>,
 8275    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8276        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8277
 8278        let ((buffer_id, row), tasks) = self
 8279            .tasks
 8280            .iter()
 8281            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8282
 8283        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8284        let tasks = Arc::new(tasks.to_owned());
 8285        Some((buffer, *row, tasks))
 8286    }
 8287
 8288    fn find_enclosing_node_task(
 8289        &mut self,
 8290        cx: &mut Context<Self>,
 8291    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8292        let snapshot = self.buffer.read(cx).snapshot(cx);
 8293        let offset = self.selections.newest::<usize>(cx).head();
 8294        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8295        let buffer_id = excerpt.buffer().remote_id();
 8296
 8297        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8298        let mut cursor = layer.node().walk();
 8299
 8300        while cursor.goto_first_child_for_byte(offset).is_some() {
 8301            if cursor.node().end_byte() == offset {
 8302                cursor.goto_next_sibling();
 8303            }
 8304        }
 8305
 8306        // Ascend to the smallest ancestor that contains the range and has a task.
 8307        loop {
 8308            let node = cursor.node();
 8309            let node_range = node.byte_range();
 8310            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8311
 8312            // Check if this node contains our offset
 8313            if node_range.start <= offset && node_range.end >= offset {
 8314                // If it contains offset, check for task
 8315                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8316                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8317                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8318                }
 8319            }
 8320
 8321            if !cursor.goto_parent() {
 8322                break;
 8323            }
 8324        }
 8325        None
 8326    }
 8327
 8328    fn render_run_indicator(
 8329        &self,
 8330        _style: &EditorStyle,
 8331        is_active: bool,
 8332        row: DisplayRow,
 8333        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8334        cx: &mut Context<Self>,
 8335    ) -> IconButton {
 8336        let color = Color::Muted;
 8337        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8338
 8339        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8340            .shape(ui::IconButtonShape::Square)
 8341            .icon_size(IconSize::XSmall)
 8342            .icon_color(color)
 8343            .toggle_state(is_active)
 8344            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8345                let quick_launch = e.down.button == MouseButton::Left;
 8346                window.focus(&editor.focus_handle(cx));
 8347                editor.toggle_code_actions(
 8348                    &ToggleCodeActions {
 8349                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8350                        quick_launch,
 8351                    },
 8352                    window,
 8353                    cx,
 8354                );
 8355            }))
 8356            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8357                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8358            }))
 8359    }
 8360
 8361    pub fn context_menu_visible(&self) -> bool {
 8362        !self.edit_prediction_preview_is_active()
 8363            && self
 8364                .context_menu
 8365                .borrow()
 8366                .as_ref()
 8367                .map_or(false, |menu| menu.visible())
 8368    }
 8369
 8370    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8371        self.context_menu
 8372            .borrow()
 8373            .as_ref()
 8374            .map(|menu| menu.origin())
 8375    }
 8376
 8377    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8378        self.context_menu_options = Some(options);
 8379    }
 8380
 8381    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8382    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8383
 8384    fn render_edit_prediction_popover(
 8385        &mut self,
 8386        text_bounds: &Bounds<Pixels>,
 8387        content_origin: gpui::Point<Pixels>,
 8388        right_margin: Pixels,
 8389        editor_snapshot: &EditorSnapshot,
 8390        visible_row_range: Range<DisplayRow>,
 8391        scroll_top: f32,
 8392        scroll_bottom: f32,
 8393        line_layouts: &[LineWithInvisibles],
 8394        line_height: Pixels,
 8395        scroll_pixel_position: gpui::Point<Pixels>,
 8396        newest_selection_head: Option<DisplayPoint>,
 8397        editor_width: Pixels,
 8398        style: &EditorStyle,
 8399        window: &mut Window,
 8400        cx: &mut App,
 8401    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8402        if self.mode().is_minimap() {
 8403            return None;
 8404        }
 8405        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8406
 8407        if self.edit_prediction_visible_in_cursor_popover(true) {
 8408            return None;
 8409        }
 8410
 8411        match &active_inline_completion.completion {
 8412            InlineCompletion::Move { target, .. } => {
 8413                let target_display_point = target.to_display_point(editor_snapshot);
 8414
 8415                if self.edit_prediction_requires_modifier() {
 8416                    if !self.edit_prediction_preview_is_active() {
 8417                        return None;
 8418                    }
 8419
 8420                    self.render_edit_prediction_modifier_jump_popover(
 8421                        text_bounds,
 8422                        content_origin,
 8423                        visible_row_range,
 8424                        line_layouts,
 8425                        line_height,
 8426                        scroll_pixel_position,
 8427                        newest_selection_head,
 8428                        target_display_point,
 8429                        window,
 8430                        cx,
 8431                    )
 8432                } else {
 8433                    self.render_edit_prediction_eager_jump_popover(
 8434                        text_bounds,
 8435                        content_origin,
 8436                        editor_snapshot,
 8437                        visible_row_range,
 8438                        scroll_top,
 8439                        scroll_bottom,
 8440                        line_height,
 8441                        scroll_pixel_position,
 8442                        target_display_point,
 8443                        editor_width,
 8444                        window,
 8445                        cx,
 8446                    )
 8447                }
 8448            }
 8449            InlineCompletion::Edit {
 8450                display_mode: EditDisplayMode::Inline,
 8451                ..
 8452            } => None,
 8453            InlineCompletion::Edit {
 8454                display_mode: EditDisplayMode::TabAccept,
 8455                edits,
 8456                ..
 8457            } => {
 8458                let range = &edits.first()?.0;
 8459                let target_display_point = range.end.to_display_point(editor_snapshot);
 8460
 8461                self.render_edit_prediction_end_of_line_popover(
 8462                    "Accept",
 8463                    editor_snapshot,
 8464                    visible_row_range,
 8465                    target_display_point,
 8466                    line_height,
 8467                    scroll_pixel_position,
 8468                    content_origin,
 8469                    editor_width,
 8470                    window,
 8471                    cx,
 8472                )
 8473            }
 8474            InlineCompletion::Edit {
 8475                edits,
 8476                edit_preview,
 8477                display_mode: EditDisplayMode::DiffPopover,
 8478                snapshot,
 8479            } => self.render_edit_prediction_diff_popover(
 8480                text_bounds,
 8481                content_origin,
 8482                right_margin,
 8483                editor_snapshot,
 8484                visible_row_range,
 8485                line_layouts,
 8486                line_height,
 8487                scroll_pixel_position,
 8488                newest_selection_head,
 8489                editor_width,
 8490                style,
 8491                edits,
 8492                edit_preview,
 8493                snapshot,
 8494                window,
 8495                cx,
 8496            ),
 8497        }
 8498    }
 8499
 8500    fn render_edit_prediction_modifier_jump_popover(
 8501        &mut self,
 8502        text_bounds: &Bounds<Pixels>,
 8503        content_origin: gpui::Point<Pixels>,
 8504        visible_row_range: Range<DisplayRow>,
 8505        line_layouts: &[LineWithInvisibles],
 8506        line_height: Pixels,
 8507        scroll_pixel_position: gpui::Point<Pixels>,
 8508        newest_selection_head: Option<DisplayPoint>,
 8509        target_display_point: DisplayPoint,
 8510        window: &mut Window,
 8511        cx: &mut App,
 8512    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8513        let scrolled_content_origin =
 8514            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8515
 8516        const SCROLL_PADDING_Y: Pixels = px(12.);
 8517
 8518        if target_display_point.row() < visible_row_range.start {
 8519            return self.render_edit_prediction_scroll_popover(
 8520                |_| SCROLL_PADDING_Y,
 8521                IconName::ArrowUp,
 8522                visible_row_range,
 8523                line_layouts,
 8524                newest_selection_head,
 8525                scrolled_content_origin,
 8526                window,
 8527                cx,
 8528            );
 8529        } else if target_display_point.row() >= visible_row_range.end {
 8530            return self.render_edit_prediction_scroll_popover(
 8531                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8532                IconName::ArrowDown,
 8533                visible_row_range,
 8534                line_layouts,
 8535                newest_selection_head,
 8536                scrolled_content_origin,
 8537                window,
 8538                cx,
 8539            );
 8540        }
 8541
 8542        const POLE_WIDTH: Pixels = px(2.);
 8543
 8544        let line_layout =
 8545            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8546        let target_column = target_display_point.column() as usize;
 8547
 8548        let target_x = line_layout.x_for_index(target_column);
 8549        let target_y =
 8550            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8551
 8552        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8553
 8554        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8555        border_color.l += 0.001;
 8556
 8557        let mut element = v_flex()
 8558            .items_end()
 8559            .when(flag_on_right, |el| el.items_start())
 8560            .child(if flag_on_right {
 8561                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8562                    .rounded_bl(px(0.))
 8563                    .rounded_tl(px(0.))
 8564                    .border_l_2()
 8565                    .border_color(border_color)
 8566            } else {
 8567                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8568                    .rounded_br(px(0.))
 8569                    .rounded_tr(px(0.))
 8570                    .border_r_2()
 8571                    .border_color(border_color)
 8572            })
 8573            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8574            .into_any();
 8575
 8576        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8577
 8578        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8579            - point(
 8580                if flag_on_right {
 8581                    POLE_WIDTH
 8582                } else {
 8583                    size.width - POLE_WIDTH
 8584                },
 8585                size.height - line_height,
 8586            );
 8587
 8588        origin.x = origin.x.max(content_origin.x);
 8589
 8590        element.prepaint_at(origin, window, cx);
 8591
 8592        Some((element, origin))
 8593    }
 8594
 8595    fn render_edit_prediction_scroll_popover(
 8596        &mut self,
 8597        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8598        scroll_icon: IconName,
 8599        visible_row_range: Range<DisplayRow>,
 8600        line_layouts: &[LineWithInvisibles],
 8601        newest_selection_head: Option<DisplayPoint>,
 8602        scrolled_content_origin: gpui::Point<Pixels>,
 8603        window: &mut Window,
 8604        cx: &mut App,
 8605    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8606        let mut element = self
 8607            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8608            .into_any();
 8609
 8610        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8611
 8612        let cursor = newest_selection_head?;
 8613        let cursor_row_layout =
 8614            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8615        let cursor_column = cursor.column() as usize;
 8616
 8617        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8618
 8619        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8620
 8621        element.prepaint_at(origin, window, cx);
 8622        Some((element, origin))
 8623    }
 8624
 8625    fn render_edit_prediction_eager_jump_popover(
 8626        &mut self,
 8627        text_bounds: &Bounds<Pixels>,
 8628        content_origin: gpui::Point<Pixels>,
 8629        editor_snapshot: &EditorSnapshot,
 8630        visible_row_range: Range<DisplayRow>,
 8631        scroll_top: f32,
 8632        scroll_bottom: f32,
 8633        line_height: Pixels,
 8634        scroll_pixel_position: gpui::Point<Pixels>,
 8635        target_display_point: DisplayPoint,
 8636        editor_width: Pixels,
 8637        window: &mut Window,
 8638        cx: &mut App,
 8639    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8640        if target_display_point.row().as_f32() < scroll_top {
 8641            let mut element = self
 8642                .render_edit_prediction_line_popover(
 8643                    "Jump to Edit",
 8644                    Some(IconName::ArrowUp),
 8645                    window,
 8646                    cx,
 8647                )?
 8648                .into_any();
 8649
 8650            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8651            let offset = point(
 8652                (text_bounds.size.width - size.width) / 2.,
 8653                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8654            );
 8655
 8656            let origin = text_bounds.origin + offset;
 8657            element.prepaint_at(origin, window, cx);
 8658            Some((element, origin))
 8659        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8660            let mut element = self
 8661                .render_edit_prediction_line_popover(
 8662                    "Jump to Edit",
 8663                    Some(IconName::ArrowDown),
 8664                    window,
 8665                    cx,
 8666                )?
 8667                .into_any();
 8668
 8669            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8670            let offset = point(
 8671                (text_bounds.size.width - size.width) / 2.,
 8672                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8673            );
 8674
 8675            let origin = text_bounds.origin + offset;
 8676            element.prepaint_at(origin, window, cx);
 8677            Some((element, origin))
 8678        } else {
 8679            self.render_edit_prediction_end_of_line_popover(
 8680                "Jump to Edit",
 8681                editor_snapshot,
 8682                visible_row_range,
 8683                target_display_point,
 8684                line_height,
 8685                scroll_pixel_position,
 8686                content_origin,
 8687                editor_width,
 8688                window,
 8689                cx,
 8690            )
 8691        }
 8692    }
 8693
 8694    fn render_edit_prediction_end_of_line_popover(
 8695        self: &mut Editor,
 8696        label: &'static str,
 8697        editor_snapshot: &EditorSnapshot,
 8698        visible_row_range: Range<DisplayRow>,
 8699        target_display_point: DisplayPoint,
 8700        line_height: Pixels,
 8701        scroll_pixel_position: gpui::Point<Pixels>,
 8702        content_origin: gpui::Point<Pixels>,
 8703        editor_width: Pixels,
 8704        window: &mut Window,
 8705        cx: &mut App,
 8706    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8707        let target_line_end = DisplayPoint::new(
 8708            target_display_point.row(),
 8709            editor_snapshot.line_len(target_display_point.row()),
 8710        );
 8711
 8712        let mut element = self
 8713            .render_edit_prediction_line_popover(label, None, window, cx)?
 8714            .into_any();
 8715
 8716        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8717
 8718        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8719
 8720        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8721        let mut origin = start_point
 8722            + line_origin
 8723            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8724        origin.x = origin.x.max(content_origin.x);
 8725
 8726        let max_x = content_origin.x + editor_width - size.width;
 8727
 8728        if origin.x > max_x {
 8729            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8730
 8731            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8732                origin.y += offset;
 8733                IconName::ArrowUp
 8734            } else {
 8735                origin.y -= offset;
 8736                IconName::ArrowDown
 8737            };
 8738
 8739            element = self
 8740                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8741                .into_any();
 8742
 8743            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8744
 8745            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8746        }
 8747
 8748        element.prepaint_at(origin, window, cx);
 8749        Some((element, origin))
 8750    }
 8751
 8752    fn render_edit_prediction_diff_popover(
 8753        self: &Editor,
 8754        text_bounds: &Bounds<Pixels>,
 8755        content_origin: gpui::Point<Pixels>,
 8756        right_margin: Pixels,
 8757        editor_snapshot: &EditorSnapshot,
 8758        visible_row_range: Range<DisplayRow>,
 8759        line_layouts: &[LineWithInvisibles],
 8760        line_height: Pixels,
 8761        scroll_pixel_position: gpui::Point<Pixels>,
 8762        newest_selection_head: Option<DisplayPoint>,
 8763        editor_width: Pixels,
 8764        style: &EditorStyle,
 8765        edits: &Vec<(Range<Anchor>, String)>,
 8766        edit_preview: &Option<language::EditPreview>,
 8767        snapshot: &language::BufferSnapshot,
 8768        window: &mut Window,
 8769        cx: &mut App,
 8770    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8771        let edit_start = edits
 8772            .first()
 8773            .unwrap()
 8774            .0
 8775            .start
 8776            .to_display_point(editor_snapshot);
 8777        let edit_end = edits
 8778            .last()
 8779            .unwrap()
 8780            .0
 8781            .end
 8782            .to_display_point(editor_snapshot);
 8783
 8784        let is_visible = visible_row_range.contains(&edit_start.row())
 8785            || visible_row_range.contains(&edit_end.row());
 8786        if !is_visible {
 8787            return None;
 8788        }
 8789
 8790        let highlighted_edits =
 8791            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8792
 8793        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8794        let line_count = highlighted_edits.text.lines().count();
 8795
 8796        const BORDER_WIDTH: Pixels = px(1.);
 8797
 8798        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8799        let has_keybind = keybind.is_some();
 8800
 8801        let mut element = h_flex()
 8802            .items_start()
 8803            .child(
 8804                h_flex()
 8805                    .bg(cx.theme().colors().editor_background)
 8806                    .border(BORDER_WIDTH)
 8807                    .shadow_xs()
 8808                    .border_color(cx.theme().colors().border)
 8809                    .rounded_l_lg()
 8810                    .when(line_count > 1, |el| el.rounded_br_lg())
 8811                    .pr_1()
 8812                    .child(styled_text),
 8813            )
 8814            .child(
 8815                h_flex()
 8816                    .h(line_height + BORDER_WIDTH * 2.)
 8817                    .px_1p5()
 8818                    .gap_1()
 8819                    // Workaround: For some reason, there's a gap if we don't do this
 8820                    .ml(-BORDER_WIDTH)
 8821                    .shadow(vec![gpui::BoxShadow {
 8822                        color: gpui::black().opacity(0.05),
 8823                        offset: point(px(1.), px(1.)),
 8824                        blur_radius: px(2.),
 8825                        spread_radius: px(0.),
 8826                    }])
 8827                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8828                    .border(BORDER_WIDTH)
 8829                    .border_color(cx.theme().colors().border)
 8830                    .rounded_r_lg()
 8831                    .id("edit_prediction_diff_popover_keybind")
 8832                    .when(!has_keybind, |el| {
 8833                        let status_colors = cx.theme().status();
 8834
 8835                        el.bg(status_colors.error_background)
 8836                            .border_color(status_colors.error.opacity(0.6))
 8837                            .child(Icon::new(IconName::Info).color(Color::Error))
 8838                            .cursor_default()
 8839                            .hoverable_tooltip(move |_window, cx| {
 8840                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8841                            })
 8842                    })
 8843                    .children(keybind),
 8844            )
 8845            .into_any();
 8846
 8847        let longest_row =
 8848            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8849        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8850            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8851        } else {
 8852            layout_line(
 8853                longest_row,
 8854                editor_snapshot,
 8855                style,
 8856                editor_width,
 8857                |_| false,
 8858                window,
 8859                cx,
 8860            )
 8861            .width
 8862        };
 8863
 8864        let viewport_bounds =
 8865            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8866                right: -right_margin,
 8867                ..Default::default()
 8868            });
 8869
 8870        let x_after_longest =
 8871            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8872                - scroll_pixel_position.x;
 8873
 8874        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8875
 8876        // Fully visible if it can be displayed within the window (allow overlapping other
 8877        // panes). However, this is only allowed if the popover starts within text_bounds.
 8878        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8879            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8880
 8881        let mut origin = if can_position_to_the_right {
 8882            point(
 8883                x_after_longest,
 8884                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8885                    - scroll_pixel_position.y,
 8886            )
 8887        } else {
 8888            let cursor_row = newest_selection_head.map(|head| head.row());
 8889            let above_edit = edit_start
 8890                .row()
 8891                .0
 8892                .checked_sub(line_count as u32)
 8893                .map(DisplayRow);
 8894            let below_edit = Some(edit_end.row() + 1);
 8895            let above_cursor =
 8896                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8897            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8898
 8899            // Place the edit popover adjacent to the edit if there is a location
 8900            // available that is onscreen and does not obscure the cursor. Otherwise,
 8901            // place it adjacent to the cursor.
 8902            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8903                .into_iter()
 8904                .flatten()
 8905                .find(|&start_row| {
 8906                    let end_row = start_row + line_count as u32;
 8907                    visible_row_range.contains(&start_row)
 8908                        && visible_row_range.contains(&end_row)
 8909                        && cursor_row.map_or(true, |cursor_row| {
 8910                            !((start_row..end_row).contains(&cursor_row))
 8911                        })
 8912                })?;
 8913
 8914            content_origin
 8915                + point(
 8916                    -scroll_pixel_position.x,
 8917                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8918                )
 8919        };
 8920
 8921        origin.x -= BORDER_WIDTH;
 8922
 8923        window.defer_draw(element, origin, 1);
 8924
 8925        // Do not return an element, since it will already be drawn due to defer_draw.
 8926        None
 8927    }
 8928
 8929    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8930        px(30.)
 8931    }
 8932
 8933    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8934        if self.read_only(cx) {
 8935            cx.theme().players().read_only()
 8936        } else {
 8937            self.style.as_ref().unwrap().local_player
 8938        }
 8939    }
 8940
 8941    fn render_edit_prediction_accept_keybind(
 8942        &self,
 8943        window: &mut Window,
 8944        cx: &App,
 8945    ) -> Option<AnyElement> {
 8946        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8947        let accept_keystroke = accept_binding.keystroke()?;
 8948
 8949        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8950
 8951        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8952            Color::Accent
 8953        } else {
 8954            Color::Muted
 8955        };
 8956
 8957        h_flex()
 8958            .px_0p5()
 8959            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8960            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8961            .text_size(TextSize::XSmall.rems(cx))
 8962            .child(h_flex().children(ui::render_modifiers(
 8963                &accept_keystroke.modifiers,
 8964                PlatformStyle::platform(),
 8965                Some(modifiers_color),
 8966                Some(IconSize::XSmall.rems().into()),
 8967                true,
 8968            )))
 8969            .when(is_platform_style_mac, |parent| {
 8970                parent.child(accept_keystroke.key.clone())
 8971            })
 8972            .when(!is_platform_style_mac, |parent| {
 8973                parent.child(
 8974                    Key::new(
 8975                        util::capitalize(&accept_keystroke.key),
 8976                        Some(Color::Default),
 8977                    )
 8978                    .size(Some(IconSize::XSmall.rems().into())),
 8979                )
 8980            })
 8981            .into_any()
 8982            .into()
 8983    }
 8984
 8985    fn render_edit_prediction_line_popover(
 8986        &self,
 8987        label: impl Into<SharedString>,
 8988        icon: Option<IconName>,
 8989        window: &mut Window,
 8990        cx: &App,
 8991    ) -> Option<Stateful<Div>> {
 8992        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8993
 8994        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8995        let has_keybind = keybind.is_some();
 8996
 8997        let result = h_flex()
 8998            .id("ep-line-popover")
 8999            .py_0p5()
 9000            .pl_1()
 9001            .pr(padding_right)
 9002            .gap_1()
 9003            .rounded_md()
 9004            .border_1()
 9005            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9006            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9007            .shadow_xs()
 9008            .when(!has_keybind, |el| {
 9009                let status_colors = cx.theme().status();
 9010
 9011                el.bg(status_colors.error_background)
 9012                    .border_color(status_colors.error.opacity(0.6))
 9013                    .pl_2()
 9014                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9015                    .cursor_default()
 9016                    .hoverable_tooltip(move |_window, cx| {
 9017                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9018                    })
 9019            })
 9020            .children(keybind)
 9021            .child(
 9022                Label::new(label)
 9023                    .size(LabelSize::Small)
 9024                    .when(!has_keybind, |el| {
 9025                        el.color(cx.theme().status().error.into()).strikethrough()
 9026                    }),
 9027            )
 9028            .when(!has_keybind, |el| {
 9029                el.child(
 9030                    h_flex().ml_1().child(
 9031                        Icon::new(IconName::Info)
 9032                            .size(IconSize::Small)
 9033                            .color(cx.theme().status().error.into()),
 9034                    ),
 9035                )
 9036            })
 9037            .when_some(icon, |element, icon| {
 9038                element.child(
 9039                    div()
 9040                        .mt(px(1.5))
 9041                        .child(Icon::new(icon).size(IconSize::Small)),
 9042                )
 9043            });
 9044
 9045        Some(result)
 9046    }
 9047
 9048    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9049        let accent_color = cx.theme().colors().text_accent;
 9050        let editor_bg_color = cx.theme().colors().editor_background;
 9051        editor_bg_color.blend(accent_color.opacity(0.1))
 9052    }
 9053
 9054    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9055        let accent_color = cx.theme().colors().text_accent;
 9056        let editor_bg_color = cx.theme().colors().editor_background;
 9057        editor_bg_color.blend(accent_color.opacity(0.6))
 9058    }
 9059
 9060    fn render_edit_prediction_cursor_popover(
 9061        &self,
 9062        min_width: Pixels,
 9063        max_width: Pixels,
 9064        cursor_point: Point,
 9065        style: &EditorStyle,
 9066        accept_keystroke: Option<&gpui::Keystroke>,
 9067        _window: &Window,
 9068        cx: &mut Context<Editor>,
 9069    ) -> Option<AnyElement> {
 9070        let provider = self.edit_prediction_provider.as_ref()?;
 9071
 9072        if provider.provider.needs_terms_acceptance(cx) {
 9073            return Some(
 9074                h_flex()
 9075                    .min_w(min_width)
 9076                    .flex_1()
 9077                    .px_2()
 9078                    .py_1()
 9079                    .gap_3()
 9080                    .elevation_2(cx)
 9081                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9082                    .id("accept-terms")
 9083                    .cursor_pointer()
 9084                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9085                    .on_click(cx.listener(|this, _event, window, cx| {
 9086                        cx.stop_propagation();
 9087                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9088                        window.dispatch_action(
 9089                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9090                            cx,
 9091                        );
 9092                    }))
 9093                    .child(
 9094                        h_flex()
 9095                            .flex_1()
 9096                            .gap_2()
 9097                            .child(Icon::new(IconName::ZedPredict))
 9098                            .child(Label::new("Accept Terms of Service"))
 9099                            .child(div().w_full())
 9100                            .child(
 9101                                Icon::new(IconName::ArrowUpRight)
 9102                                    .color(Color::Muted)
 9103                                    .size(IconSize::Small),
 9104                            )
 9105                            .into_any_element(),
 9106                    )
 9107                    .into_any(),
 9108            );
 9109        }
 9110
 9111        let is_refreshing = provider.provider.is_refreshing(cx);
 9112
 9113        fn pending_completion_container() -> Div {
 9114            h_flex()
 9115                .h_full()
 9116                .flex_1()
 9117                .gap_2()
 9118                .child(Icon::new(IconName::ZedPredict))
 9119        }
 9120
 9121        let completion = match &self.active_inline_completion {
 9122            Some(prediction) => {
 9123                if !self.has_visible_completions_menu() {
 9124                    const RADIUS: Pixels = px(6.);
 9125                    const BORDER_WIDTH: Pixels = px(1.);
 9126
 9127                    return Some(
 9128                        h_flex()
 9129                            .elevation_2(cx)
 9130                            .border(BORDER_WIDTH)
 9131                            .border_color(cx.theme().colors().border)
 9132                            .when(accept_keystroke.is_none(), |el| {
 9133                                el.border_color(cx.theme().status().error)
 9134                            })
 9135                            .rounded(RADIUS)
 9136                            .rounded_tl(px(0.))
 9137                            .overflow_hidden()
 9138                            .child(div().px_1p5().child(match &prediction.completion {
 9139                                InlineCompletion::Move { target, snapshot } => {
 9140                                    use text::ToPoint as _;
 9141                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9142                                    {
 9143                                        Icon::new(IconName::ZedPredictDown)
 9144                                    } else {
 9145                                        Icon::new(IconName::ZedPredictUp)
 9146                                    }
 9147                                }
 9148                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9149                            }))
 9150                            .child(
 9151                                h_flex()
 9152                                    .gap_1()
 9153                                    .py_1()
 9154                                    .px_2()
 9155                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9156                                    .border_l_1()
 9157                                    .border_color(cx.theme().colors().border)
 9158                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9159                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9160                                        el.child(
 9161                                            Label::new("Hold")
 9162                                                .size(LabelSize::Small)
 9163                                                .when(accept_keystroke.is_none(), |el| {
 9164                                                    el.strikethrough()
 9165                                                })
 9166                                                .line_height_style(LineHeightStyle::UiLabel),
 9167                                        )
 9168                                    })
 9169                                    .id("edit_prediction_cursor_popover_keybind")
 9170                                    .when(accept_keystroke.is_none(), |el| {
 9171                                        let status_colors = cx.theme().status();
 9172
 9173                                        el.bg(status_colors.error_background)
 9174                                            .border_color(status_colors.error.opacity(0.6))
 9175                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9176                                            .cursor_default()
 9177                                            .hoverable_tooltip(move |_window, cx| {
 9178                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9179                                                    .into()
 9180                                            })
 9181                                    })
 9182                                    .when_some(
 9183                                        accept_keystroke.as_ref(),
 9184                                        |el, accept_keystroke| {
 9185                                            el.child(h_flex().children(ui::render_modifiers(
 9186                                                &accept_keystroke.modifiers,
 9187                                                PlatformStyle::platform(),
 9188                                                Some(Color::Default),
 9189                                                Some(IconSize::XSmall.rems().into()),
 9190                                                false,
 9191                                            )))
 9192                                        },
 9193                                    ),
 9194                            )
 9195                            .into_any(),
 9196                    );
 9197                }
 9198
 9199                self.render_edit_prediction_cursor_popover_preview(
 9200                    prediction,
 9201                    cursor_point,
 9202                    style,
 9203                    cx,
 9204                )?
 9205            }
 9206
 9207            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9208                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9209                    stale_completion,
 9210                    cursor_point,
 9211                    style,
 9212                    cx,
 9213                )?,
 9214
 9215                None => {
 9216                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9217                }
 9218            },
 9219
 9220            None => pending_completion_container().child(Label::new("No Prediction")),
 9221        };
 9222
 9223        let completion = if is_refreshing {
 9224            completion
 9225                .with_animation(
 9226                    "loading-completion",
 9227                    Animation::new(Duration::from_secs(2))
 9228                        .repeat()
 9229                        .with_easing(pulsating_between(0.4, 0.8)),
 9230                    |label, delta| label.opacity(delta),
 9231                )
 9232                .into_any_element()
 9233        } else {
 9234            completion.into_any_element()
 9235        };
 9236
 9237        let has_completion = self.active_inline_completion.is_some();
 9238
 9239        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9240        Some(
 9241            h_flex()
 9242                .min_w(min_width)
 9243                .max_w(max_width)
 9244                .flex_1()
 9245                .elevation_2(cx)
 9246                .border_color(cx.theme().colors().border)
 9247                .child(
 9248                    div()
 9249                        .flex_1()
 9250                        .py_1()
 9251                        .px_2()
 9252                        .overflow_hidden()
 9253                        .child(completion),
 9254                )
 9255                .when_some(accept_keystroke, |el, accept_keystroke| {
 9256                    if !accept_keystroke.modifiers.modified() {
 9257                        return el;
 9258                    }
 9259
 9260                    el.child(
 9261                        h_flex()
 9262                            .h_full()
 9263                            .border_l_1()
 9264                            .rounded_r_lg()
 9265                            .border_color(cx.theme().colors().border)
 9266                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9267                            .gap_1()
 9268                            .py_1()
 9269                            .px_2()
 9270                            .child(
 9271                                h_flex()
 9272                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9273                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9274                                    .child(h_flex().children(ui::render_modifiers(
 9275                                        &accept_keystroke.modifiers,
 9276                                        PlatformStyle::platform(),
 9277                                        Some(if !has_completion {
 9278                                            Color::Muted
 9279                                        } else {
 9280                                            Color::Default
 9281                                        }),
 9282                                        None,
 9283                                        false,
 9284                                    ))),
 9285                            )
 9286                            .child(Label::new("Preview").into_any_element())
 9287                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9288                    )
 9289                })
 9290                .into_any(),
 9291        )
 9292    }
 9293
 9294    fn render_edit_prediction_cursor_popover_preview(
 9295        &self,
 9296        completion: &InlineCompletionState,
 9297        cursor_point: Point,
 9298        style: &EditorStyle,
 9299        cx: &mut Context<Editor>,
 9300    ) -> Option<Div> {
 9301        use text::ToPoint as _;
 9302
 9303        fn render_relative_row_jump(
 9304            prefix: impl Into<String>,
 9305            current_row: u32,
 9306            target_row: u32,
 9307        ) -> Div {
 9308            let (row_diff, arrow) = if target_row < current_row {
 9309                (current_row - target_row, IconName::ArrowUp)
 9310            } else {
 9311                (target_row - current_row, IconName::ArrowDown)
 9312            };
 9313
 9314            h_flex()
 9315                .child(
 9316                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9317                        .color(Color::Muted)
 9318                        .size(LabelSize::Small),
 9319                )
 9320                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9321        }
 9322
 9323        match &completion.completion {
 9324            InlineCompletion::Move {
 9325                target, snapshot, ..
 9326            } => Some(
 9327                h_flex()
 9328                    .px_2()
 9329                    .gap_2()
 9330                    .flex_1()
 9331                    .child(
 9332                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9333                            Icon::new(IconName::ZedPredictDown)
 9334                        } else {
 9335                            Icon::new(IconName::ZedPredictUp)
 9336                        },
 9337                    )
 9338                    .child(Label::new("Jump to Edit")),
 9339            ),
 9340
 9341            InlineCompletion::Edit {
 9342                edits,
 9343                edit_preview,
 9344                snapshot,
 9345                display_mode: _,
 9346            } => {
 9347                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9348
 9349                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9350                    &snapshot,
 9351                    &edits,
 9352                    edit_preview.as_ref()?,
 9353                    true,
 9354                    cx,
 9355                )
 9356                .first_line_preview();
 9357
 9358                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9359                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9360
 9361                let preview = h_flex()
 9362                    .gap_1()
 9363                    .min_w_16()
 9364                    .child(styled_text)
 9365                    .when(has_more_lines, |parent| parent.child(""));
 9366
 9367                let left = if first_edit_row != cursor_point.row {
 9368                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9369                        .into_any_element()
 9370                } else {
 9371                    Icon::new(IconName::ZedPredict).into_any_element()
 9372                };
 9373
 9374                Some(
 9375                    h_flex()
 9376                        .h_full()
 9377                        .flex_1()
 9378                        .gap_2()
 9379                        .pr_1()
 9380                        .overflow_x_hidden()
 9381                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9382                        .child(left)
 9383                        .child(preview),
 9384                )
 9385            }
 9386        }
 9387    }
 9388
 9389    pub fn render_context_menu(
 9390        &self,
 9391        style: &EditorStyle,
 9392        max_height_in_lines: u32,
 9393        window: &mut Window,
 9394        cx: &mut Context<Editor>,
 9395    ) -> Option<AnyElement> {
 9396        let menu = self.context_menu.borrow();
 9397        let menu = menu.as_ref()?;
 9398        if !menu.visible() {
 9399            return None;
 9400        };
 9401        Some(menu.render(style, max_height_in_lines, window, cx))
 9402    }
 9403
 9404    fn render_context_menu_aside(
 9405        &mut self,
 9406        max_size: Size<Pixels>,
 9407        window: &mut Window,
 9408        cx: &mut Context<Editor>,
 9409    ) -> Option<AnyElement> {
 9410        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9411            if menu.visible() {
 9412                menu.render_aside(max_size, window, cx)
 9413            } else {
 9414                None
 9415            }
 9416        })
 9417    }
 9418
 9419    fn hide_context_menu(
 9420        &mut self,
 9421        window: &mut Window,
 9422        cx: &mut Context<Self>,
 9423    ) -> Option<CodeContextMenu> {
 9424        cx.notify();
 9425        self.completion_tasks.clear();
 9426        let context_menu = self.context_menu.borrow_mut().take();
 9427        self.stale_inline_completion_in_menu.take();
 9428        self.update_visible_inline_completion(window, cx);
 9429        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9430            if let Some(completion_provider) = &self.completion_provider {
 9431                completion_provider.selection_changed(None, window, cx);
 9432            }
 9433        }
 9434        context_menu
 9435    }
 9436
 9437    fn show_snippet_choices(
 9438        &mut self,
 9439        choices: &Vec<String>,
 9440        selection: Range<Anchor>,
 9441        cx: &mut Context<Self>,
 9442    ) {
 9443        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9444            (Some(a), Some(b)) if a == b => a,
 9445            _ => {
 9446                log::error!("expected anchor range to have matching buffer IDs");
 9447                return;
 9448            }
 9449        };
 9450        let multi_buffer = self.buffer().read(cx);
 9451        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9452            return;
 9453        };
 9454
 9455        let id = post_inc(&mut self.next_completion_id);
 9456        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9457        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9458            CompletionsMenu::new_snippet_choices(
 9459                id,
 9460                true,
 9461                choices,
 9462                selection,
 9463                buffer,
 9464                snippet_sort_order,
 9465            ),
 9466        ));
 9467    }
 9468
 9469    pub fn insert_snippet(
 9470        &mut self,
 9471        insertion_ranges: &[Range<usize>],
 9472        snippet: Snippet,
 9473        window: &mut Window,
 9474        cx: &mut Context<Self>,
 9475    ) -> Result<()> {
 9476        struct Tabstop<T> {
 9477            is_end_tabstop: bool,
 9478            ranges: Vec<Range<T>>,
 9479            choices: Option<Vec<String>>,
 9480        }
 9481
 9482        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9483            let snippet_text: Arc<str> = snippet.text.clone().into();
 9484            let edits = insertion_ranges
 9485                .iter()
 9486                .cloned()
 9487                .map(|range| (range, snippet_text.clone()));
 9488            let autoindent_mode = AutoindentMode::Block {
 9489                original_indent_columns: Vec::new(),
 9490            };
 9491            buffer.edit(edits, Some(autoindent_mode), cx);
 9492
 9493            let snapshot = &*buffer.read(cx);
 9494            let snippet = &snippet;
 9495            snippet
 9496                .tabstops
 9497                .iter()
 9498                .map(|tabstop| {
 9499                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9500                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9501                    });
 9502                    let mut tabstop_ranges = tabstop
 9503                        .ranges
 9504                        .iter()
 9505                        .flat_map(|tabstop_range| {
 9506                            let mut delta = 0_isize;
 9507                            insertion_ranges.iter().map(move |insertion_range| {
 9508                                let insertion_start = insertion_range.start as isize + delta;
 9509                                delta +=
 9510                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9511
 9512                                let start = ((insertion_start + tabstop_range.start) as usize)
 9513                                    .min(snapshot.len());
 9514                                let end = ((insertion_start + tabstop_range.end) as usize)
 9515                                    .min(snapshot.len());
 9516                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9517                            })
 9518                        })
 9519                        .collect::<Vec<_>>();
 9520                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9521
 9522                    Tabstop {
 9523                        is_end_tabstop,
 9524                        ranges: tabstop_ranges,
 9525                        choices: tabstop.choices.clone(),
 9526                    }
 9527                })
 9528                .collect::<Vec<_>>()
 9529        });
 9530        if let Some(tabstop) = tabstops.first() {
 9531            self.change_selections(Default::default(), window, cx, |s| {
 9532                // Reverse order so that the first range is the newest created selection.
 9533                // Completions will use it and autoscroll will prioritize it.
 9534                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9535            });
 9536
 9537            if let Some(choices) = &tabstop.choices {
 9538                if let Some(selection) = tabstop.ranges.first() {
 9539                    self.show_snippet_choices(choices, selection.clone(), cx)
 9540                }
 9541            }
 9542
 9543            // If we're already at the last tabstop and it's at the end of the snippet,
 9544            // we're done, we don't need to keep the state around.
 9545            if !tabstop.is_end_tabstop {
 9546                let choices = tabstops
 9547                    .iter()
 9548                    .map(|tabstop| tabstop.choices.clone())
 9549                    .collect();
 9550
 9551                let ranges = tabstops
 9552                    .into_iter()
 9553                    .map(|tabstop| tabstop.ranges)
 9554                    .collect::<Vec<_>>();
 9555
 9556                self.snippet_stack.push(SnippetState {
 9557                    active_index: 0,
 9558                    ranges,
 9559                    choices,
 9560                });
 9561            }
 9562
 9563            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9564            if self.autoclose_regions.is_empty() {
 9565                let snapshot = self.buffer.read(cx).snapshot(cx);
 9566                for selection in &mut self.selections.all::<Point>(cx) {
 9567                    let selection_head = selection.head();
 9568                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9569                        continue;
 9570                    };
 9571
 9572                    let mut bracket_pair = None;
 9573                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9574                    let prev_chars = snapshot
 9575                        .reversed_chars_at(selection_head)
 9576                        .collect::<String>();
 9577                    for (pair, enabled) in scope.brackets() {
 9578                        if enabled
 9579                            && pair.close
 9580                            && prev_chars.starts_with(pair.start.as_str())
 9581                            && next_chars.starts_with(pair.end.as_str())
 9582                        {
 9583                            bracket_pair = Some(pair.clone());
 9584                            break;
 9585                        }
 9586                    }
 9587                    if let Some(pair) = bracket_pair {
 9588                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9589                        let autoclose_enabled =
 9590                            self.use_autoclose && snapshot_settings.use_autoclose;
 9591                        if autoclose_enabled {
 9592                            let start = snapshot.anchor_after(selection_head);
 9593                            let end = snapshot.anchor_after(selection_head);
 9594                            self.autoclose_regions.push(AutocloseRegion {
 9595                                selection_id: selection.id,
 9596                                range: start..end,
 9597                                pair,
 9598                            });
 9599                        }
 9600                    }
 9601                }
 9602            }
 9603        }
 9604        Ok(())
 9605    }
 9606
 9607    pub fn move_to_next_snippet_tabstop(
 9608        &mut self,
 9609        window: &mut Window,
 9610        cx: &mut Context<Self>,
 9611    ) -> bool {
 9612        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9613    }
 9614
 9615    pub fn move_to_prev_snippet_tabstop(
 9616        &mut self,
 9617        window: &mut Window,
 9618        cx: &mut Context<Self>,
 9619    ) -> bool {
 9620        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9621    }
 9622
 9623    pub fn move_to_snippet_tabstop(
 9624        &mut self,
 9625        bias: Bias,
 9626        window: &mut Window,
 9627        cx: &mut Context<Self>,
 9628    ) -> bool {
 9629        if let Some(mut snippet) = self.snippet_stack.pop() {
 9630            match bias {
 9631                Bias::Left => {
 9632                    if snippet.active_index > 0 {
 9633                        snippet.active_index -= 1;
 9634                    } else {
 9635                        self.snippet_stack.push(snippet);
 9636                        return false;
 9637                    }
 9638                }
 9639                Bias::Right => {
 9640                    if snippet.active_index + 1 < snippet.ranges.len() {
 9641                        snippet.active_index += 1;
 9642                    } else {
 9643                        self.snippet_stack.push(snippet);
 9644                        return false;
 9645                    }
 9646                }
 9647            }
 9648            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9649                self.change_selections(Default::default(), window, cx, |s| {
 9650                    // Reverse order so that the first range is the newest created selection.
 9651                    // Completions will use it and autoscroll will prioritize it.
 9652                    s.select_ranges(current_ranges.iter().rev().cloned())
 9653                });
 9654
 9655                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9656                    if let Some(selection) = current_ranges.first() {
 9657                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9658                    }
 9659                }
 9660
 9661                // If snippet state is not at the last tabstop, push it back on the stack
 9662                if snippet.active_index + 1 < snippet.ranges.len() {
 9663                    self.snippet_stack.push(snippet);
 9664                }
 9665                return true;
 9666            }
 9667        }
 9668
 9669        false
 9670    }
 9671
 9672    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9673        self.transact(window, cx, |this, window, cx| {
 9674            this.select_all(&SelectAll, window, cx);
 9675            this.insert("", window, cx);
 9676        });
 9677    }
 9678
 9679    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9681        self.transact(window, cx, |this, window, cx| {
 9682            this.select_autoclose_pair(window, cx);
 9683            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9684            if !this.linked_edit_ranges.is_empty() {
 9685                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9686                let snapshot = this.buffer.read(cx).snapshot(cx);
 9687
 9688                for selection in selections.iter() {
 9689                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9690                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9691                    if selection_start.buffer_id != selection_end.buffer_id {
 9692                        continue;
 9693                    }
 9694                    if let Some(ranges) =
 9695                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9696                    {
 9697                        for (buffer, entries) in ranges {
 9698                            linked_ranges.entry(buffer).or_default().extend(entries);
 9699                        }
 9700                    }
 9701                }
 9702            }
 9703
 9704            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9705            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9706            for selection in &mut selections {
 9707                if selection.is_empty() {
 9708                    let old_head = selection.head();
 9709                    let mut new_head =
 9710                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9711                            .to_point(&display_map);
 9712                    if let Some((buffer, line_buffer_range)) = display_map
 9713                        .buffer_snapshot
 9714                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9715                    {
 9716                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9717                        let indent_len = match indent_size.kind {
 9718                            IndentKind::Space => {
 9719                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9720                            }
 9721                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9722                        };
 9723                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9724                            let indent_len = indent_len.get();
 9725                            new_head = cmp::min(
 9726                                new_head,
 9727                                MultiBufferPoint::new(
 9728                                    old_head.row,
 9729                                    ((old_head.column - 1) / indent_len) * indent_len,
 9730                                ),
 9731                            );
 9732                        }
 9733                    }
 9734
 9735                    selection.set_head(new_head, SelectionGoal::None);
 9736                }
 9737            }
 9738
 9739            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9740            this.insert("", window, cx);
 9741            let empty_str: Arc<str> = Arc::from("");
 9742            for (buffer, edits) in linked_ranges {
 9743                let snapshot = buffer.read(cx).snapshot();
 9744                use text::ToPoint as TP;
 9745
 9746                let edits = edits
 9747                    .into_iter()
 9748                    .map(|range| {
 9749                        let end_point = TP::to_point(&range.end, &snapshot);
 9750                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9751
 9752                        if end_point == start_point {
 9753                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9754                                .saturating_sub(1);
 9755                            start_point =
 9756                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9757                        };
 9758
 9759                        (start_point..end_point, empty_str.clone())
 9760                    })
 9761                    .sorted_by_key(|(range, _)| range.start)
 9762                    .collect::<Vec<_>>();
 9763                buffer.update(cx, |this, cx| {
 9764                    this.edit(edits, None, cx);
 9765                })
 9766            }
 9767            this.refresh_inline_completion(true, false, window, cx);
 9768            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9769        });
 9770    }
 9771
 9772    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9774        self.transact(window, cx, |this, window, cx| {
 9775            this.change_selections(Default::default(), window, cx, |s| {
 9776                s.move_with(|map, selection| {
 9777                    if selection.is_empty() {
 9778                        let cursor = movement::right(map, selection.head());
 9779                        selection.end = cursor;
 9780                        selection.reversed = true;
 9781                        selection.goal = SelectionGoal::None;
 9782                    }
 9783                })
 9784            });
 9785            this.insert("", window, cx);
 9786            this.refresh_inline_completion(true, false, window, cx);
 9787        });
 9788    }
 9789
 9790    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9791        if self.mode.is_single_line() {
 9792            cx.propagate();
 9793            return;
 9794        }
 9795
 9796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9797        if self.move_to_prev_snippet_tabstop(window, cx) {
 9798            return;
 9799        }
 9800        self.outdent(&Outdent, window, cx);
 9801    }
 9802
 9803    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9804        if self.mode.is_single_line() {
 9805            cx.propagate();
 9806            return;
 9807        }
 9808
 9809        if self.move_to_next_snippet_tabstop(window, cx) {
 9810            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9811            return;
 9812        }
 9813        if self.read_only(cx) {
 9814            return;
 9815        }
 9816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9817        let mut selections = self.selections.all_adjusted(cx);
 9818        let buffer = self.buffer.read(cx);
 9819        let snapshot = buffer.snapshot(cx);
 9820        let rows_iter = selections.iter().map(|s| s.head().row);
 9821        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9822
 9823        let has_some_cursor_in_whitespace = selections
 9824            .iter()
 9825            .filter(|selection| selection.is_empty())
 9826            .any(|selection| {
 9827                let cursor = selection.head();
 9828                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9829                cursor.column < current_indent.len
 9830            });
 9831
 9832        let mut edits = Vec::new();
 9833        let mut prev_edited_row = 0;
 9834        let mut row_delta = 0;
 9835        for selection in &mut selections {
 9836            if selection.start.row != prev_edited_row {
 9837                row_delta = 0;
 9838            }
 9839            prev_edited_row = selection.end.row;
 9840
 9841            // If the selection is non-empty, then increase the indentation of the selected lines.
 9842            if !selection.is_empty() {
 9843                row_delta =
 9844                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9845                continue;
 9846            }
 9847
 9848            let cursor = selection.head();
 9849            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9850            if let Some(suggested_indent) =
 9851                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9852            {
 9853                // Don't do anything if already at suggested indent
 9854                // and there is any other cursor which is not
 9855                if has_some_cursor_in_whitespace
 9856                    && cursor.column == current_indent.len
 9857                    && current_indent.len == suggested_indent.len
 9858                {
 9859                    continue;
 9860                }
 9861
 9862                // Adjust line and move cursor to suggested indent
 9863                // if cursor is not at suggested indent
 9864                if cursor.column < suggested_indent.len
 9865                    && cursor.column <= current_indent.len
 9866                    && current_indent.len <= suggested_indent.len
 9867                {
 9868                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9869                    selection.end = selection.start;
 9870                    if row_delta == 0 {
 9871                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9872                            cursor.row,
 9873                            current_indent,
 9874                            suggested_indent,
 9875                        ));
 9876                        row_delta = suggested_indent.len - current_indent.len;
 9877                    }
 9878                    continue;
 9879                }
 9880
 9881                // If current indent is more than suggested indent
 9882                // only move cursor to current indent and skip indent
 9883                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9884                    selection.start = Point::new(cursor.row, current_indent.len);
 9885                    selection.end = selection.start;
 9886                    continue;
 9887                }
 9888            }
 9889
 9890            // Otherwise, insert a hard or soft tab.
 9891            let settings = buffer.language_settings_at(cursor, cx);
 9892            let tab_size = if settings.hard_tabs {
 9893                IndentSize::tab()
 9894            } else {
 9895                let tab_size = settings.tab_size.get();
 9896                let indent_remainder = snapshot
 9897                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9898                    .flat_map(str::chars)
 9899                    .fold(row_delta % tab_size, |counter: u32, c| {
 9900                        if c == '\t' {
 9901                            0
 9902                        } else {
 9903                            (counter + 1) % tab_size
 9904                        }
 9905                    });
 9906
 9907                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9908                IndentSize::spaces(chars_to_next_tab_stop)
 9909            };
 9910            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9911            selection.end = selection.start;
 9912            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9913            row_delta += tab_size.len;
 9914        }
 9915
 9916        self.transact(window, cx, |this, window, cx| {
 9917            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9918            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9919            this.refresh_inline_completion(true, false, window, cx);
 9920        });
 9921    }
 9922
 9923    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9924        if self.read_only(cx) {
 9925            return;
 9926        }
 9927        if self.mode.is_single_line() {
 9928            cx.propagate();
 9929            return;
 9930        }
 9931
 9932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9933        let mut selections = self.selections.all::<Point>(cx);
 9934        let mut prev_edited_row = 0;
 9935        let mut row_delta = 0;
 9936        let mut edits = Vec::new();
 9937        let buffer = self.buffer.read(cx);
 9938        let snapshot = buffer.snapshot(cx);
 9939        for selection in &mut selections {
 9940            if selection.start.row != prev_edited_row {
 9941                row_delta = 0;
 9942            }
 9943            prev_edited_row = selection.end.row;
 9944
 9945            row_delta =
 9946                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9947        }
 9948
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9951            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9952        });
 9953    }
 9954
 9955    fn indent_selection(
 9956        buffer: &MultiBuffer,
 9957        snapshot: &MultiBufferSnapshot,
 9958        selection: &mut Selection<Point>,
 9959        edits: &mut Vec<(Range<Point>, String)>,
 9960        delta_for_start_row: u32,
 9961        cx: &App,
 9962    ) -> u32 {
 9963        let settings = buffer.language_settings_at(selection.start, cx);
 9964        let tab_size = settings.tab_size.get();
 9965        let indent_kind = if settings.hard_tabs {
 9966            IndentKind::Tab
 9967        } else {
 9968            IndentKind::Space
 9969        };
 9970        let mut start_row = selection.start.row;
 9971        let mut end_row = selection.end.row + 1;
 9972
 9973        // If a selection ends at the beginning of a line, don't indent
 9974        // that last line.
 9975        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9976            end_row -= 1;
 9977        }
 9978
 9979        // Avoid re-indenting a row that has already been indented by a
 9980        // previous selection, but still update this selection's column
 9981        // to reflect that indentation.
 9982        if delta_for_start_row > 0 {
 9983            start_row += 1;
 9984            selection.start.column += delta_for_start_row;
 9985            if selection.end.row == selection.start.row {
 9986                selection.end.column += delta_for_start_row;
 9987            }
 9988        }
 9989
 9990        let mut delta_for_end_row = 0;
 9991        let has_multiple_rows = start_row + 1 != end_row;
 9992        for row in start_row..end_row {
 9993            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9994            let indent_delta = match (current_indent.kind, indent_kind) {
 9995                (IndentKind::Space, IndentKind::Space) => {
 9996                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9997                    IndentSize::spaces(columns_to_next_tab_stop)
 9998                }
 9999                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10000                (_, IndentKind::Tab) => IndentSize::tab(),
10001            };
10002
10003            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10004                0
10005            } else {
10006                selection.start.column
10007            };
10008            let row_start = Point::new(row, start);
10009            edits.push((
10010                row_start..row_start,
10011                indent_delta.chars().collect::<String>(),
10012            ));
10013
10014            // Update this selection's endpoints to reflect the indentation.
10015            if row == selection.start.row {
10016                selection.start.column += indent_delta.len;
10017            }
10018            if row == selection.end.row {
10019                selection.end.column += indent_delta.len;
10020                delta_for_end_row = indent_delta.len;
10021            }
10022        }
10023
10024        if selection.start.row == selection.end.row {
10025            delta_for_start_row + delta_for_end_row
10026        } else {
10027            delta_for_end_row
10028        }
10029    }
10030
10031    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10032        if self.read_only(cx) {
10033            return;
10034        }
10035        if self.mode.is_single_line() {
10036            cx.propagate();
10037            return;
10038        }
10039
10040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10041        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10042        let selections = self.selections.all::<Point>(cx);
10043        let mut deletion_ranges = Vec::new();
10044        let mut last_outdent = None;
10045        {
10046            let buffer = self.buffer.read(cx);
10047            let snapshot = buffer.snapshot(cx);
10048            for selection in &selections {
10049                let settings = buffer.language_settings_at(selection.start, cx);
10050                let tab_size = settings.tab_size.get();
10051                let mut rows = selection.spanned_rows(false, &display_map);
10052
10053                // Avoid re-outdenting a row that has already been outdented by a
10054                // previous selection.
10055                if let Some(last_row) = last_outdent {
10056                    if last_row == rows.start {
10057                        rows.start = rows.start.next_row();
10058                    }
10059                }
10060                let has_multiple_rows = rows.len() > 1;
10061                for row in rows.iter_rows() {
10062                    let indent_size = snapshot.indent_size_for_line(row);
10063                    if indent_size.len > 0 {
10064                        let deletion_len = match indent_size.kind {
10065                            IndentKind::Space => {
10066                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10067                                if columns_to_prev_tab_stop == 0 {
10068                                    tab_size
10069                                } else {
10070                                    columns_to_prev_tab_stop
10071                                }
10072                            }
10073                            IndentKind::Tab => 1,
10074                        };
10075                        let start = if has_multiple_rows
10076                            || deletion_len > selection.start.column
10077                            || indent_size.len < selection.start.column
10078                        {
10079                            0
10080                        } else {
10081                            selection.start.column - deletion_len
10082                        };
10083                        deletion_ranges.push(
10084                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10085                        );
10086                        last_outdent = Some(row);
10087                    }
10088                }
10089            }
10090        }
10091
10092        self.transact(window, cx, |this, window, cx| {
10093            this.buffer.update(cx, |buffer, cx| {
10094                let empty_str: Arc<str> = Arc::default();
10095                buffer.edit(
10096                    deletion_ranges
10097                        .into_iter()
10098                        .map(|range| (range, empty_str.clone())),
10099                    None,
10100                    cx,
10101                );
10102            });
10103            let selections = this.selections.all::<usize>(cx);
10104            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10105        });
10106    }
10107
10108    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10109        if self.read_only(cx) {
10110            return;
10111        }
10112        if self.mode.is_single_line() {
10113            cx.propagate();
10114            return;
10115        }
10116
10117        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10118        let selections = self
10119            .selections
10120            .all::<usize>(cx)
10121            .into_iter()
10122            .map(|s| s.range());
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |buffer, cx| {
10126                buffer.autoindent_ranges(selections, cx);
10127            });
10128            let selections = this.selections.all::<usize>(cx);
10129            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10130        });
10131    }
10132
10133    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10135        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10136        let selections = self.selections.all::<Point>(cx);
10137
10138        let mut new_cursors = Vec::new();
10139        let mut edit_ranges = Vec::new();
10140        let mut selections = selections.iter().peekable();
10141        while let Some(selection) = selections.next() {
10142            let mut rows = selection.spanned_rows(false, &display_map);
10143            let goal_display_column = selection.head().to_display_point(&display_map).column();
10144
10145            // Accumulate contiguous regions of rows that we want to delete.
10146            while let Some(next_selection) = selections.peek() {
10147                let next_rows = next_selection.spanned_rows(false, &display_map);
10148                if next_rows.start <= rows.end {
10149                    rows.end = next_rows.end;
10150                    selections.next().unwrap();
10151                } else {
10152                    break;
10153                }
10154            }
10155
10156            let buffer = &display_map.buffer_snapshot;
10157            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10158            let edit_end;
10159            let cursor_buffer_row;
10160            if buffer.max_point().row >= rows.end.0 {
10161                // If there's a line after the range, delete the \n from the end of the row range
10162                // and position the cursor on the next line.
10163                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10164                cursor_buffer_row = rows.end;
10165            } else {
10166                // If there isn't a line after the range, delete the \n from the line before the
10167                // start of the row range and position the cursor there.
10168                edit_start = edit_start.saturating_sub(1);
10169                edit_end = buffer.len();
10170                cursor_buffer_row = rows.start.previous_row();
10171            }
10172
10173            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10174            *cursor.column_mut() =
10175                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10176
10177            new_cursors.push((
10178                selection.id,
10179                buffer.anchor_after(cursor.to_point(&display_map)),
10180            ));
10181            edit_ranges.push(edit_start..edit_end);
10182        }
10183
10184        self.transact(window, cx, |this, window, cx| {
10185            let buffer = this.buffer.update(cx, |buffer, cx| {
10186                let empty_str: Arc<str> = Arc::default();
10187                buffer.edit(
10188                    edit_ranges
10189                        .into_iter()
10190                        .map(|range| (range, empty_str.clone())),
10191                    None,
10192                    cx,
10193                );
10194                buffer.snapshot(cx)
10195            });
10196            let new_selections = new_cursors
10197                .into_iter()
10198                .map(|(id, cursor)| {
10199                    let cursor = cursor.to_point(&buffer);
10200                    Selection {
10201                        id,
10202                        start: cursor,
10203                        end: cursor,
10204                        reversed: false,
10205                        goal: SelectionGoal::None,
10206                    }
10207                })
10208                .collect();
10209
10210            this.change_selections(Default::default(), window, cx, |s| {
10211                s.select(new_selections);
10212            });
10213        });
10214    }
10215
10216    pub fn join_lines_impl(
10217        &mut self,
10218        insert_whitespace: bool,
10219        window: &mut Window,
10220        cx: &mut Context<Self>,
10221    ) {
10222        if self.read_only(cx) {
10223            return;
10224        }
10225        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10226        for selection in self.selections.all::<Point>(cx) {
10227            let start = MultiBufferRow(selection.start.row);
10228            // Treat single line selections as if they include the next line. Otherwise this action
10229            // would do nothing for single line selections individual cursors.
10230            let end = if selection.start.row == selection.end.row {
10231                MultiBufferRow(selection.start.row + 1)
10232            } else {
10233                MultiBufferRow(selection.end.row)
10234            };
10235
10236            if let Some(last_row_range) = row_ranges.last_mut() {
10237                if start <= last_row_range.end {
10238                    last_row_range.end = end;
10239                    continue;
10240                }
10241            }
10242            row_ranges.push(start..end);
10243        }
10244
10245        let snapshot = self.buffer.read(cx).snapshot(cx);
10246        let mut cursor_positions = Vec::new();
10247        for row_range in &row_ranges {
10248            let anchor = snapshot.anchor_before(Point::new(
10249                row_range.end.previous_row().0,
10250                snapshot.line_len(row_range.end.previous_row()),
10251            ));
10252            cursor_positions.push(anchor..anchor);
10253        }
10254
10255        self.transact(window, cx, |this, window, cx| {
10256            for row_range in row_ranges.into_iter().rev() {
10257                for row in row_range.iter_rows().rev() {
10258                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10259                    let next_line_row = row.next_row();
10260                    let indent = snapshot.indent_size_for_line(next_line_row);
10261                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10262
10263                    let replace =
10264                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10265                            " "
10266                        } else {
10267                            ""
10268                        };
10269
10270                    this.buffer.update(cx, |buffer, cx| {
10271                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10272                    });
10273                }
10274            }
10275
10276            this.change_selections(Default::default(), window, cx, |s| {
10277                s.select_anchor_ranges(cursor_positions)
10278            });
10279        });
10280    }
10281
10282    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10283        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10284        self.join_lines_impl(true, window, cx);
10285    }
10286
10287    pub fn sort_lines_case_sensitive(
10288        &mut self,
10289        _: &SortLinesCaseSensitive,
10290        window: &mut Window,
10291        cx: &mut Context<Self>,
10292    ) {
10293        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10294    }
10295
10296    pub fn sort_lines_by_length(
10297        &mut self,
10298        _: &SortLinesByLength,
10299        window: &mut Window,
10300        cx: &mut Context<Self>,
10301    ) {
10302        self.manipulate_immutable_lines(window, cx, |lines| {
10303            lines.sort_by_key(|&line| line.chars().count())
10304        })
10305    }
10306
10307    pub fn sort_lines_case_insensitive(
10308        &mut self,
10309        _: &SortLinesCaseInsensitive,
10310        window: &mut Window,
10311        cx: &mut Context<Self>,
10312    ) {
10313        self.manipulate_immutable_lines(window, cx, |lines| {
10314            lines.sort_by_key(|line| line.to_lowercase())
10315        })
10316    }
10317
10318    pub fn unique_lines_case_insensitive(
10319        &mut self,
10320        _: &UniqueLinesCaseInsensitive,
10321        window: &mut Window,
10322        cx: &mut Context<Self>,
10323    ) {
10324        self.manipulate_immutable_lines(window, cx, |lines| {
10325            let mut seen = HashSet::default();
10326            lines.retain(|line| seen.insert(line.to_lowercase()));
10327        })
10328    }
10329
10330    pub fn unique_lines_case_sensitive(
10331        &mut self,
10332        _: &UniqueLinesCaseSensitive,
10333        window: &mut Window,
10334        cx: &mut Context<Self>,
10335    ) {
10336        self.manipulate_immutable_lines(window, cx, |lines| {
10337            let mut seen = HashSet::default();
10338            lines.retain(|line| seen.insert(*line));
10339        })
10340    }
10341
10342    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10343        let Some(project) = self.project.clone() else {
10344            return;
10345        };
10346        self.reload(project, window, cx)
10347            .detach_and_notify_err(window, cx);
10348    }
10349
10350    pub fn restore_file(
10351        &mut self,
10352        _: &::git::RestoreFile,
10353        window: &mut Window,
10354        cx: &mut Context<Self>,
10355    ) {
10356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10357        let mut buffer_ids = HashSet::default();
10358        let snapshot = self.buffer().read(cx).snapshot(cx);
10359        for selection in self.selections.all::<usize>(cx) {
10360            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10361        }
10362
10363        let buffer = self.buffer().read(cx);
10364        let ranges = buffer_ids
10365            .into_iter()
10366            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10367            .collect::<Vec<_>>();
10368
10369        self.restore_hunks_in_ranges(ranges, window, cx);
10370    }
10371
10372    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10374        let selections = self
10375            .selections
10376            .all(cx)
10377            .into_iter()
10378            .map(|s| s.range())
10379            .collect();
10380        self.restore_hunks_in_ranges(selections, window, cx);
10381    }
10382
10383    pub fn restore_hunks_in_ranges(
10384        &mut self,
10385        ranges: Vec<Range<Point>>,
10386        window: &mut Window,
10387        cx: &mut Context<Editor>,
10388    ) {
10389        let mut revert_changes = HashMap::default();
10390        let chunk_by = self
10391            .snapshot(window, cx)
10392            .hunks_for_ranges(ranges)
10393            .into_iter()
10394            .chunk_by(|hunk| hunk.buffer_id);
10395        for (buffer_id, hunks) in &chunk_by {
10396            let hunks = hunks.collect::<Vec<_>>();
10397            for hunk in &hunks {
10398                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10399            }
10400            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10401        }
10402        drop(chunk_by);
10403        if !revert_changes.is_empty() {
10404            self.transact(window, cx, |editor, window, cx| {
10405                editor.restore(revert_changes, window, cx);
10406            });
10407        }
10408    }
10409
10410    pub fn open_active_item_in_terminal(
10411        &mut self,
10412        _: &OpenInTerminal,
10413        window: &mut Window,
10414        cx: &mut Context<Self>,
10415    ) {
10416        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10417            let project_path = buffer.read(cx).project_path(cx)?;
10418            let project = self.project.as_ref()?.read(cx);
10419            let entry = project.entry_for_path(&project_path, cx)?;
10420            let parent = match &entry.canonical_path {
10421                Some(canonical_path) => canonical_path.to_path_buf(),
10422                None => project.absolute_path(&project_path, cx)?,
10423            }
10424            .parent()?
10425            .to_path_buf();
10426            Some(parent)
10427        }) {
10428            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10429        }
10430    }
10431
10432    fn set_breakpoint_context_menu(
10433        &mut self,
10434        display_row: DisplayRow,
10435        position: Option<Anchor>,
10436        clicked_point: gpui::Point<Pixels>,
10437        window: &mut Window,
10438        cx: &mut Context<Self>,
10439    ) {
10440        let source = self
10441            .buffer
10442            .read(cx)
10443            .snapshot(cx)
10444            .anchor_before(Point::new(display_row.0, 0u32));
10445
10446        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10447
10448        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10449            self,
10450            source,
10451            clicked_point,
10452            context_menu,
10453            window,
10454            cx,
10455        );
10456    }
10457
10458    fn add_edit_breakpoint_block(
10459        &mut self,
10460        anchor: Anchor,
10461        breakpoint: &Breakpoint,
10462        edit_action: BreakpointPromptEditAction,
10463        window: &mut Window,
10464        cx: &mut Context<Self>,
10465    ) {
10466        let weak_editor = cx.weak_entity();
10467        let bp_prompt = cx.new(|cx| {
10468            BreakpointPromptEditor::new(
10469                weak_editor,
10470                anchor,
10471                breakpoint.clone(),
10472                edit_action,
10473                window,
10474                cx,
10475            )
10476        });
10477
10478        let height = bp_prompt.update(cx, |this, cx| {
10479            this.prompt
10480                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10481        });
10482        let cloned_prompt = bp_prompt.clone();
10483        let blocks = vec![BlockProperties {
10484            style: BlockStyle::Sticky,
10485            placement: BlockPlacement::Above(anchor),
10486            height: Some(height),
10487            render: Arc::new(move |cx| {
10488                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10489                cloned_prompt.clone().into_any_element()
10490            }),
10491            priority: 0,
10492        }];
10493
10494        let focus_handle = bp_prompt.focus_handle(cx);
10495        window.focus(&focus_handle);
10496
10497        let block_ids = self.insert_blocks(blocks, None, cx);
10498        bp_prompt.update(cx, |prompt, _| {
10499            prompt.add_block_ids(block_ids);
10500        });
10501    }
10502
10503    pub(crate) fn breakpoint_at_row(
10504        &self,
10505        row: u32,
10506        window: &mut Window,
10507        cx: &mut Context<Self>,
10508    ) -> Option<(Anchor, Breakpoint)> {
10509        let snapshot = self.snapshot(window, cx);
10510        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10511
10512        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10513    }
10514
10515    pub(crate) fn breakpoint_at_anchor(
10516        &self,
10517        breakpoint_position: Anchor,
10518        snapshot: &EditorSnapshot,
10519        cx: &mut Context<Self>,
10520    ) -> Option<(Anchor, Breakpoint)> {
10521        let project = self.project.clone()?;
10522
10523        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10524            snapshot
10525                .buffer_snapshot
10526                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10527        })?;
10528
10529        let enclosing_excerpt = breakpoint_position.excerpt_id;
10530        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10531        let buffer_snapshot = buffer.read(cx).snapshot();
10532
10533        let row = buffer_snapshot
10534            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10535            .row;
10536
10537        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10538        let anchor_end = snapshot
10539            .buffer_snapshot
10540            .anchor_after(Point::new(row, line_len));
10541
10542        let bp = self
10543            .breakpoint_store
10544            .as_ref()?
10545            .read_with(cx, |breakpoint_store, cx| {
10546                breakpoint_store
10547                    .breakpoints(
10548                        &buffer,
10549                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10550                        &buffer_snapshot,
10551                        cx,
10552                    )
10553                    .next()
10554                    .and_then(|(bp, _)| {
10555                        let breakpoint_row = buffer_snapshot
10556                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10557                            .row;
10558
10559                        if breakpoint_row == row {
10560                            snapshot
10561                                .buffer_snapshot
10562                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10563                                .map(|position| (position, bp.bp.clone()))
10564                        } else {
10565                            None
10566                        }
10567                    })
10568            });
10569        bp
10570    }
10571
10572    pub fn edit_log_breakpoint(
10573        &mut self,
10574        _: &EditLogBreakpoint,
10575        window: &mut Window,
10576        cx: &mut Context<Self>,
10577    ) {
10578        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10579            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10580                message: None,
10581                state: BreakpointState::Enabled,
10582                condition: None,
10583                hit_condition: None,
10584            });
10585
10586            self.add_edit_breakpoint_block(
10587                anchor,
10588                &breakpoint,
10589                BreakpointPromptEditAction::Log,
10590                window,
10591                cx,
10592            );
10593        }
10594    }
10595
10596    fn breakpoints_at_cursors(
10597        &self,
10598        window: &mut Window,
10599        cx: &mut Context<Self>,
10600    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10601        let snapshot = self.snapshot(window, cx);
10602        let cursors = self
10603            .selections
10604            .disjoint_anchors()
10605            .into_iter()
10606            .map(|selection| {
10607                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10608
10609                let breakpoint_position = self
10610                    .breakpoint_at_row(cursor_position.row, window, cx)
10611                    .map(|bp| bp.0)
10612                    .unwrap_or_else(|| {
10613                        snapshot
10614                            .display_snapshot
10615                            .buffer_snapshot
10616                            .anchor_after(Point::new(cursor_position.row, 0))
10617                    });
10618
10619                let breakpoint = self
10620                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10621                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10622
10623                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10624            })
10625            // 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.
10626            .collect::<HashMap<Anchor, _>>();
10627
10628        cursors.into_iter().collect()
10629    }
10630
10631    pub fn enable_breakpoint(
10632        &mut self,
10633        _: &crate::actions::EnableBreakpoint,
10634        window: &mut Window,
10635        cx: &mut Context<Self>,
10636    ) {
10637        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10638            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10639                continue;
10640            };
10641            self.edit_breakpoint_at_anchor(
10642                anchor,
10643                breakpoint,
10644                BreakpointEditAction::InvertState,
10645                cx,
10646            );
10647        }
10648    }
10649
10650    pub fn disable_breakpoint(
10651        &mut self,
10652        _: &crate::actions::DisableBreakpoint,
10653        window: &mut Window,
10654        cx: &mut Context<Self>,
10655    ) {
10656        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10657            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10658                continue;
10659            };
10660            self.edit_breakpoint_at_anchor(
10661                anchor,
10662                breakpoint,
10663                BreakpointEditAction::InvertState,
10664                cx,
10665            );
10666        }
10667    }
10668
10669    pub fn toggle_breakpoint(
10670        &mut self,
10671        _: &crate::actions::ToggleBreakpoint,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10676            if let Some(breakpoint) = breakpoint {
10677                self.edit_breakpoint_at_anchor(
10678                    anchor,
10679                    breakpoint,
10680                    BreakpointEditAction::Toggle,
10681                    cx,
10682                );
10683            } else {
10684                self.edit_breakpoint_at_anchor(
10685                    anchor,
10686                    Breakpoint::new_standard(),
10687                    BreakpointEditAction::Toggle,
10688                    cx,
10689                );
10690            }
10691        }
10692    }
10693
10694    pub fn edit_breakpoint_at_anchor(
10695        &mut self,
10696        breakpoint_position: Anchor,
10697        breakpoint: Breakpoint,
10698        edit_action: BreakpointEditAction,
10699        cx: &mut Context<Self>,
10700    ) {
10701        let Some(breakpoint_store) = &self.breakpoint_store else {
10702            return;
10703        };
10704
10705        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10706            if breakpoint_position == Anchor::min() {
10707                self.buffer()
10708                    .read(cx)
10709                    .excerpt_buffer_ids()
10710                    .into_iter()
10711                    .next()
10712            } else {
10713                None
10714            }
10715        }) else {
10716            return;
10717        };
10718
10719        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10720            return;
10721        };
10722
10723        breakpoint_store.update(cx, |breakpoint_store, cx| {
10724            breakpoint_store.toggle_breakpoint(
10725                buffer,
10726                BreakpointWithPosition {
10727                    position: breakpoint_position.text_anchor,
10728                    bp: breakpoint,
10729                },
10730                edit_action,
10731                cx,
10732            );
10733        });
10734
10735        cx.notify();
10736    }
10737
10738    #[cfg(any(test, feature = "test-support"))]
10739    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10740        self.breakpoint_store.clone()
10741    }
10742
10743    pub fn prepare_restore_change(
10744        &self,
10745        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10746        hunk: &MultiBufferDiffHunk,
10747        cx: &mut App,
10748    ) -> Option<()> {
10749        if hunk.is_created_file() {
10750            return None;
10751        }
10752        let buffer = self.buffer.read(cx);
10753        let diff = buffer.diff_for(hunk.buffer_id)?;
10754        let buffer = buffer.buffer(hunk.buffer_id)?;
10755        let buffer = buffer.read(cx);
10756        let original_text = diff
10757            .read(cx)
10758            .base_text()
10759            .as_rope()
10760            .slice(hunk.diff_base_byte_range.clone());
10761        let buffer_snapshot = buffer.snapshot();
10762        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10763        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10764            probe
10765                .0
10766                .start
10767                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10768                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10769        }) {
10770            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10771            Some(())
10772        } else {
10773            None
10774        }
10775    }
10776
10777    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10778        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10779    }
10780
10781    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10782        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10783    }
10784
10785    fn manipulate_lines<M>(
10786        &mut self,
10787        window: &mut Window,
10788        cx: &mut Context<Self>,
10789        mut manipulate: M,
10790    ) where
10791        M: FnMut(&str) -> LineManipulationResult,
10792    {
10793        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10794
10795        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10796        let buffer = self.buffer.read(cx).snapshot(cx);
10797
10798        let mut edits = Vec::new();
10799
10800        let selections = self.selections.all::<Point>(cx);
10801        let mut selections = selections.iter().peekable();
10802        let mut contiguous_row_selections = Vec::new();
10803        let mut new_selections = Vec::new();
10804        let mut added_lines = 0;
10805        let mut removed_lines = 0;
10806
10807        while let Some(selection) = selections.next() {
10808            let (start_row, end_row) = consume_contiguous_rows(
10809                &mut contiguous_row_selections,
10810                selection,
10811                &display_map,
10812                &mut selections,
10813            );
10814
10815            let start_point = Point::new(start_row.0, 0);
10816            let end_point = Point::new(
10817                end_row.previous_row().0,
10818                buffer.line_len(end_row.previous_row()),
10819            );
10820            let text = buffer
10821                .text_for_range(start_point..end_point)
10822                .collect::<String>();
10823
10824            let LineManipulationResult {
10825                new_text,
10826                line_count_before,
10827                line_count_after,
10828            } = manipulate(&text);
10829
10830            edits.push((start_point..end_point, new_text));
10831
10832            // Selections must change based on added and removed line count
10833            let start_row =
10834                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10835            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10836            new_selections.push(Selection {
10837                id: selection.id,
10838                start: start_row,
10839                end: end_row,
10840                goal: SelectionGoal::None,
10841                reversed: selection.reversed,
10842            });
10843
10844            if line_count_after > line_count_before {
10845                added_lines += line_count_after - line_count_before;
10846            } else if line_count_before > line_count_after {
10847                removed_lines += line_count_before - line_count_after;
10848            }
10849        }
10850
10851        self.transact(window, cx, |this, window, cx| {
10852            let buffer = this.buffer.update(cx, |buffer, cx| {
10853                buffer.edit(edits, None, cx);
10854                buffer.snapshot(cx)
10855            });
10856
10857            // Recalculate offsets on newly edited buffer
10858            let new_selections = new_selections
10859                .iter()
10860                .map(|s| {
10861                    let start_point = Point::new(s.start.0, 0);
10862                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10863                    Selection {
10864                        id: s.id,
10865                        start: buffer.point_to_offset(start_point),
10866                        end: buffer.point_to_offset(end_point),
10867                        goal: s.goal,
10868                        reversed: s.reversed,
10869                    }
10870                })
10871                .collect();
10872
10873            this.change_selections(Default::default(), window, cx, |s| {
10874                s.select(new_selections);
10875            });
10876
10877            this.request_autoscroll(Autoscroll::fit(), cx);
10878        });
10879    }
10880
10881    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10882        self.manipulate_text(window, cx, |text| {
10883            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10884            if has_upper_case_characters {
10885                text.to_lowercase()
10886            } else {
10887                text.to_uppercase()
10888            }
10889        })
10890    }
10891
10892    fn manipulate_immutable_lines<Fn>(
10893        &mut self,
10894        window: &mut Window,
10895        cx: &mut Context<Self>,
10896        mut callback: Fn,
10897    ) where
10898        Fn: FnMut(&mut Vec<&str>),
10899    {
10900        self.manipulate_lines(window, cx, |text| {
10901            let mut lines: Vec<&str> = text.split('\n').collect();
10902            let line_count_before = lines.len();
10903
10904            callback(&mut lines);
10905
10906            LineManipulationResult {
10907                new_text: lines.join("\n"),
10908                line_count_before,
10909                line_count_after: lines.len(),
10910            }
10911        });
10912    }
10913
10914    fn manipulate_mutable_lines<Fn>(
10915        &mut self,
10916        window: &mut Window,
10917        cx: &mut Context<Self>,
10918        mut callback: Fn,
10919    ) where
10920        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10921    {
10922        self.manipulate_lines(window, cx, |text| {
10923            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10924            let line_count_before = lines.len();
10925
10926            callback(&mut lines);
10927
10928            LineManipulationResult {
10929                new_text: lines.join("\n"),
10930                line_count_before,
10931                line_count_after: lines.len(),
10932            }
10933        });
10934    }
10935
10936    pub fn convert_indentation_to_spaces(
10937        &mut self,
10938        _: &ConvertIndentationToSpaces,
10939        window: &mut Window,
10940        cx: &mut Context<Self>,
10941    ) {
10942        let settings = self.buffer.read(cx).language_settings(cx);
10943        let tab_size = settings.tab_size.get() as usize;
10944
10945        self.manipulate_mutable_lines(window, cx, |lines| {
10946            // Allocates a reasonably sized scratch buffer once for the whole loop
10947            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10948            // Avoids recomputing spaces that could be inserted many times
10949            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10950                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10951                .collect();
10952
10953            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10954                let mut chars = line.as_ref().chars();
10955                let mut col = 0;
10956                let mut changed = false;
10957
10958                while let Some(ch) = chars.next() {
10959                    match ch {
10960                        ' ' => {
10961                            reindented_line.push(' ');
10962                            col += 1;
10963                        }
10964                        '\t' => {
10965                            // \t are converted to spaces depending on the current column
10966                            let spaces_len = tab_size - (col % tab_size);
10967                            reindented_line.extend(&space_cache[spaces_len - 1]);
10968                            col += spaces_len;
10969                            changed = true;
10970                        }
10971                        _ => {
10972                            // If we dont append before break, the character is consumed
10973                            reindented_line.push(ch);
10974                            break;
10975                        }
10976                    }
10977                }
10978
10979                if !changed {
10980                    reindented_line.clear();
10981                    continue;
10982                }
10983                // Append the rest of the line and replace old reference with new one
10984                reindented_line.extend(chars);
10985                *line = Cow::Owned(reindented_line.clone());
10986                reindented_line.clear();
10987            }
10988        });
10989    }
10990
10991    pub fn convert_indentation_to_tabs(
10992        &mut self,
10993        _: &ConvertIndentationToTabs,
10994        window: &mut Window,
10995        cx: &mut Context<Self>,
10996    ) {
10997        let settings = self.buffer.read(cx).language_settings(cx);
10998        let tab_size = settings.tab_size.get() as usize;
10999
11000        self.manipulate_mutable_lines(window, cx, |lines| {
11001            // Allocates a reasonably sized buffer once for the whole loop
11002            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11003            // Avoids recomputing spaces that could be inserted many times
11004            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11005                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11006                .collect();
11007
11008            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11009                let mut chars = line.chars();
11010                let mut spaces_count = 0;
11011                let mut first_non_indent_char = None;
11012                let mut changed = false;
11013
11014                while let Some(ch) = chars.next() {
11015                    match ch {
11016                        ' ' => {
11017                            // Keep track of spaces. Append \t when we reach tab_size
11018                            spaces_count += 1;
11019                            changed = true;
11020                            if spaces_count == tab_size {
11021                                reindented_line.push('\t');
11022                                spaces_count = 0;
11023                            }
11024                        }
11025                        '\t' => {
11026                            reindented_line.push('\t');
11027                            spaces_count = 0;
11028                        }
11029                        _ => {
11030                            // Dont append it yet, we might have remaining spaces
11031                            first_non_indent_char = Some(ch);
11032                            break;
11033                        }
11034                    }
11035                }
11036
11037                if !changed {
11038                    reindented_line.clear();
11039                    continue;
11040                }
11041                // Remaining spaces that didn't make a full tab stop
11042                if spaces_count > 0 {
11043                    reindented_line.extend(&space_cache[spaces_count - 1]);
11044                }
11045                // If we consume an extra character that was not indentation, add it back
11046                if let Some(extra_char) = first_non_indent_char {
11047                    reindented_line.push(extra_char);
11048                }
11049                // Append the rest of the line and replace old reference with new one
11050                reindented_line.extend(chars);
11051                *line = Cow::Owned(reindented_line.clone());
11052                reindented_line.clear();
11053            }
11054        });
11055    }
11056
11057    pub fn convert_to_upper_case(
11058        &mut self,
11059        _: &ConvertToUpperCase,
11060        window: &mut Window,
11061        cx: &mut Context<Self>,
11062    ) {
11063        self.manipulate_text(window, cx, |text| text.to_uppercase())
11064    }
11065
11066    pub fn convert_to_lower_case(
11067        &mut self,
11068        _: &ConvertToLowerCase,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071    ) {
11072        self.manipulate_text(window, cx, |text| text.to_lowercase())
11073    }
11074
11075    pub fn convert_to_title_case(
11076        &mut self,
11077        _: &ConvertToTitleCase,
11078        window: &mut Window,
11079        cx: &mut Context<Self>,
11080    ) {
11081        self.manipulate_text(window, cx, |text| {
11082            text.split('\n')
11083                .map(|line| line.to_case(Case::Title))
11084                .join("\n")
11085        })
11086    }
11087
11088    pub fn convert_to_snake_case(
11089        &mut self,
11090        _: &ConvertToSnakeCase,
11091        window: &mut Window,
11092        cx: &mut Context<Self>,
11093    ) {
11094        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11095    }
11096
11097    pub fn convert_to_kebab_case(
11098        &mut self,
11099        _: &ConvertToKebabCase,
11100        window: &mut Window,
11101        cx: &mut Context<Self>,
11102    ) {
11103        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11104    }
11105
11106    pub fn convert_to_upper_camel_case(
11107        &mut self,
11108        _: &ConvertToUpperCamelCase,
11109        window: &mut Window,
11110        cx: &mut Context<Self>,
11111    ) {
11112        self.manipulate_text(window, cx, |text| {
11113            text.split('\n')
11114                .map(|line| line.to_case(Case::UpperCamel))
11115                .join("\n")
11116        })
11117    }
11118
11119    pub fn convert_to_lower_camel_case(
11120        &mut self,
11121        _: &ConvertToLowerCamelCase,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124    ) {
11125        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11126    }
11127
11128    pub fn convert_to_opposite_case(
11129        &mut self,
11130        _: &ConvertToOppositeCase,
11131        window: &mut Window,
11132        cx: &mut Context<Self>,
11133    ) {
11134        self.manipulate_text(window, cx, |text| {
11135            text.chars()
11136                .fold(String::with_capacity(text.len()), |mut t, c| {
11137                    if c.is_uppercase() {
11138                        t.extend(c.to_lowercase());
11139                    } else {
11140                        t.extend(c.to_uppercase());
11141                    }
11142                    t
11143                })
11144        })
11145    }
11146
11147    pub fn convert_to_rot13(
11148        &mut self,
11149        _: &ConvertToRot13,
11150        window: &mut Window,
11151        cx: &mut Context<Self>,
11152    ) {
11153        self.manipulate_text(window, cx, |text| {
11154            text.chars()
11155                .map(|c| match c {
11156                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11157                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11158                    _ => c,
11159                })
11160                .collect()
11161        })
11162    }
11163
11164    pub fn convert_to_rot47(
11165        &mut self,
11166        _: &ConvertToRot47,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        self.manipulate_text(window, cx, |text| {
11171            text.chars()
11172                .map(|c| {
11173                    let code_point = c as u32;
11174                    if code_point >= 33 && code_point <= 126 {
11175                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11176                    }
11177                    c
11178                })
11179                .collect()
11180        })
11181    }
11182
11183    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11184    where
11185        Fn: FnMut(&str) -> String,
11186    {
11187        let buffer = self.buffer.read(cx).snapshot(cx);
11188
11189        let mut new_selections = Vec::new();
11190        let mut edits = Vec::new();
11191        let mut selection_adjustment = 0i32;
11192
11193        for selection in self.selections.all::<usize>(cx) {
11194            let selection_is_empty = selection.is_empty();
11195
11196            let (start, end) = if selection_is_empty {
11197                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11198                (word_range.start, word_range.end)
11199            } else {
11200                (selection.start, selection.end)
11201            };
11202
11203            let text = buffer.text_for_range(start..end).collect::<String>();
11204            let old_length = text.len() as i32;
11205            let text = callback(&text);
11206
11207            new_selections.push(Selection {
11208                start: (start as i32 - selection_adjustment) as usize,
11209                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11210                goal: SelectionGoal::None,
11211                ..selection
11212            });
11213
11214            selection_adjustment += old_length - text.len() as i32;
11215
11216            edits.push((start..end, text));
11217        }
11218
11219        self.transact(window, cx, |this, window, cx| {
11220            this.buffer.update(cx, |buffer, cx| {
11221                buffer.edit(edits, None, cx);
11222            });
11223
11224            this.change_selections(Default::default(), window, cx, |s| {
11225                s.select(new_selections);
11226            });
11227
11228            this.request_autoscroll(Autoscroll::fit(), cx);
11229        });
11230    }
11231
11232    pub fn move_selection_on_drop(
11233        &mut self,
11234        selection: &Selection<Anchor>,
11235        target: DisplayPoint,
11236        is_cut: bool,
11237        window: &mut Window,
11238        cx: &mut Context<Self>,
11239    ) {
11240        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11241        let buffer = &display_map.buffer_snapshot;
11242        let mut edits = Vec::new();
11243        let insert_point = display_map
11244            .clip_point(target, Bias::Left)
11245            .to_point(&display_map);
11246        let text = buffer
11247            .text_for_range(selection.start..selection.end)
11248            .collect::<String>();
11249        if is_cut {
11250            edits.push(((selection.start..selection.end), String::new()));
11251        }
11252        let insert_anchor = buffer.anchor_before(insert_point);
11253        edits.push(((insert_anchor..insert_anchor), text));
11254        let last_edit_start = insert_anchor.bias_left(buffer);
11255        let last_edit_end = insert_anchor.bias_right(buffer);
11256        self.transact(window, cx, |this, window, cx| {
11257            this.buffer.update(cx, |buffer, cx| {
11258                buffer.edit(edits, None, cx);
11259            });
11260            this.change_selections(Default::default(), window, cx, |s| {
11261                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11262            });
11263        });
11264    }
11265
11266    pub fn clear_selection_drag_state(&mut self) {
11267        self.selection_drag_state = SelectionDragState::None;
11268    }
11269
11270    pub fn duplicate(
11271        &mut self,
11272        upwards: bool,
11273        whole_lines: bool,
11274        window: &mut Window,
11275        cx: &mut Context<Self>,
11276    ) {
11277        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11278
11279        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11280        let buffer = &display_map.buffer_snapshot;
11281        let selections = self.selections.all::<Point>(cx);
11282
11283        let mut edits = Vec::new();
11284        let mut selections_iter = selections.iter().peekable();
11285        while let Some(selection) = selections_iter.next() {
11286            let mut rows = selection.spanned_rows(false, &display_map);
11287            // duplicate line-wise
11288            if whole_lines || selection.start == selection.end {
11289                // Avoid duplicating the same lines twice.
11290                while let Some(next_selection) = selections_iter.peek() {
11291                    let next_rows = next_selection.spanned_rows(false, &display_map);
11292                    if next_rows.start < rows.end {
11293                        rows.end = next_rows.end;
11294                        selections_iter.next().unwrap();
11295                    } else {
11296                        break;
11297                    }
11298                }
11299
11300                // Copy the text from the selected row region and splice it either at the start
11301                // or end of the region.
11302                let start = Point::new(rows.start.0, 0);
11303                let end = Point::new(
11304                    rows.end.previous_row().0,
11305                    buffer.line_len(rows.end.previous_row()),
11306                );
11307                let text = buffer
11308                    .text_for_range(start..end)
11309                    .chain(Some("\n"))
11310                    .collect::<String>();
11311                let insert_location = if upwards {
11312                    Point::new(rows.end.0, 0)
11313                } else {
11314                    start
11315                };
11316                edits.push((insert_location..insert_location, text));
11317            } else {
11318                // duplicate character-wise
11319                let start = selection.start;
11320                let end = selection.end;
11321                let text = buffer.text_for_range(start..end).collect::<String>();
11322                edits.push((selection.end..selection.end, text));
11323            }
11324        }
11325
11326        self.transact(window, cx, |this, _, cx| {
11327            this.buffer.update(cx, |buffer, cx| {
11328                buffer.edit(edits, None, cx);
11329            });
11330
11331            this.request_autoscroll(Autoscroll::fit(), cx);
11332        });
11333    }
11334
11335    pub fn duplicate_line_up(
11336        &mut self,
11337        _: &DuplicateLineUp,
11338        window: &mut Window,
11339        cx: &mut Context<Self>,
11340    ) {
11341        self.duplicate(true, true, window, cx);
11342    }
11343
11344    pub fn duplicate_line_down(
11345        &mut self,
11346        _: &DuplicateLineDown,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.duplicate(false, true, window, cx);
11351    }
11352
11353    pub fn duplicate_selection(
11354        &mut self,
11355        _: &DuplicateSelection,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.duplicate(false, false, window, cx);
11360    }
11361
11362    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11363        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11364        if self.mode.is_single_line() {
11365            cx.propagate();
11366            return;
11367        }
11368
11369        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11370        let buffer = self.buffer.read(cx).snapshot(cx);
11371
11372        let mut edits = Vec::new();
11373        let mut unfold_ranges = Vec::new();
11374        let mut refold_creases = Vec::new();
11375
11376        let selections = self.selections.all::<Point>(cx);
11377        let mut selections = selections.iter().peekable();
11378        let mut contiguous_row_selections = Vec::new();
11379        let mut new_selections = Vec::new();
11380
11381        while let Some(selection) = selections.next() {
11382            // Find all the selections that span a contiguous row range
11383            let (start_row, end_row) = consume_contiguous_rows(
11384                &mut contiguous_row_selections,
11385                selection,
11386                &display_map,
11387                &mut selections,
11388            );
11389
11390            // Move the text spanned by the row range to be before the line preceding the row range
11391            if start_row.0 > 0 {
11392                let range_to_move = Point::new(
11393                    start_row.previous_row().0,
11394                    buffer.line_len(start_row.previous_row()),
11395                )
11396                    ..Point::new(
11397                        end_row.previous_row().0,
11398                        buffer.line_len(end_row.previous_row()),
11399                    );
11400                let insertion_point = display_map
11401                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11402                    .0;
11403
11404                // Don't move lines across excerpts
11405                if buffer
11406                    .excerpt_containing(insertion_point..range_to_move.end)
11407                    .is_some()
11408                {
11409                    let text = buffer
11410                        .text_for_range(range_to_move.clone())
11411                        .flat_map(|s| s.chars())
11412                        .skip(1)
11413                        .chain(['\n'])
11414                        .collect::<String>();
11415
11416                    edits.push((
11417                        buffer.anchor_after(range_to_move.start)
11418                            ..buffer.anchor_before(range_to_move.end),
11419                        String::new(),
11420                    ));
11421                    let insertion_anchor = buffer.anchor_after(insertion_point);
11422                    edits.push((insertion_anchor..insertion_anchor, text));
11423
11424                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11425
11426                    // Move selections up
11427                    new_selections.extend(contiguous_row_selections.drain(..).map(
11428                        |mut selection| {
11429                            selection.start.row -= row_delta;
11430                            selection.end.row -= row_delta;
11431                            selection
11432                        },
11433                    ));
11434
11435                    // Move folds up
11436                    unfold_ranges.push(range_to_move.clone());
11437                    for fold in display_map.folds_in_range(
11438                        buffer.anchor_before(range_to_move.start)
11439                            ..buffer.anchor_after(range_to_move.end),
11440                    ) {
11441                        let mut start = fold.range.start.to_point(&buffer);
11442                        let mut end = fold.range.end.to_point(&buffer);
11443                        start.row -= row_delta;
11444                        end.row -= row_delta;
11445                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11446                    }
11447                }
11448            }
11449
11450            // If we didn't move line(s), preserve the existing selections
11451            new_selections.append(&mut contiguous_row_selections);
11452        }
11453
11454        self.transact(window, cx, |this, window, cx| {
11455            this.unfold_ranges(&unfold_ranges, true, true, cx);
11456            this.buffer.update(cx, |buffer, cx| {
11457                for (range, text) in edits {
11458                    buffer.edit([(range, text)], None, cx);
11459                }
11460            });
11461            this.fold_creases(refold_creases, true, window, cx);
11462            this.change_selections(Default::default(), window, cx, |s| {
11463                s.select(new_selections);
11464            })
11465        });
11466    }
11467
11468    pub fn move_line_down(
11469        &mut self,
11470        _: &MoveLineDown,
11471        window: &mut Window,
11472        cx: &mut Context<Self>,
11473    ) {
11474        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11475        if self.mode.is_single_line() {
11476            cx.propagate();
11477            return;
11478        }
11479
11480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11481        let buffer = self.buffer.read(cx).snapshot(cx);
11482
11483        let mut edits = Vec::new();
11484        let mut unfold_ranges = Vec::new();
11485        let mut refold_creases = Vec::new();
11486
11487        let selections = self.selections.all::<Point>(cx);
11488        let mut selections = selections.iter().peekable();
11489        let mut contiguous_row_selections = Vec::new();
11490        let mut new_selections = Vec::new();
11491
11492        while let Some(selection) = selections.next() {
11493            // Find all the selections that span a contiguous row range
11494            let (start_row, end_row) = consume_contiguous_rows(
11495                &mut contiguous_row_selections,
11496                selection,
11497                &display_map,
11498                &mut selections,
11499            );
11500
11501            // Move the text spanned by the row range to be after the last line of the row range
11502            if end_row.0 <= buffer.max_point().row {
11503                let range_to_move =
11504                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11505                let insertion_point = display_map
11506                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11507                    .0;
11508
11509                // Don't move lines across excerpt boundaries
11510                if buffer
11511                    .excerpt_containing(range_to_move.start..insertion_point)
11512                    .is_some()
11513                {
11514                    let mut text = String::from("\n");
11515                    text.extend(buffer.text_for_range(range_to_move.clone()));
11516                    text.pop(); // Drop trailing newline
11517                    edits.push((
11518                        buffer.anchor_after(range_to_move.start)
11519                            ..buffer.anchor_before(range_to_move.end),
11520                        String::new(),
11521                    ));
11522                    let insertion_anchor = buffer.anchor_after(insertion_point);
11523                    edits.push((insertion_anchor..insertion_anchor, text));
11524
11525                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11526
11527                    // Move selections down
11528                    new_selections.extend(contiguous_row_selections.drain(..).map(
11529                        |mut selection| {
11530                            selection.start.row += row_delta;
11531                            selection.end.row += row_delta;
11532                            selection
11533                        },
11534                    ));
11535
11536                    // Move folds down
11537                    unfold_ranges.push(range_to_move.clone());
11538                    for fold in display_map.folds_in_range(
11539                        buffer.anchor_before(range_to_move.start)
11540                            ..buffer.anchor_after(range_to_move.end),
11541                    ) {
11542                        let mut start = fold.range.start.to_point(&buffer);
11543                        let mut end = fold.range.end.to_point(&buffer);
11544                        start.row += row_delta;
11545                        end.row += row_delta;
11546                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11547                    }
11548                }
11549            }
11550
11551            // If we didn't move line(s), preserve the existing selections
11552            new_selections.append(&mut contiguous_row_selections);
11553        }
11554
11555        self.transact(window, cx, |this, window, cx| {
11556            this.unfold_ranges(&unfold_ranges, true, true, cx);
11557            this.buffer.update(cx, |buffer, cx| {
11558                for (range, text) in edits {
11559                    buffer.edit([(range, text)], None, cx);
11560                }
11561            });
11562            this.fold_creases(refold_creases, true, window, cx);
11563            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11564        });
11565    }
11566
11567    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11569        let text_layout_details = &self.text_layout_details(window);
11570        self.transact(window, cx, |this, window, cx| {
11571            let edits = this.change_selections(Default::default(), window, cx, |s| {
11572                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11573                s.move_with(|display_map, selection| {
11574                    if !selection.is_empty() {
11575                        return;
11576                    }
11577
11578                    let mut head = selection.head();
11579                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11580                    if head.column() == display_map.line_len(head.row()) {
11581                        transpose_offset = display_map
11582                            .buffer_snapshot
11583                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11584                    }
11585
11586                    if transpose_offset == 0 {
11587                        return;
11588                    }
11589
11590                    *head.column_mut() += 1;
11591                    head = display_map.clip_point(head, Bias::Right);
11592                    let goal = SelectionGoal::HorizontalPosition(
11593                        display_map
11594                            .x_for_display_point(head, text_layout_details)
11595                            .into(),
11596                    );
11597                    selection.collapse_to(head, goal);
11598
11599                    let transpose_start = display_map
11600                        .buffer_snapshot
11601                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11602                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11603                        let transpose_end = display_map
11604                            .buffer_snapshot
11605                            .clip_offset(transpose_offset + 1, Bias::Right);
11606                        if let Some(ch) =
11607                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11608                        {
11609                            edits.push((transpose_start..transpose_offset, String::new()));
11610                            edits.push((transpose_end..transpose_end, ch.to_string()));
11611                        }
11612                    }
11613                });
11614                edits
11615            });
11616            this.buffer
11617                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11618            let selections = this.selections.all::<usize>(cx);
11619            this.change_selections(Default::default(), window, cx, |s| {
11620                s.select(selections);
11621            });
11622        });
11623    }
11624
11625    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11627        if self.mode.is_single_line() {
11628            cx.propagate();
11629            return;
11630        }
11631
11632        self.rewrap_impl(RewrapOptions::default(), cx)
11633    }
11634
11635    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11636        let buffer = self.buffer.read(cx).snapshot(cx);
11637        let selections = self.selections.all::<Point>(cx);
11638
11639        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11640        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11641            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11642                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11643                .peekable();
11644
11645            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11646                row
11647            } else {
11648                return Vec::new();
11649            };
11650
11651            let language_settings = buffer.language_settings_at(selection.head(), cx);
11652            let language_scope = buffer.language_scope_at(selection.head());
11653
11654            let indent_and_prefix_for_row =
11655                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11656                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11657                    let (comment_prefix, rewrap_prefix) =
11658                        if let Some(language_scope) = &language_scope {
11659                            let indent_end = Point::new(row, indent.len);
11660                            let comment_prefix = language_scope
11661                                .line_comment_prefixes()
11662                                .iter()
11663                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11664                                .map(|prefix| prefix.to_string());
11665                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11666                            let line_text_after_indent = buffer
11667                                .text_for_range(indent_end..line_end)
11668                                .collect::<String>();
11669                            let rewrap_prefix = language_scope
11670                                .rewrap_prefixes()
11671                                .iter()
11672                                .find_map(|prefix_regex| {
11673                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11674                                        if mat.start() == 0 {
11675                                            Some(mat.as_str().to_string())
11676                                        } else {
11677                                            None
11678                                        }
11679                                    })
11680                                })
11681                                .flatten();
11682                            (comment_prefix, rewrap_prefix)
11683                        } else {
11684                            (None, None)
11685                        };
11686                    (indent, comment_prefix, rewrap_prefix)
11687                };
11688
11689            let mut ranges = Vec::new();
11690            let from_empty_selection = selection.is_empty();
11691
11692            let mut current_range_start = first_row;
11693            let mut prev_row = first_row;
11694            let (
11695                mut current_range_indent,
11696                mut current_range_comment_prefix,
11697                mut current_range_rewrap_prefix,
11698            ) = indent_and_prefix_for_row(first_row);
11699
11700            for row in non_blank_rows_iter.skip(1) {
11701                let has_paragraph_break = row > prev_row + 1;
11702
11703                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11704                    indent_and_prefix_for_row(row);
11705
11706                let has_indent_change = row_indent != current_range_indent;
11707                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11708
11709                let has_boundary_change = has_comment_change
11710                    || row_rewrap_prefix.is_some()
11711                    || (has_indent_change && current_range_comment_prefix.is_some());
11712
11713                if has_paragraph_break || has_boundary_change {
11714                    ranges.push((
11715                        language_settings.clone(),
11716                        Point::new(current_range_start, 0)
11717                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11718                        current_range_indent,
11719                        current_range_comment_prefix.clone(),
11720                        current_range_rewrap_prefix.clone(),
11721                        from_empty_selection,
11722                    ));
11723                    current_range_start = row;
11724                    current_range_indent = row_indent;
11725                    current_range_comment_prefix = row_comment_prefix;
11726                    current_range_rewrap_prefix = row_rewrap_prefix;
11727                }
11728                prev_row = row;
11729            }
11730
11731            ranges.push((
11732                language_settings.clone(),
11733                Point::new(current_range_start, 0)
11734                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11735                current_range_indent,
11736                current_range_comment_prefix,
11737                current_range_rewrap_prefix,
11738                from_empty_selection,
11739            ));
11740
11741            ranges
11742        });
11743
11744        let mut edits = Vec::new();
11745        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11746
11747        for (
11748            language_settings,
11749            wrap_range,
11750            indent_size,
11751            comment_prefix,
11752            rewrap_prefix,
11753            from_empty_selection,
11754        ) in wrap_ranges
11755        {
11756            let mut start_row = wrap_range.start.row;
11757            let mut end_row = wrap_range.end.row;
11758
11759            // Skip selections that overlap with a range that has already been rewrapped.
11760            let selection_range = start_row..end_row;
11761            if rewrapped_row_ranges
11762                .iter()
11763                .any(|range| range.overlaps(&selection_range))
11764            {
11765                continue;
11766            }
11767
11768            let tab_size = language_settings.tab_size;
11769
11770            let indent_prefix = indent_size.chars().collect::<String>();
11771            let mut line_prefix = indent_prefix.clone();
11772            let mut inside_comment = false;
11773            if let Some(prefix) = &comment_prefix {
11774                line_prefix.push_str(prefix);
11775                inside_comment = true;
11776            }
11777            if let Some(prefix) = &rewrap_prefix {
11778                line_prefix.push_str(prefix);
11779            }
11780
11781            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11782                RewrapBehavior::InComments => inside_comment,
11783                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11784                RewrapBehavior::Anywhere => true,
11785            };
11786
11787            let should_rewrap = options.override_language_settings
11788                || allow_rewrap_based_on_language
11789                || self.hard_wrap.is_some();
11790            if !should_rewrap {
11791                continue;
11792            }
11793
11794            if from_empty_selection {
11795                'expand_upwards: while start_row > 0 {
11796                    let prev_row = start_row - 1;
11797                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11798                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11799                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11800                    {
11801                        start_row = prev_row;
11802                    } else {
11803                        break 'expand_upwards;
11804                    }
11805                }
11806
11807                'expand_downwards: while end_row < buffer.max_point().row {
11808                    let next_row = end_row + 1;
11809                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11810                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11811                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11812                    {
11813                        end_row = next_row;
11814                    } else {
11815                        break 'expand_downwards;
11816                    }
11817                }
11818            }
11819
11820            let start = Point::new(start_row, 0);
11821            let start_offset = start.to_offset(&buffer);
11822            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11823            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11824            let Some(lines_without_prefixes) = selection_text
11825                .lines()
11826                .enumerate()
11827                .map(|(ix, line)| {
11828                    let line_trimmed = line.trim_start();
11829                    if rewrap_prefix.is_some() && ix > 0 {
11830                        Ok(line_trimmed)
11831                    } else {
11832                        line_trimmed
11833                            .strip_prefix(&line_prefix.trim_start())
11834                            .with_context(|| {
11835                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11836                            })
11837                    }
11838                })
11839                .collect::<Result<Vec<_>, _>>()
11840                .log_err()
11841            else {
11842                continue;
11843            };
11844
11845            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11846                buffer
11847                    .language_settings_at(Point::new(start_row, 0), cx)
11848                    .preferred_line_length as usize
11849            });
11850
11851            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11852                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11853            } else {
11854                line_prefix.clone()
11855            };
11856
11857            let wrapped_text = wrap_with_prefix(
11858                line_prefix,
11859                subsequent_lines_prefix,
11860                lines_without_prefixes.join("\n"),
11861                wrap_column,
11862                tab_size,
11863                options.preserve_existing_whitespace,
11864            );
11865
11866            // TODO: should always use char-based diff while still supporting cursor behavior that
11867            // matches vim.
11868            let mut diff_options = DiffOptions::default();
11869            if options.override_language_settings {
11870                diff_options.max_word_diff_len = 0;
11871                diff_options.max_word_diff_line_count = 0;
11872            } else {
11873                diff_options.max_word_diff_len = usize::MAX;
11874                diff_options.max_word_diff_line_count = usize::MAX;
11875            }
11876
11877            for (old_range, new_text) in
11878                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11879            {
11880                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11881                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11882                edits.push((edit_start..edit_end, new_text));
11883            }
11884
11885            rewrapped_row_ranges.push(start_row..=end_row);
11886        }
11887
11888        self.buffer
11889            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11890    }
11891
11892    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11893        let mut text = String::new();
11894        let buffer = self.buffer.read(cx).snapshot(cx);
11895        let mut selections = self.selections.all::<Point>(cx);
11896        let mut clipboard_selections = Vec::with_capacity(selections.len());
11897        {
11898            let max_point = buffer.max_point();
11899            let mut is_first = true;
11900            for selection in &mut selections {
11901                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11902                if is_entire_line {
11903                    selection.start = Point::new(selection.start.row, 0);
11904                    if !selection.is_empty() && selection.end.column == 0 {
11905                        selection.end = cmp::min(max_point, selection.end);
11906                    } else {
11907                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11908                    }
11909                    selection.goal = SelectionGoal::None;
11910                }
11911                if is_first {
11912                    is_first = false;
11913                } else {
11914                    text += "\n";
11915                }
11916                let mut len = 0;
11917                for chunk in buffer.text_for_range(selection.start..selection.end) {
11918                    text.push_str(chunk);
11919                    len += chunk.len();
11920                }
11921                clipboard_selections.push(ClipboardSelection {
11922                    len,
11923                    is_entire_line,
11924                    first_line_indent: buffer
11925                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11926                        .len,
11927                });
11928            }
11929        }
11930
11931        self.transact(window, cx, |this, window, cx| {
11932            this.change_selections(Default::default(), window, cx, |s| {
11933                s.select(selections);
11934            });
11935            this.insert("", window, cx);
11936        });
11937        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11938    }
11939
11940    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11942        let item = self.cut_common(window, cx);
11943        cx.write_to_clipboard(item);
11944    }
11945
11946    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11948        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11949            s.move_with(|snapshot, sel| {
11950                if sel.is_empty() {
11951                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11952                }
11953            });
11954        });
11955        let item = self.cut_common(window, cx);
11956        cx.set_global(KillRing(item))
11957    }
11958
11959    pub fn kill_ring_yank(
11960        &mut self,
11961        _: &KillRingYank,
11962        window: &mut Window,
11963        cx: &mut Context<Self>,
11964    ) {
11965        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11966        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11967            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11968                (kill_ring.text().to_string(), kill_ring.metadata_json())
11969            } else {
11970                return;
11971            }
11972        } else {
11973            return;
11974        };
11975        self.do_paste(&text, metadata, false, window, cx);
11976    }
11977
11978    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11979        self.do_copy(true, cx);
11980    }
11981
11982    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11983        self.do_copy(false, cx);
11984    }
11985
11986    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11987        let selections = self.selections.all::<Point>(cx);
11988        let buffer = self.buffer.read(cx).read(cx);
11989        let mut text = String::new();
11990
11991        let mut clipboard_selections = Vec::with_capacity(selections.len());
11992        {
11993            let max_point = buffer.max_point();
11994            let mut is_first = true;
11995            for selection in &selections {
11996                let mut start = selection.start;
11997                let mut end = selection.end;
11998                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11999                if is_entire_line {
12000                    start = Point::new(start.row, 0);
12001                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12002                }
12003
12004                let mut trimmed_selections = Vec::new();
12005                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12006                    let row = MultiBufferRow(start.row);
12007                    let first_indent = buffer.indent_size_for_line(row);
12008                    if first_indent.len == 0 || start.column > first_indent.len {
12009                        trimmed_selections.push(start..end);
12010                    } else {
12011                        trimmed_selections.push(
12012                            Point::new(row.0, first_indent.len)
12013                                ..Point::new(row.0, buffer.line_len(row)),
12014                        );
12015                        for row in start.row + 1..=end.row {
12016                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12017                            if row == end.row {
12018                                line_len = end.column;
12019                            }
12020                            if line_len == 0 {
12021                                trimmed_selections
12022                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12023                                continue;
12024                            }
12025                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12026                            if row_indent_size.len >= first_indent.len {
12027                                trimmed_selections.push(
12028                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12029                                );
12030                            } else {
12031                                trimmed_selections.clear();
12032                                trimmed_selections.push(start..end);
12033                                break;
12034                            }
12035                        }
12036                    }
12037                } else {
12038                    trimmed_selections.push(start..end);
12039                }
12040
12041                for trimmed_range in trimmed_selections {
12042                    if is_first {
12043                        is_first = false;
12044                    } else {
12045                        text += "\n";
12046                    }
12047                    let mut len = 0;
12048                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12049                        text.push_str(chunk);
12050                        len += chunk.len();
12051                    }
12052                    clipboard_selections.push(ClipboardSelection {
12053                        len,
12054                        is_entire_line,
12055                        first_line_indent: buffer
12056                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12057                            .len,
12058                    });
12059                }
12060            }
12061        }
12062
12063        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12064            text,
12065            clipboard_selections,
12066        ));
12067    }
12068
12069    pub fn do_paste(
12070        &mut self,
12071        text: &String,
12072        clipboard_selections: Option<Vec<ClipboardSelection>>,
12073        handle_entire_lines: bool,
12074        window: &mut Window,
12075        cx: &mut Context<Self>,
12076    ) {
12077        if self.read_only(cx) {
12078            return;
12079        }
12080
12081        let clipboard_text = Cow::Borrowed(text);
12082
12083        self.transact(window, cx, |this, window, cx| {
12084            if let Some(mut clipboard_selections) = clipboard_selections {
12085                let old_selections = this.selections.all::<usize>(cx);
12086                let all_selections_were_entire_line =
12087                    clipboard_selections.iter().all(|s| s.is_entire_line);
12088                let first_selection_indent_column =
12089                    clipboard_selections.first().map(|s| s.first_line_indent);
12090                if clipboard_selections.len() != old_selections.len() {
12091                    clipboard_selections.drain(..);
12092                }
12093                let cursor_offset = this.selections.last::<usize>(cx).head();
12094                let mut auto_indent_on_paste = true;
12095
12096                this.buffer.update(cx, |buffer, cx| {
12097                    let snapshot = buffer.read(cx);
12098                    auto_indent_on_paste = snapshot
12099                        .language_settings_at(cursor_offset, cx)
12100                        .auto_indent_on_paste;
12101
12102                    let mut start_offset = 0;
12103                    let mut edits = Vec::new();
12104                    let mut original_indent_columns = Vec::new();
12105                    for (ix, selection) in old_selections.iter().enumerate() {
12106                        let to_insert;
12107                        let entire_line;
12108                        let original_indent_column;
12109                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12110                            let end_offset = start_offset + clipboard_selection.len;
12111                            to_insert = &clipboard_text[start_offset..end_offset];
12112                            entire_line = clipboard_selection.is_entire_line;
12113                            start_offset = end_offset + 1;
12114                            original_indent_column = Some(clipboard_selection.first_line_indent);
12115                        } else {
12116                            to_insert = clipboard_text.as_str();
12117                            entire_line = all_selections_were_entire_line;
12118                            original_indent_column = first_selection_indent_column
12119                        }
12120
12121                        // If the corresponding selection was empty when this slice of the
12122                        // clipboard text was written, then the entire line containing the
12123                        // selection was copied. If this selection is also currently empty,
12124                        // then paste the line before the current line of the buffer.
12125                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12126                            let column = selection.start.to_point(&snapshot).column as usize;
12127                            let line_start = selection.start - column;
12128                            line_start..line_start
12129                        } else {
12130                            selection.range()
12131                        };
12132
12133                        edits.push((range, to_insert));
12134                        original_indent_columns.push(original_indent_column);
12135                    }
12136                    drop(snapshot);
12137
12138                    buffer.edit(
12139                        edits,
12140                        if auto_indent_on_paste {
12141                            Some(AutoindentMode::Block {
12142                                original_indent_columns,
12143                            })
12144                        } else {
12145                            None
12146                        },
12147                        cx,
12148                    );
12149                });
12150
12151                let selections = this.selections.all::<usize>(cx);
12152                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12153            } else {
12154                this.insert(&clipboard_text, window, cx);
12155            }
12156        });
12157    }
12158
12159    pub fn diff_clipboard_with_selection(
12160        &mut self,
12161        _: &DiffClipboardWithSelection,
12162        window: &mut Window,
12163        cx: &mut Context<Self>,
12164    ) {
12165        let selections = self.selections.all::<usize>(cx);
12166
12167        if selections.is_empty() {
12168            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12169            return;
12170        };
12171
12172        let clipboard_text = match cx.read_from_clipboard() {
12173            Some(item) => match item.entries().first() {
12174                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12175                _ => None,
12176            },
12177            None => None,
12178        };
12179
12180        let Some(clipboard_text) = clipboard_text else {
12181            log::warn!("Clipboard doesn't contain text.");
12182            return;
12183        };
12184
12185        window.dispatch_action(
12186            Box::new(DiffClipboardWithSelectionData {
12187                clipboard_text,
12188                editor: cx.entity(),
12189            }),
12190            cx,
12191        );
12192    }
12193
12194    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12195        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12196        if let Some(item) = cx.read_from_clipboard() {
12197            let entries = item.entries();
12198
12199            match entries.first() {
12200                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12201                // of all the pasted entries.
12202                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12203                    .do_paste(
12204                        clipboard_string.text(),
12205                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12206                        true,
12207                        window,
12208                        cx,
12209                    ),
12210                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12211            }
12212        }
12213    }
12214
12215    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12216        if self.read_only(cx) {
12217            return;
12218        }
12219
12220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12221
12222        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12223            if let Some((selections, _)) =
12224                self.selection_history.transaction(transaction_id).cloned()
12225            {
12226                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12227                    s.select_anchors(selections.to_vec());
12228                });
12229            } else {
12230                log::error!(
12231                    "No entry in selection_history found for undo. \
12232                     This may correspond to a bug where undo does not update the selection. \
12233                     If this is occurring, please add details to \
12234                     https://github.com/zed-industries/zed/issues/22692"
12235                );
12236            }
12237            self.request_autoscroll(Autoscroll::fit(), cx);
12238            self.unmark_text(window, cx);
12239            self.refresh_inline_completion(true, false, window, cx);
12240            cx.emit(EditorEvent::Edited { transaction_id });
12241            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12242        }
12243    }
12244
12245    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12246        if self.read_only(cx) {
12247            return;
12248        }
12249
12250        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12251
12252        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12253            if let Some((_, Some(selections))) =
12254                self.selection_history.transaction(transaction_id).cloned()
12255            {
12256                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12257                    s.select_anchors(selections.to_vec());
12258                });
12259            } else {
12260                log::error!(
12261                    "No entry in selection_history found for redo. \
12262                     This may correspond to a bug where undo does not update the selection. \
12263                     If this is occurring, please add details to \
12264                     https://github.com/zed-industries/zed/issues/22692"
12265                );
12266            }
12267            self.request_autoscroll(Autoscroll::fit(), cx);
12268            self.unmark_text(window, cx);
12269            self.refresh_inline_completion(true, false, window, cx);
12270            cx.emit(EditorEvent::Edited { transaction_id });
12271        }
12272    }
12273
12274    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12275        self.buffer
12276            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12277    }
12278
12279    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12280        self.buffer
12281            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12282    }
12283
12284    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12286        self.change_selections(Default::default(), window, cx, |s| {
12287            s.move_with(|map, selection| {
12288                let cursor = if selection.is_empty() {
12289                    movement::left(map, selection.start)
12290                } else {
12291                    selection.start
12292                };
12293                selection.collapse_to(cursor, SelectionGoal::None);
12294            });
12295        })
12296    }
12297
12298    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12300        self.change_selections(Default::default(), window, cx, |s| {
12301            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12302        })
12303    }
12304
12305    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12307        self.change_selections(Default::default(), window, cx, |s| {
12308            s.move_with(|map, selection| {
12309                let cursor = if selection.is_empty() {
12310                    movement::right(map, selection.end)
12311                } else {
12312                    selection.end
12313                };
12314                selection.collapse_to(cursor, SelectionGoal::None)
12315            });
12316        })
12317    }
12318
12319    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12320        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12321        self.change_selections(Default::default(), window, cx, |s| {
12322            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12323        })
12324    }
12325
12326    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12327        if self.take_rename(true, window, cx).is_some() {
12328            return;
12329        }
12330
12331        if self.mode.is_single_line() {
12332            cx.propagate();
12333            return;
12334        }
12335
12336        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12337
12338        let text_layout_details = &self.text_layout_details(window);
12339        let selection_count = self.selections.count();
12340        let first_selection = self.selections.first_anchor();
12341
12342        self.change_selections(Default::default(), window, cx, |s| {
12343            s.move_with(|map, selection| {
12344                if !selection.is_empty() {
12345                    selection.goal = SelectionGoal::None;
12346                }
12347                let (cursor, goal) = movement::up(
12348                    map,
12349                    selection.start,
12350                    selection.goal,
12351                    false,
12352                    text_layout_details,
12353                );
12354                selection.collapse_to(cursor, goal);
12355            });
12356        });
12357
12358        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12359        {
12360            cx.propagate();
12361        }
12362    }
12363
12364    pub fn move_up_by_lines(
12365        &mut self,
12366        action: &MoveUpByLines,
12367        window: &mut Window,
12368        cx: &mut Context<Self>,
12369    ) {
12370        if self.take_rename(true, window, cx).is_some() {
12371            return;
12372        }
12373
12374        if self.mode.is_single_line() {
12375            cx.propagate();
12376            return;
12377        }
12378
12379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12380
12381        let text_layout_details = &self.text_layout_details(window);
12382
12383        self.change_selections(Default::default(), window, cx, |s| {
12384            s.move_with(|map, selection| {
12385                if !selection.is_empty() {
12386                    selection.goal = SelectionGoal::None;
12387                }
12388                let (cursor, goal) = movement::up_by_rows(
12389                    map,
12390                    selection.start,
12391                    action.lines,
12392                    selection.goal,
12393                    false,
12394                    text_layout_details,
12395                );
12396                selection.collapse_to(cursor, goal);
12397            });
12398        })
12399    }
12400
12401    pub fn move_down_by_lines(
12402        &mut self,
12403        action: &MoveDownByLines,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        if self.take_rename(true, window, cx).is_some() {
12408            return;
12409        }
12410
12411        if self.mode.is_single_line() {
12412            cx.propagate();
12413            return;
12414        }
12415
12416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12417
12418        let text_layout_details = &self.text_layout_details(window);
12419
12420        self.change_selections(Default::default(), window, cx, |s| {
12421            s.move_with(|map, selection| {
12422                if !selection.is_empty() {
12423                    selection.goal = SelectionGoal::None;
12424                }
12425                let (cursor, goal) = movement::down_by_rows(
12426                    map,
12427                    selection.start,
12428                    action.lines,
12429                    selection.goal,
12430                    false,
12431                    text_layout_details,
12432                );
12433                selection.collapse_to(cursor, goal);
12434            });
12435        })
12436    }
12437
12438    pub fn select_down_by_lines(
12439        &mut self,
12440        action: &SelectDownByLines,
12441        window: &mut Window,
12442        cx: &mut Context<Self>,
12443    ) {
12444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12445        let text_layout_details = &self.text_layout_details(window);
12446        self.change_selections(Default::default(), window, cx, |s| {
12447            s.move_heads_with(|map, head, goal| {
12448                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12449            })
12450        })
12451    }
12452
12453    pub fn select_up_by_lines(
12454        &mut self,
12455        action: &SelectUpByLines,
12456        window: &mut Window,
12457        cx: &mut Context<Self>,
12458    ) {
12459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12460        let text_layout_details = &self.text_layout_details(window);
12461        self.change_selections(Default::default(), window, cx, |s| {
12462            s.move_heads_with(|map, head, goal| {
12463                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12464            })
12465        })
12466    }
12467
12468    pub fn select_page_up(
12469        &mut self,
12470        _: &SelectPageUp,
12471        window: &mut Window,
12472        cx: &mut Context<Self>,
12473    ) {
12474        let Some(row_count) = self.visible_row_count() else {
12475            return;
12476        };
12477
12478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12479
12480        let text_layout_details = &self.text_layout_details(window);
12481
12482        self.change_selections(Default::default(), window, cx, |s| {
12483            s.move_heads_with(|map, head, goal| {
12484                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12485            })
12486        })
12487    }
12488
12489    pub fn move_page_up(
12490        &mut self,
12491        action: &MovePageUp,
12492        window: &mut Window,
12493        cx: &mut Context<Self>,
12494    ) {
12495        if self.take_rename(true, window, cx).is_some() {
12496            return;
12497        }
12498
12499        if self
12500            .context_menu
12501            .borrow_mut()
12502            .as_mut()
12503            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12504            .unwrap_or(false)
12505        {
12506            return;
12507        }
12508
12509        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12510            cx.propagate();
12511            return;
12512        }
12513
12514        let Some(row_count) = self.visible_row_count() else {
12515            return;
12516        };
12517
12518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12519
12520        let effects = if action.center_cursor {
12521            SelectionEffects::scroll(Autoscroll::center())
12522        } else {
12523            SelectionEffects::default()
12524        };
12525
12526        let text_layout_details = &self.text_layout_details(window);
12527
12528        self.change_selections(effects, window, cx, |s| {
12529            s.move_with(|map, selection| {
12530                if !selection.is_empty() {
12531                    selection.goal = SelectionGoal::None;
12532                }
12533                let (cursor, goal) = movement::up_by_rows(
12534                    map,
12535                    selection.end,
12536                    row_count,
12537                    selection.goal,
12538                    false,
12539                    text_layout_details,
12540                );
12541                selection.collapse_to(cursor, goal);
12542            });
12543        });
12544    }
12545
12546    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12548        let text_layout_details = &self.text_layout_details(window);
12549        self.change_selections(Default::default(), window, cx, |s| {
12550            s.move_heads_with(|map, head, goal| {
12551                movement::up(map, head, goal, false, text_layout_details)
12552            })
12553        })
12554    }
12555
12556    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12557        self.take_rename(true, window, cx);
12558
12559        if self.mode.is_single_line() {
12560            cx.propagate();
12561            return;
12562        }
12563
12564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12565
12566        let text_layout_details = &self.text_layout_details(window);
12567        let selection_count = self.selections.count();
12568        let first_selection = self.selections.first_anchor();
12569
12570        self.change_selections(Default::default(), window, cx, |s| {
12571            s.move_with(|map, selection| {
12572                if !selection.is_empty() {
12573                    selection.goal = SelectionGoal::None;
12574                }
12575                let (cursor, goal) = movement::down(
12576                    map,
12577                    selection.end,
12578                    selection.goal,
12579                    false,
12580                    text_layout_details,
12581                );
12582                selection.collapse_to(cursor, goal);
12583            });
12584        });
12585
12586        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12587        {
12588            cx.propagate();
12589        }
12590    }
12591
12592    pub fn select_page_down(
12593        &mut self,
12594        _: &SelectPageDown,
12595        window: &mut Window,
12596        cx: &mut Context<Self>,
12597    ) {
12598        let Some(row_count) = self.visible_row_count() else {
12599            return;
12600        };
12601
12602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12603
12604        let text_layout_details = &self.text_layout_details(window);
12605
12606        self.change_selections(Default::default(), window, cx, |s| {
12607            s.move_heads_with(|map, head, goal| {
12608                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12609            })
12610        })
12611    }
12612
12613    pub fn move_page_down(
12614        &mut self,
12615        action: &MovePageDown,
12616        window: &mut Window,
12617        cx: &mut Context<Self>,
12618    ) {
12619        if self.take_rename(true, window, cx).is_some() {
12620            return;
12621        }
12622
12623        if self
12624            .context_menu
12625            .borrow_mut()
12626            .as_mut()
12627            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12628            .unwrap_or(false)
12629        {
12630            return;
12631        }
12632
12633        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12634            cx.propagate();
12635            return;
12636        }
12637
12638        let Some(row_count) = self.visible_row_count() else {
12639            return;
12640        };
12641
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12643
12644        let effects = if action.center_cursor {
12645            SelectionEffects::scroll(Autoscroll::center())
12646        } else {
12647            SelectionEffects::default()
12648        };
12649
12650        let text_layout_details = &self.text_layout_details(window);
12651        self.change_selections(effects, window, cx, |s| {
12652            s.move_with(|map, selection| {
12653                if !selection.is_empty() {
12654                    selection.goal = SelectionGoal::None;
12655                }
12656                let (cursor, goal) = movement::down_by_rows(
12657                    map,
12658                    selection.end,
12659                    row_count,
12660                    selection.goal,
12661                    false,
12662                    text_layout_details,
12663                );
12664                selection.collapse_to(cursor, goal);
12665            });
12666        });
12667    }
12668
12669    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12671        let text_layout_details = &self.text_layout_details(window);
12672        self.change_selections(Default::default(), window, cx, |s| {
12673            s.move_heads_with(|map, head, goal| {
12674                movement::down(map, head, goal, false, text_layout_details)
12675            })
12676        });
12677    }
12678
12679    pub fn context_menu_first(
12680        &mut self,
12681        _: &ContextMenuFirst,
12682        window: &mut Window,
12683        cx: &mut Context<Self>,
12684    ) {
12685        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12686            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12687        }
12688    }
12689
12690    pub fn context_menu_prev(
12691        &mut self,
12692        _: &ContextMenuPrevious,
12693        window: &mut Window,
12694        cx: &mut Context<Self>,
12695    ) {
12696        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12697            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12698        }
12699    }
12700
12701    pub fn context_menu_next(
12702        &mut self,
12703        _: &ContextMenuNext,
12704        window: &mut Window,
12705        cx: &mut Context<Self>,
12706    ) {
12707        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12708            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12709        }
12710    }
12711
12712    pub fn context_menu_last(
12713        &mut self,
12714        _: &ContextMenuLast,
12715        window: &mut Window,
12716        cx: &mut Context<Self>,
12717    ) {
12718        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12719            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12720        }
12721    }
12722
12723    pub fn signature_help_prev(
12724        &mut self,
12725        _: &SignatureHelpPrevious,
12726        _: &mut Window,
12727        cx: &mut Context<Self>,
12728    ) {
12729        if let Some(popover) = self.signature_help_state.popover_mut() {
12730            if popover.current_signature == 0 {
12731                popover.current_signature = popover.signatures.len() - 1;
12732            } else {
12733                popover.current_signature -= 1;
12734            }
12735            cx.notify();
12736        }
12737    }
12738
12739    pub fn signature_help_next(
12740        &mut self,
12741        _: &SignatureHelpNext,
12742        _: &mut Window,
12743        cx: &mut Context<Self>,
12744    ) {
12745        if let Some(popover) = self.signature_help_state.popover_mut() {
12746            if popover.current_signature + 1 == popover.signatures.len() {
12747                popover.current_signature = 0;
12748            } else {
12749                popover.current_signature += 1;
12750            }
12751            cx.notify();
12752        }
12753    }
12754
12755    pub fn move_to_previous_word_start(
12756        &mut self,
12757        _: &MoveToPreviousWordStart,
12758        window: &mut Window,
12759        cx: &mut Context<Self>,
12760    ) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12762        self.change_selections(Default::default(), window, cx, |s| {
12763            s.move_cursors_with(|map, head, _| {
12764                (
12765                    movement::previous_word_start(map, head),
12766                    SelectionGoal::None,
12767                )
12768            });
12769        })
12770    }
12771
12772    pub fn move_to_previous_subword_start(
12773        &mut self,
12774        _: &MoveToPreviousSubwordStart,
12775        window: &mut Window,
12776        cx: &mut Context<Self>,
12777    ) {
12778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12779        self.change_selections(Default::default(), window, cx, |s| {
12780            s.move_cursors_with(|map, head, _| {
12781                (
12782                    movement::previous_subword_start(map, head),
12783                    SelectionGoal::None,
12784                )
12785            });
12786        })
12787    }
12788
12789    pub fn select_to_previous_word_start(
12790        &mut self,
12791        _: &SelectToPreviousWordStart,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) {
12795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12796        self.change_selections(Default::default(), window, cx, |s| {
12797            s.move_heads_with(|map, head, _| {
12798                (
12799                    movement::previous_word_start(map, head),
12800                    SelectionGoal::None,
12801                )
12802            });
12803        })
12804    }
12805
12806    pub fn select_to_previous_subword_start(
12807        &mut self,
12808        _: &SelectToPreviousSubwordStart,
12809        window: &mut Window,
12810        cx: &mut Context<Self>,
12811    ) {
12812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12813        self.change_selections(Default::default(), window, cx, |s| {
12814            s.move_heads_with(|map, head, _| {
12815                (
12816                    movement::previous_subword_start(map, head),
12817                    SelectionGoal::None,
12818                )
12819            });
12820        })
12821    }
12822
12823    pub fn delete_to_previous_word_start(
12824        &mut self,
12825        action: &DeleteToPreviousWordStart,
12826        window: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) {
12829        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12830        self.transact(window, cx, |this, window, cx| {
12831            this.select_autoclose_pair(window, cx);
12832            this.change_selections(Default::default(), window, cx, |s| {
12833                s.move_with(|map, selection| {
12834                    if selection.is_empty() {
12835                        let cursor = if action.ignore_newlines {
12836                            movement::previous_word_start(map, selection.head())
12837                        } else {
12838                            movement::previous_word_start_or_newline(map, selection.head())
12839                        };
12840                        selection.set_head(cursor, SelectionGoal::None);
12841                    }
12842                });
12843            });
12844            this.insert("", window, cx);
12845        });
12846    }
12847
12848    pub fn delete_to_previous_subword_start(
12849        &mut self,
12850        _: &DeleteToPreviousSubwordStart,
12851        window: &mut Window,
12852        cx: &mut Context<Self>,
12853    ) {
12854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12855        self.transact(window, cx, |this, window, cx| {
12856            this.select_autoclose_pair(window, cx);
12857            this.change_selections(Default::default(), window, cx, |s| {
12858                s.move_with(|map, selection| {
12859                    if selection.is_empty() {
12860                        let cursor = movement::previous_subword_start(map, selection.head());
12861                        selection.set_head(cursor, SelectionGoal::None);
12862                    }
12863                });
12864            });
12865            this.insert("", window, cx);
12866        });
12867    }
12868
12869    pub fn move_to_next_word_end(
12870        &mut self,
12871        _: &MoveToNextWordEnd,
12872        window: &mut Window,
12873        cx: &mut Context<Self>,
12874    ) {
12875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12876        self.change_selections(Default::default(), window, cx, |s| {
12877            s.move_cursors_with(|map, head, _| {
12878                (movement::next_word_end(map, head), SelectionGoal::None)
12879            });
12880        })
12881    }
12882
12883    pub fn move_to_next_subword_end(
12884        &mut self,
12885        _: &MoveToNextSubwordEnd,
12886        window: &mut Window,
12887        cx: &mut Context<Self>,
12888    ) {
12889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12890        self.change_selections(Default::default(), window, cx, |s| {
12891            s.move_cursors_with(|map, head, _| {
12892                (movement::next_subword_end(map, head), SelectionGoal::None)
12893            });
12894        })
12895    }
12896
12897    pub fn select_to_next_word_end(
12898        &mut self,
12899        _: &SelectToNextWordEnd,
12900        window: &mut Window,
12901        cx: &mut Context<Self>,
12902    ) {
12903        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12904        self.change_selections(Default::default(), window, cx, |s| {
12905            s.move_heads_with(|map, head, _| {
12906                (movement::next_word_end(map, head), SelectionGoal::None)
12907            });
12908        })
12909    }
12910
12911    pub fn select_to_next_subword_end(
12912        &mut self,
12913        _: &SelectToNextSubwordEnd,
12914        window: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) {
12917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12918        self.change_selections(Default::default(), window, cx, |s| {
12919            s.move_heads_with(|map, head, _| {
12920                (movement::next_subword_end(map, head), SelectionGoal::None)
12921            });
12922        })
12923    }
12924
12925    pub fn delete_to_next_word_end(
12926        &mut self,
12927        action: &DeleteToNextWordEnd,
12928        window: &mut Window,
12929        cx: &mut Context<Self>,
12930    ) {
12931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12932        self.transact(window, cx, |this, window, cx| {
12933            this.change_selections(Default::default(), window, cx, |s| {
12934                s.move_with(|map, selection| {
12935                    if selection.is_empty() {
12936                        let cursor = if action.ignore_newlines {
12937                            movement::next_word_end(map, selection.head())
12938                        } else {
12939                            movement::next_word_end_or_newline(map, selection.head())
12940                        };
12941                        selection.set_head(cursor, SelectionGoal::None);
12942                    }
12943                });
12944            });
12945            this.insert("", window, cx);
12946        });
12947    }
12948
12949    pub fn delete_to_next_subword_end(
12950        &mut self,
12951        _: &DeleteToNextSubwordEnd,
12952        window: &mut Window,
12953        cx: &mut Context<Self>,
12954    ) {
12955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12956        self.transact(window, cx, |this, window, cx| {
12957            this.change_selections(Default::default(), window, cx, |s| {
12958                s.move_with(|map, selection| {
12959                    if selection.is_empty() {
12960                        let cursor = movement::next_subword_end(map, selection.head());
12961                        selection.set_head(cursor, SelectionGoal::None);
12962                    }
12963                });
12964            });
12965            this.insert("", window, cx);
12966        });
12967    }
12968
12969    pub fn move_to_beginning_of_line(
12970        &mut self,
12971        action: &MoveToBeginningOfLine,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12976        self.change_selections(Default::default(), window, cx, |s| {
12977            s.move_cursors_with(|map, head, _| {
12978                (
12979                    movement::indented_line_beginning(
12980                        map,
12981                        head,
12982                        action.stop_at_soft_wraps,
12983                        action.stop_at_indent,
12984                    ),
12985                    SelectionGoal::None,
12986                )
12987            });
12988        })
12989    }
12990
12991    pub fn select_to_beginning_of_line(
12992        &mut self,
12993        action: &SelectToBeginningOfLine,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) {
12997        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12998        self.change_selections(Default::default(), window, cx, |s| {
12999            s.move_heads_with(|map, head, _| {
13000                (
13001                    movement::indented_line_beginning(
13002                        map,
13003                        head,
13004                        action.stop_at_soft_wraps,
13005                        action.stop_at_indent,
13006                    ),
13007                    SelectionGoal::None,
13008                )
13009            });
13010        });
13011    }
13012
13013    pub fn delete_to_beginning_of_line(
13014        &mut self,
13015        action: &DeleteToBeginningOfLine,
13016        window: &mut Window,
13017        cx: &mut Context<Self>,
13018    ) {
13019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13020        self.transact(window, cx, |this, window, cx| {
13021            this.change_selections(Default::default(), window, cx, |s| {
13022                s.move_with(|_, selection| {
13023                    selection.reversed = true;
13024                });
13025            });
13026
13027            this.select_to_beginning_of_line(
13028                &SelectToBeginningOfLine {
13029                    stop_at_soft_wraps: false,
13030                    stop_at_indent: action.stop_at_indent,
13031                },
13032                window,
13033                cx,
13034            );
13035            this.backspace(&Backspace, window, cx);
13036        });
13037    }
13038
13039    pub fn move_to_end_of_line(
13040        &mut self,
13041        action: &MoveToEndOfLine,
13042        window: &mut Window,
13043        cx: &mut Context<Self>,
13044    ) {
13045        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13046        self.change_selections(Default::default(), window, cx, |s| {
13047            s.move_cursors_with(|map, head, _| {
13048                (
13049                    movement::line_end(map, head, action.stop_at_soft_wraps),
13050                    SelectionGoal::None,
13051                )
13052            });
13053        })
13054    }
13055
13056    pub fn select_to_end_of_line(
13057        &mut self,
13058        action: &SelectToEndOfLine,
13059        window: &mut Window,
13060        cx: &mut Context<Self>,
13061    ) {
13062        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13063        self.change_selections(Default::default(), window, cx, |s| {
13064            s.move_heads_with(|map, head, _| {
13065                (
13066                    movement::line_end(map, head, action.stop_at_soft_wraps),
13067                    SelectionGoal::None,
13068                )
13069            });
13070        })
13071    }
13072
13073    pub fn delete_to_end_of_line(
13074        &mut self,
13075        _: &DeleteToEndOfLine,
13076        window: &mut Window,
13077        cx: &mut Context<Self>,
13078    ) {
13079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13080        self.transact(window, cx, |this, window, cx| {
13081            this.select_to_end_of_line(
13082                &SelectToEndOfLine {
13083                    stop_at_soft_wraps: false,
13084                },
13085                window,
13086                cx,
13087            );
13088            this.delete(&Delete, window, cx);
13089        });
13090    }
13091
13092    pub fn cut_to_end_of_line(
13093        &mut self,
13094        _: &CutToEndOfLine,
13095        window: &mut Window,
13096        cx: &mut Context<Self>,
13097    ) {
13098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13099        self.transact(window, cx, |this, window, cx| {
13100            this.select_to_end_of_line(
13101                &SelectToEndOfLine {
13102                    stop_at_soft_wraps: false,
13103                },
13104                window,
13105                cx,
13106            );
13107            this.cut(&Cut, window, cx);
13108        });
13109    }
13110
13111    pub fn move_to_start_of_paragraph(
13112        &mut self,
13113        _: &MoveToStartOfParagraph,
13114        window: &mut Window,
13115        cx: &mut Context<Self>,
13116    ) {
13117        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13118            cx.propagate();
13119            return;
13120        }
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_with(|map, selection| {
13124                selection.collapse_to(
13125                    movement::start_of_paragraph(map, selection.head(), 1),
13126                    SelectionGoal::None,
13127                )
13128            });
13129        })
13130    }
13131
13132    pub fn move_to_end_of_paragraph(
13133        &mut self,
13134        _: &MoveToEndOfParagraph,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13139            cx.propagate();
13140            return;
13141        }
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13143        self.change_selections(Default::default(), window, cx, |s| {
13144            s.move_with(|map, selection| {
13145                selection.collapse_to(
13146                    movement::end_of_paragraph(map, selection.head(), 1),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        })
13151    }
13152
13153    pub fn select_to_start_of_paragraph(
13154        &mut self,
13155        _: &SelectToStartOfParagraph,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13160            cx.propagate();
13161            return;
13162        }
13163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13164        self.change_selections(Default::default(), window, cx, |s| {
13165            s.move_heads_with(|map, head, _| {
13166                (
13167                    movement::start_of_paragraph(map, head, 1),
13168                    SelectionGoal::None,
13169                )
13170            });
13171        })
13172    }
13173
13174    pub fn select_to_end_of_paragraph(
13175        &mut self,
13176        _: &SelectToEndOfParagraph,
13177        window: &mut Window,
13178        cx: &mut Context<Self>,
13179    ) {
13180        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13181            cx.propagate();
13182            return;
13183        }
13184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13185        self.change_selections(Default::default(), window, cx, |s| {
13186            s.move_heads_with(|map, head, _| {
13187                (
13188                    movement::end_of_paragraph(map, head, 1),
13189                    SelectionGoal::None,
13190                )
13191            });
13192        })
13193    }
13194
13195    pub fn move_to_start_of_excerpt(
13196        &mut self,
13197        _: &MoveToStartOfExcerpt,
13198        window: &mut Window,
13199        cx: &mut Context<Self>,
13200    ) {
13201        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13202            cx.propagate();
13203            return;
13204        }
13205        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13206        self.change_selections(Default::default(), window, cx, |s| {
13207            s.move_with(|map, selection| {
13208                selection.collapse_to(
13209                    movement::start_of_excerpt(
13210                        map,
13211                        selection.head(),
13212                        workspace::searchable::Direction::Prev,
13213                    ),
13214                    SelectionGoal::None,
13215                )
13216            });
13217        })
13218    }
13219
13220    pub fn move_to_start_of_next_excerpt(
13221        &mut self,
13222        _: &MoveToStartOfNextExcerpt,
13223        window: &mut Window,
13224        cx: &mut Context<Self>,
13225    ) {
13226        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13227            cx.propagate();
13228            return;
13229        }
13230
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_with(|map, selection| {
13233                selection.collapse_to(
13234                    movement::start_of_excerpt(
13235                        map,
13236                        selection.head(),
13237                        workspace::searchable::Direction::Next,
13238                    ),
13239                    SelectionGoal::None,
13240                )
13241            });
13242        })
13243    }
13244
13245    pub fn move_to_end_of_excerpt(
13246        &mut self,
13247        _: &MoveToEndOfExcerpt,
13248        window: &mut Window,
13249        cx: &mut Context<Self>,
13250    ) {
13251        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13252            cx.propagate();
13253            return;
13254        }
13255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13256        self.change_selections(Default::default(), window, cx, |s| {
13257            s.move_with(|map, selection| {
13258                selection.collapse_to(
13259                    movement::end_of_excerpt(
13260                        map,
13261                        selection.head(),
13262                        workspace::searchable::Direction::Next,
13263                    ),
13264                    SelectionGoal::None,
13265                )
13266            });
13267        })
13268    }
13269
13270    pub fn move_to_end_of_previous_excerpt(
13271        &mut self,
13272        _: &MoveToEndOfPreviousExcerpt,
13273        window: &mut Window,
13274        cx: &mut Context<Self>,
13275    ) {
13276        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13277            cx.propagate();
13278            return;
13279        }
13280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13281        self.change_selections(Default::default(), window, cx, |s| {
13282            s.move_with(|map, selection| {
13283                selection.collapse_to(
13284                    movement::end_of_excerpt(
13285                        map,
13286                        selection.head(),
13287                        workspace::searchable::Direction::Prev,
13288                    ),
13289                    SelectionGoal::None,
13290                )
13291            });
13292        })
13293    }
13294
13295    pub fn select_to_start_of_excerpt(
13296        &mut self,
13297        _: &SelectToStartOfExcerpt,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13302            cx.propagate();
13303            return;
13304        }
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13306        self.change_selections(Default::default(), window, cx, |s| {
13307            s.move_heads_with(|map, head, _| {
13308                (
13309                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13310                    SelectionGoal::None,
13311                )
13312            });
13313        })
13314    }
13315
13316    pub fn select_to_start_of_next_excerpt(
13317        &mut self,
13318        _: &SelectToStartOfNextExcerpt,
13319        window: &mut Window,
13320        cx: &mut Context<Self>,
13321    ) {
13322        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13323            cx.propagate();
13324            return;
13325        }
13326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13327        self.change_selections(Default::default(), window, cx, |s| {
13328            s.move_heads_with(|map, head, _| {
13329                (
13330                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13331                    SelectionGoal::None,
13332                )
13333            });
13334        })
13335    }
13336
13337    pub fn select_to_end_of_excerpt(
13338        &mut self,
13339        _: &SelectToEndOfExcerpt,
13340        window: &mut Window,
13341        cx: &mut Context<Self>,
13342    ) {
13343        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13344            cx.propagate();
13345            return;
13346        }
13347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13348        self.change_selections(Default::default(), window, cx, |s| {
13349            s.move_heads_with(|map, head, _| {
13350                (
13351                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13352                    SelectionGoal::None,
13353                )
13354            });
13355        })
13356    }
13357
13358    pub fn select_to_end_of_previous_excerpt(
13359        &mut self,
13360        _: &SelectToEndOfPreviousExcerpt,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13365            cx.propagate();
13366            return;
13367        }
13368        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13369        self.change_selections(Default::default(), window, cx, |s| {
13370            s.move_heads_with(|map, head, _| {
13371                (
13372                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13373                    SelectionGoal::None,
13374                )
13375            });
13376        })
13377    }
13378
13379    pub fn move_to_beginning(
13380        &mut self,
13381        _: &MoveToBeginning,
13382        window: &mut Window,
13383        cx: &mut Context<Self>,
13384    ) {
13385        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13386            cx.propagate();
13387            return;
13388        }
13389        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13390        self.change_selections(Default::default(), window, cx, |s| {
13391            s.select_ranges(vec![0..0]);
13392        });
13393    }
13394
13395    pub fn select_to_beginning(
13396        &mut self,
13397        _: &SelectToBeginning,
13398        window: &mut Window,
13399        cx: &mut Context<Self>,
13400    ) {
13401        let mut selection = self.selections.last::<Point>(cx);
13402        selection.set_head(Point::zero(), SelectionGoal::None);
13403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13404        self.change_selections(Default::default(), window, cx, |s| {
13405            s.select(vec![selection]);
13406        });
13407    }
13408
13409    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13410        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13411            cx.propagate();
13412            return;
13413        }
13414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13415        let cursor = self.buffer.read(cx).read(cx).len();
13416        self.change_selections(Default::default(), window, cx, |s| {
13417            s.select_ranges(vec![cursor..cursor])
13418        });
13419    }
13420
13421    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13422        self.nav_history = nav_history;
13423    }
13424
13425    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13426        self.nav_history.as_ref()
13427    }
13428
13429    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13430        self.push_to_nav_history(
13431            self.selections.newest_anchor().head(),
13432            None,
13433            false,
13434            true,
13435            cx,
13436        );
13437    }
13438
13439    fn push_to_nav_history(
13440        &mut self,
13441        cursor_anchor: Anchor,
13442        new_position: Option<Point>,
13443        is_deactivate: bool,
13444        always: bool,
13445        cx: &mut Context<Self>,
13446    ) {
13447        if let Some(nav_history) = self.nav_history.as_mut() {
13448            let buffer = self.buffer.read(cx).read(cx);
13449            let cursor_position = cursor_anchor.to_point(&buffer);
13450            let scroll_state = self.scroll_manager.anchor();
13451            let scroll_top_row = scroll_state.top_row(&buffer);
13452            drop(buffer);
13453
13454            if let Some(new_position) = new_position {
13455                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13456                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13457                    return;
13458                }
13459            }
13460
13461            nav_history.push(
13462                Some(NavigationData {
13463                    cursor_anchor,
13464                    cursor_position,
13465                    scroll_anchor: scroll_state,
13466                    scroll_top_row,
13467                }),
13468                cx,
13469            );
13470            cx.emit(EditorEvent::PushedToNavHistory {
13471                anchor: cursor_anchor,
13472                is_deactivate,
13473            })
13474        }
13475    }
13476
13477    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13479        let buffer = self.buffer.read(cx).snapshot(cx);
13480        let mut selection = self.selections.first::<usize>(cx);
13481        selection.set_head(buffer.len(), SelectionGoal::None);
13482        self.change_selections(Default::default(), window, cx, |s| {
13483            s.select(vec![selection]);
13484        });
13485    }
13486
13487    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13488        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13489        let end = self.buffer.read(cx).read(cx).len();
13490        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13491            s.select_ranges(vec![0..end]);
13492        });
13493    }
13494
13495    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13496        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13498        let mut selections = self.selections.all::<Point>(cx);
13499        let max_point = display_map.buffer_snapshot.max_point();
13500        for selection in &mut selections {
13501            let rows = selection.spanned_rows(true, &display_map);
13502            selection.start = Point::new(rows.start.0, 0);
13503            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13504            selection.reversed = false;
13505        }
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.select(selections);
13508        });
13509    }
13510
13511    pub fn split_selection_into_lines(
13512        &mut self,
13513        _: &SplitSelectionIntoLines,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        let selections = self
13518            .selections
13519            .all::<Point>(cx)
13520            .into_iter()
13521            .map(|selection| selection.start..selection.end)
13522            .collect::<Vec<_>>();
13523        self.unfold_ranges(&selections, true, true, cx);
13524
13525        let mut new_selection_ranges = Vec::new();
13526        {
13527            let buffer = self.buffer.read(cx).read(cx);
13528            for selection in selections {
13529                for row in selection.start.row..selection.end.row {
13530                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13531                    new_selection_ranges.push(cursor..cursor);
13532                }
13533
13534                let is_multiline_selection = selection.start.row != selection.end.row;
13535                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13536                // so this action feels more ergonomic when paired with other selection operations
13537                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13538                if !should_skip_last {
13539                    new_selection_ranges.push(selection.end..selection.end);
13540                }
13541            }
13542        }
13543        self.change_selections(Default::default(), window, cx, |s| {
13544            s.select_ranges(new_selection_ranges);
13545        });
13546    }
13547
13548    pub fn add_selection_above(
13549        &mut self,
13550        _: &AddSelectionAbove,
13551        window: &mut Window,
13552        cx: &mut Context<Self>,
13553    ) {
13554        self.add_selection(true, window, cx);
13555    }
13556
13557    pub fn add_selection_below(
13558        &mut self,
13559        _: &AddSelectionBelow,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        self.add_selection(false, window, cx);
13564    }
13565
13566    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13568
13569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13570        let all_selections = self.selections.all::<Point>(cx);
13571        let text_layout_details = self.text_layout_details(window);
13572
13573        let (mut columnar_selections, new_selections_to_columnarize) = {
13574            if let Some(state) = self.add_selections_state.as_ref() {
13575                let columnar_selection_ids: HashSet<_> = state
13576                    .groups
13577                    .iter()
13578                    .flat_map(|group| group.stack.iter())
13579                    .copied()
13580                    .collect();
13581
13582                all_selections
13583                    .into_iter()
13584                    .partition(|s| columnar_selection_ids.contains(&s.id))
13585            } else {
13586                (Vec::new(), all_selections)
13587            }
13588        };
13589
13590        let mut state = self
13591            .add_selections_state
13592            .take()
13593            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13594
13595        for selection in new_selections_to_columnarize {
13596            let range = selection.display_range(&display_map).sorted();
13597            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13598            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13599            let positions = start_x.min(end_x)..start_x.max(end_x);
13600            let mut stack = Vec::new();
13601            for row in range.start.row().0..=range.end.row().0 {
13602                if let Some(selection) = self.selections.build_columnar_selection(
13603                    &display_map,
13604                    DisplayRow(row),
13605                    &positions,
13606                    selection.reversed,
13607                    &text_layout_details,
13608                ) {
13609                    stack.push(selection.id);
13610                    columnar_selections.push(selection);
13611                }
13612            }
13613            if !stack.is_empty() {
13614                if above {
13615                    stack.reverse();
13616                }
13617                state.groups.push(AddSelectionsGroup { above, stack });
13618            }
13619        }
13620
13621        let mut final_selections = Vec::new();
13622        let end_row = if above {
13623            DisplayRow(0)
13624        } else {
13625            display_map.max_point().row()
13626        };
13627
13628        let mut last_added_item_per_group = HashMap::default();
13629        for group in state.groups.iter_mut() {
13630            if let Some(last_id) = group.stack.last() {
13631                last_added_item_per_group.insert(*last_id, group);
13632            }
13633        }
13634
13635        for selection in columnar_selections {
13636            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13637                if above == group.above {
13638                    let range = selection.display_range(&display_map).sorted();
13639                    debug_assert_eq!(range.start.row(), range.end.row());
13640                    let mut row = range.start.row();
13641                    let positions =
13642                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13643                            px(start)..px(end)
13644                        } else {
13645                            let start_x =
13646                                display_map.x_for_display_point(range.start, &text_layout_details);
13647                            let end_x =
13648                                display_map.x_for_display_point(range.end, &text_layout_details);
13649                            start_x.min(end_x)..start_x.max(end_x)
13650                        };
13651
13652                    let mut maybe_new_selection = None;
13653                    while row != end_row {
13654                        if above {
13655                            row.0 -= 1;
13656                        } else {
13657                            row.0 += 1;
13658                        }
13659                        if let Some(new_selection) = self.selections.build_columnar_selection(
13660                            &display_map,
13661                            row,
13662                            &positions,
13663                            selection.reversed,
13664                            &text_layout_details,
13665                        ) {
13666                            maybe_new_selection = Some(new_selection);
13667                            break;
13668                        }
13669                    }
13670
13671                    if let Some(new_selection) = maybe_new_selection {
13672                        group.stack.push(new_selection.id);
13673                        if above {
13674                            final_selections.push(new_selection);
13675                            final_selections.push(selection);
13676                        } else {
13677                            final_selections.push(selection);
13678                            final_selections.push(new_selection);
13679                        }
13680                    } else {
13681                        final_selections.push(selection);
13682                    }
13683                } else {
13684                    group.stack.pop();
13685                }
13686            } else {
13687                final_selections.push(selection);
13688            }
13689        }
13690
13691        self.change_selections(Default::default(), window, cx, |s| {
13692            s.select(final_selections);
13693        });
13694
13695        let final_selection_ids: HashSet<_> = self
13696            .selections
13697            .all::<Point>(cx)
13698            .iter()
13699            .map(|s| s.id)
13700            .collect();
13701        state.groups.retain_mut(|group| {
13702            // selections might get merged above so we remove invalid items from stacks
13703            group.stack.retain(|id| final_selection_ids.contains(id));
13704
13705            // single selection in stack can be treated as initial state
13706            group.stack.len() > 1
13707        });
13708
13709        if !state.groups.is_empty() {
13710            self.add_selections_state = Some(state);
13711        }
13712    }
13713
13714    fn select_match_ranges(
13715        &mut self,
13716        range: Range<usize>,
13717        reversed: bool,
13718        replace_newest: bool,
13719        auto_scroll: Option<Autoscroll>,
13720        window: &mut Window,
13721        cx: &mut Context<Editor>,
13722    ) {
13723        self.unfold_ranges(
13724            std::slice::from_ref(&range),
13725            false,
13726            auto_scroll.is_some(),
13727            cx,
13728        );
13729        let effects = if let Some(scroll) = auto_scroll {
13730            SelectionEffects::scroll(scroll)
13731        } else {
13732            SelectionEffects::no_scroll()
13733        };
13734        self.change_selections(effects, window, cx, |s| {
13735            if replace_newest {
13736                s.delete(s.newest_anchor().id);
13737            }
13738            if reversed {
13739                s.insert_range(range.end..range.start);
13740            } else {
13741                s.insert_range(range);
13742            }
13743        });
13744    }
13745
13746    pub fn select_next_match_internal(
13747        &mut self,
13748        display_map: &DisplaySnapshot,
13749        replace_newest: bool,
13750        autoscroll: Option<Autoscroll>,
13751        window: &mut Window,
13752        cx: &mut Context<Self>,
13753    ) -> Result<()> {
13754        let buffer = &display_map.buffer_snapshot;
13755        let mut selections = self.selections.all::<usize>(cx);
13756        if let Some(mut select_next_state) = self.select_next_state.take() {
13757            let query = &select_next_state.query;
13758            if !select_next_state.done {
13759                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13760                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13761                let mut next_selected_range = None;
13762
13763                let bytes_after_last_selection =
13764                    buffer.bytes_in_range(last_selection.end..buffer.len());
13765                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13766                let query_matches = query
13767                    .stream_find_iter(bytes_after_last_selection)
13768                    .map(|result| (last_selection.end, result))
13769                    .chain(
13770                        query
13771                            .stream_find_iter(bytes_before_first_selection)
13772                            .map(|result| (0, result)),
13773                    );
13774
13775                for (start_offset, query_match) in query_matches {
13776                    let query_match = query_match.unwrap(); // can only fail due to I/O
13777                    let offset_range =
13778                        start_offset + query_match.start()..start_offset + query_match.end();
13779
13780                    if !select_next_state.wordwise
13781                        || (!buffer.is_inside_word(offset_range.start, false)
13782                            && !buffer.is_inside_word(offset_range.end, false))
13783                    {
13784                        // TODO: This is n^2, because we might check all the selections
13785                        if !selections
13786                            .iter()
13787                            .any(|selection| selection.range().overlaps(&offset_range))
13788                        {
13789                            next_selected_range = Some(offset_range);
13790                            break;
13791                        }
13792                    }
13793                }
13794
13795                if let Some(next_selected_range) = next_selected_range {
13796                    self.select_match_ranges(
13797                        next_selected_range,
13798                        last_selection.reversed,
13799                        replace_newest,
13800                        autoscroll,
13801                        window,
13802                        cx,
13803                    );
13804                } else {
13805                    select_next_state.done = true;
13806                }
13807            }
13808
13809            self.select_next_state = Some(select_next_state);
13810        } else {
13811            let mut only_carets = true;
13812            let mut same_text_selected = true;
13813            let mut selected_text = None;
13814
13815            let mut selections_iter = selections.iter().peekable();
13816            while let Some(selection) = selections_iter.next() {
13817                if selection.start != selection.end {
13818                    only_carets = false;
13819                }
13820
13821                if same_text_selected {
13822                    if selected_text.is_none() {
13823                        selected_text =
13824                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13825                    }
13826
13827                    if let Some(next_selection) = selections_iter.peek() {
13828                        if next_selection.range().len() == selection.range().len() {
13829                            let next_selected_text = buffer
13830                                .text_for_range(next_selection.range())
13831                                .collect::<String>();
13832                            if Some(next_selected_text) != selected_text {
13833                                same_text_selected = false;
13834                                selected_text = None;
13835                            }
13836                        } else {
13837                            same_text_selected = false;
13838                            selected_text = None;
13839                        }
13840                    }
13841                }
13842            }
13843
13844            if only_carets {
13845                for selection in &mut selections {
13846                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13847                    selection.start = word_range.start;
13848                    selection.end = word_range.end;
13849                    selection.goal = SelectionGoal::None;
13850                    selection.reversed = false;
13851                    self.select_match_ranges(
13852                        selection.start..selection.end,
13853                        selection.reversed,
13854                        replace_newest,
13855                        autoscroll,
13856                        window,
13857                        cx,
13858                    );
13859                }
13860
13861                if selections.len() == 1 {
13862                    let selection = selections
13863                        .last()
13864                        .expect("ensured that there's only one selection");
13865                    let query = buffer
13866                        .text_for_range(selection.start..selection.end)
13867                        .collect::<String>();
13868                    let is_empty = query.is_empty();
13869                    let select_state = SelectNextState {
13870                        query: AhoCorasick::new(&[query])?,
13871                        wordwise: true,
13872                        done: is_empty,
13873                    };
13874                    self.select_next_state = Some(select_state);
13875                } else {
13876                    self.select_next_state = None;
13877                }
13878            } else if let Some(selected_text) = selected_text {
13879                self.select_next_state = Some(SelectNextState {
13880                    query: AhoCorasick::new(&[selected_text])?,
13881                    wordwise: false,
13882                    done: false,
13883                });
13884                self.select_next_match_internal(
13885                    display_map,
13886                    replace_newest,
13887                    autoscroll,
13888                    window,
13889                    cx,
13890                )?;
13891            }
13892        }
13893        Ok(())
13894    }
13895
13896    pub fn select_all_matches(
13897        &mut self,
13898        _action: &SelectAllMatches,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) -> Result<()> {
13902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13903
13904        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13905
13906        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13907        let Some(select_next_state) = self.select_next_state.as_mut() else {
13908            return Ok(());
13909        };
13910        if select_next_state.done {
13911            return Ok(());
13912        }
13913
13914        let mut new_selections = Vec::new();
13915
13916        let reversed = self.selections.oldest::<usize>(cx).reversed;
13917        let buffer = &display_map.buffer_snapshot;
13918        let query_matches = select_next_state
13919            .query
13920            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13921
13922        for query_match in query_matches.into_iter() {
13923            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13924            let offset_range = if reversed {
13925                query_match.end()..query_match.start()
13926            } else {
13927                query_match.start()..query_match.end()
13928            };
13929
13930            if !select_next_state.wordwise
13931                || (!buffer.is_inside_word(offset_range.start, false)
13932                    && !buffer.is_inside_word(offset_range.end, false))
13933            {
13934                new_selections.push(offset_range.start..offset_range.end);
13935            }
13936        }
13937
13938        select_next_state.done = true;
13939
13940        if new_selections.is_empty() {
13941            log::error!("bug: new_selections is empty in select_all_matches");
13942            return Ok(());
13943        }
13944
13945        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13946        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13947            selections.select_ranges(new_selections)
13948        });
13949
13950        Ok(())
13951    }
13952
13953    pub fn select_next(
13954        &mut self,
13955        action: &SelectNext,
13956        window: &mut Window,
13957        cx: &mut Context<Self>,
13958    ) -> Result<()> {
13959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13960        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13961        self.select_next_match_internal(
13962            &display_map,
13963            action.replace_newest,
13964            Some(Autoscroll::newest()),
13965            window,
13966            cx,
13967        )?;
13968        Ok(())
13969    }
13970
13971    pub fn select_previous(
13972        &mut self,
13973        action: &SelectPrevious,
13974        window: &mut Window,
13975        cx: &mut Context<Self>,
13976    ) -> Result<()> {
13977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13978        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13979        let buffer = &display_map.buffer_snapshot;
13980        let mut selections = self.selections.all::<usize>(cx);
13981        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13982            let query = &select_prev_state.query;
13983            if !select_prev_state.done {
13984                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13985                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13986                let mut next_selected_range = None;
13987                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13988                let bytes_before_last_selection =
13989                    buffer.reversed_bytes_in_range(0..last_selection.start);
13990                let bytes_after_first_selection =
13991                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13992                let query_matches = query
13993                    .stream_find_iter(bytes_before_last_selection)
13994                    .map(|result| (last_selection.start, result))
13995                    .chain(
13996                        query
13997                            .stream_find_iter(bytes_after_first_selection)
13998                            .map(|result| (buffer.len(), result)),
13999                    );
14000                for (end_offset, query_match) in query_matches {
14001                    let query_match = query_match.unwrap(); // can only fail due to I/O
14002                    let offset_range =
14003                        end_offset - query_match.end()..end_offset - query_match.start();
14004
14005                    if !select_prev_state.wordwise
14006                        || (!buffer.is_inside_word(offset_range.start, false)
14007                            && !buffer.is_inside_word(offset_range.end, false))
14008                    {
14009                        next_selected_range = Some(offset_range);
14010                        break;
14011                    }
14012                }
14013
14014                if let Some(next_selected_range) = next_selected_range {
14015                    self.select_match_ranges(
14016                        next_selected_range,
14017                        last_selection.reversed,
14018                        action.replace_newest,
14019                        Some(Autoscroll::newest()),
14020                        window,
14021                        cx,
14022                    );
14023                } else {
14024                    select_prev_state.done = true;
14025                }
14026            }
14027
14028            self.select_prev_state = Some(select_prev_state);
14029        } else {
14030            let mut only_carets = true;
14031            let mut same_text_selected = true;
14032            let mut selected_text = None;
14033
14034            let mut selections_iter = selections.iter().peekable();
14035            while let Some(selection) = selections_iter.next() {
14036                if selection.start != selection.end {
14037                    only_carets = false;
14038                }
14039
14040                if same_text_selected {
14041                    if selected_text.is_none() {
14042                        selected_text =
14043                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14044                    }
14045
14046                    if let Some(next_selection) = selections_iter.peek() {
14047                        if next_selection.range().len() == selection.range().len() {
14048                            let next_selected_text = buffer
14049                                .text_for_range(next_selection.range())
14050                                .collect::<String>();
14051                            if Some(next_selected_text) != selected_text {
14052                                same_text_selected = false;
14053                                selected_text = None;
14054                            }
14055                        } else {
14056                            same_text_selected = false;
14057                            selected_text = None;
14058                        }
14059                    }
14060                }
14061            }
14062
14063            if only_carets {
14064                for selection in &mut selections {
14065                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14066                    selection.start = word_range.start;
14067                    selection.end = word_range.end;
14068                    selection.goal = SelectionGoal::None;
14069                    selection.reversed = false;
14070                    self.select_match_ranges(
14071                        selection.start..selection.end,
14072                        selection.reversed,
14073                        action.replace_newest,
14074                        Some(Autoscroll::newest()),
14075                        window,
14076                        cx,
14077                    );
14078                }
14079                if selections.len() == 1 {
14080                    let selection = selections
14081                        .last()
14082                        .expect("ensured that there's only one selection");
14083                    let query = buffer
14084                        .text_for_range(selection.start..selection.end)
14085                        .collect::<String>();
14086                    let is_empty = query.is_empty();
14087                    let select_state = SelectNextState {
14088                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14089                        wordwise: true,
14090                        done: is_empty,
14091                    };
14092                    self.select_prev_state = Some(select_state);
14093                } else {
14094                    self.select_prev_state = None;
14095                }
14096            } else if let Some(selected_text) = selected_text {
14097                self.select_prev_state = Some(SelectNextState {
14098                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14099                    wordwise: false,
14100                    done: false,
14101                });
14102                self.select_previous(action, window, cx)?;
14103            }
14104        }
14105        Ok(())
14106    }
14107
14108    pub fn find_next_match(
14109        &mut self,
14110        _: &FindNextMatch,
14111        window: &mut Window,
14112        cx: &mut Context<Self>,
14113    ) -> Result<()> {
14114        let selections = self.selections.disjoint_anchors();
14115        match selections.first() {
14116            Some(first) if selections.len() >= 2 => {
14117                self.change_selections(Default::default(), window, cx, |s| {
14118                    s.select_ranges([first.range()]);
14119                });
14120            }
14121            _ => self.select_next(
14122                &SelectNext {
14123                    replace_newest: true,
14124                },
14125                window,
14126                cx,
14127            )?,
14128        }
14129        Ok(())
14130    }
14131
14132    pub fn find_previous_match(
14133        &mut self,
14134        _: &FindPreviousMatch,
14135        window: &mut Window,
14136        cx: &mut Context<Self>,
14137    ) -> Result<()> {
14138        let selections = self.selections.disjoint_anchors();
14139        match selections.last() {
14140            Some(last) if selections.len() >= 2 => {
14141                self.change_selections(Default::default(), window, cx, |s| {
14142                    s.select_ranges([last.range()]);
14143                });
14144            }
14145            _ => self.select_previous(
14146                &SelectPrevious {
14147                    replace_newest: true,
14148                },
14149                window,
14150                cx,
14151            )?,
14152        }
14153        Ok(())
14154    }
14155
14156    pub fn toggle_comments(
14157        &mut self,
14158        action: &ToggleComments,
14159        window: &mut Window,
14160        cx: &mut Context<Self>,
14161    ) {
14162        if self.read_only(cx) {
14163            return;
14164        }
14165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14166        let text_layout_details = &self.text_layout_details(window);
14167        self.transact(window, cx, |this, window, cx| {
14168            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14169            let mut edits = Vec::new();
14170            let mut selection_edit_ranges = Vec::new();
14171            let mut last_toggled_row = None;
14172            let snapshot = this.buffer.read(cx).read(cx);
14173            let empty_str: Arc<str> = Arc::default();
14174            let mut suffixes_inserted = Vec::new();
14175            let ignore_indent = action.ignore_indent;
14176
14177            fn comment_prefix_range(
14178                snapshot: &MultiBufferSnapshot,
14179                row: MultiBufferRow,
14180                comment_prefix: &str,
14181                comment_prefix_whitespace: &str,
14182                ignore_indent: bool,
14183            ) -> Range<Point> {
14184                let indent_size = if ignore_indent {
14185                    0
14186                } else {
14187                    snapshot.indent_size_for_line(row).len
14188                };
14189
14190                let start = Point::new(row.0, indent_size);
14191
14192                let mut line_bytes = snapshot
14193                    .bytes_in_range(start..snapshot.max_point())
14194                    .flatten()
14195                    .copied();
14196
14197                // If this line currently begins with the line comment prefix, then record
14198                // the range containing the prefix.
14199                if line_bytes
14200                    .by_ref()
14201                    .take(comment_prefix.len())
14202                    .eq(comment_prefix.bytes())
14203                {
14204                    // Include any whitespace that matches the comment prefix.
14205                    let matching_whitespace_len = line_bytes
14206                        .zip(comment_prefix_whitespace.bytes())
14207                        .take_while(|(a, b)| a == b)
14208                        .count() as u32;
14209                    let end = Point::new(
14210                        start.row,
14211                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14212                    );
14213                    start..end
14214                } else {
14215                    start..start
14216                }
14217            }
14218
14219            fn comment_suffix_range(
14220                snapshot: &MultiBufferSnapshot,
14221                row: MultiBufferRow,
14222                comment_suffix: &str,
14223                comment_suffix_has_leading_space: bool,
14224            ) -> Range<Point> {
14225                let end = Point::new(row.0, snapshot.line_len(row));
14226                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14227
14228                let mut line_end_bytes = snapshot
14229                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14230                    .flatten()
14231                    .copied();
14232
14233                let leading_space_len = if suffix_start_column > 0
14234                    && line_end_bytes.next() == Some(b' ')
14235                    && comment_suffix_has_leading_space
14236                {
14237                    1
14238                } else {
14239                    0
14240                };
14241
14242                // If this line currently begins with the line comment prefix, then record
14243                // the range containing the prefix.
14244                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14245                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14246                    start..end
14247                } else {
14248                    end..end
14249                }
14250            }
14251
14252            // TODO: Handle selections that cross excerpts
14253            for selection in &mut selections {
14254                let start_column = snapshot
14255                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14256                    .len;
14257                let language = if let Some(language) =
14258                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14259                {
14260                    language
14261                } else {
14262                    continue;
14263                };
14264
14265                selection_edit_ranges.clear();
14266
14267                // If multiple selections contain a given row, avoid processing that
14268                // row more than once.
14269                let mut start_row = MultiBufferRow(selection.start.row);
14270                if last_toggled_row == Some(start_row) {
14271                    start_row = start_row.next_row();
14272                }
14273                let end_row =
14274                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14275                        MultiBufferRow(selection.end.row - 1)
14276                    } else {
14277                        MultiBufferRow(selection.end.row)
14278                    };
14279                last_toggled_row = Some(end_row);
14280
14281                if start_row > end_row {
14282                    continue;
14283                }
14284
14285                // If the language has line comments, toggle those.
14286                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14287
14288                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14289                if ignore_indent {
14290                    full_comment_prefixes = full_comment_prefixes
14291                        .into_iter()
14292                        .map(|s| Arc::from(s.trim_end()))
14293                        .collect();
14294                }
14295
14296                if !full_comment_prefixes.is_empty() {
14297                    let first_prefix = full_comment_prefixes
14298                        .first()
14299                        .expect("prefixes is non-empty");
14300                    let prefix_trimmed_lengths = full_comment_prefixes
14301                        .iter()
14302                        .map(|p| p.trim_end_matches(' ').len())
14303                        .collect::<SmallVec<[usize; 4]>>();
14304
14305                    let mut all_selection_lines_are_comments = true;
14306
14307                    for row in start_row.0..=end_row.0 {
14308                        let row = MultiBufferRow(row);
14309                        if start_row < end_row && snapshot.is_line_blank(row) {
14310                            continue;
14311                        }
14312
14313                        let prefix_range = full_comment_prefixes
14314                            .iter()
14315                            .zip(prefix_trimmed_lengths.iter().copied())
14316                            .map(|(prefix, trimmed_prefix_len)| {
14317                                comment_prefix_range(
14318                                    snapshot.deref(),
14319                                    row,
14320                                    &prefix[..trimmed_prefix_len],
14321                                    &prefix[trimmed_prefix_len..],
14322                                    ignore_indent,
14323                                )
14324                            })
14325                            .max_by_key(|range| range.end.column - range.start.column)
14326                            .expect("prefixes is non-empty");
14327
14328                        if prefix_range.is_empty() {
14329                            all_selection_lines_are_comments = false;
14330                        }
14331
14332                        selection_edit_ranges.push(prefix_range);
14333                    }
14334
14335                    if all_selection_lines_are_comments {
14336                        edits.extend(
14337                            selection_edit_ranges
14338                                .iter()
14339                                .cloned()
14340                                .map(|range| (range, empty_str.clone())),
14341                        );
14342                    } else {
14343                        let min_column = selection_edit_ranges
14344                            .iter()
14345                            .map(|range| range.start.column)
14346                            .min()
14347                            .unwrap_or(0);
14348                        edits.extend(selection_edit_ranges.iter().map(|range| {
14349                            let position = Point::new(range.start.row, min_column);
14350                            (position..position, first_prefix.clone())
14351                        }));
14352                    }
14353                } else if let Some(BlockCommentConfig {
14354                    start: full_comment_prefix,
14355                    end: comment_suffix,
14356                    ..
14357                }) = language.block_comment()
14358                {
14359                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14360                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14361                    let prefix_range = comment_prefix_range(
14362                        snapshot.deref(),
14363                        start_row,
14364                        comment_prefix,
14365                        comment_prefix_whitespace,
14366                        ignore_indent,
14367                    );
14368                    let suffix_range = comment_suffix_range(
14369                        snapshot.deref(),
14370                        end_row,
14371                        comment_suffix.trim_start_matches(' '),
14372                        comment_suffix.starts_with(' '),
14373                    );
14374
14375                    if prefix_range.is_empty() || suffix_range.is_empty() {
14376                        edits.push((
14377                            prefix_range.start..prefix_range.start,
14378                            full_comment_prefix.clone(),
14379                        ));
14380                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14381                        suffixes_inserted.push((end_row, comment_suffix.len()));
14382                    } else {
14383                        edits.push((prefix_range, empty_str.clone()));
14384                        edits.push((suffix_range, empty_str.clone()));
14385                    }
14386                } else {
14387                    continue;
14388                }
14389            }
14390
14391            drop(snapshot);
14392            this.buffer.update(cx, |buffer, cx| {
14393                buffer.edit(edits, None, cx);
14394            });
14395
14396            // Adjust selections so that they end before any comment suffixes that
14397            // were inserted.
14398            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14399            let mut selections = this.selections.all::<Point>(cx);
14400            let snapshot = this.buffer.read(cx).read(cx);
14401            for selection in &mut selections {
14402                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14403                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14404                        Ordering::Less => {
14405                            suffixes_inserted.next();
14406                            continue;
14407                        }
14408                        Ordering::Greater => break,
14409                        Ordering::Equal => {
14410                            if selection.end.column == snapshot.line_len(row) {
14411                                if selection.is_empty() {
14412                                    selection.start.column -= suffix_len as u32;
14413                                }
14414                                selection.end.column -= suffix_len as u32;
14415                            }
14416                            break;
14417                        }
14418                    }
14419                }
14420            }
14421
14422            drop(snapshot);
14423            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14424
14425            let selections = this.selections.all::<Point>(cx);
14426            let selections_on_single_row = selections.windows(2).all(|selections| {
14427                selections[0].start.row == selections[1].start.row
14428                    && selections[0].end.row == selections[1].end.row
14429                    && selections[0].start.row == selections[0].end.row
14430            });
14431            let selections_selecting = selections
14432                .iter()
14433                .any(|selection| selection.start != selection.end);
14434            let advance_downwards = action.advance_downwards
14435                && selections_on_single_row
14436                && !selections_selecting
14437                && !matches!(this.mode, EditorMode::SingleLine { .. });
14438
14439            if advance_downwards {
14440                let snapshot = this.buffer.read(cx).snapshot(cx);
14441
14442                this.change_selections(Default::default(), window, cx, |s| {
14443                    s.move_cursors_with(|display_snapshot, display_point, _| {
14444                        let mut point = display_point.to_point(display_snapshot);
14445                        point.row += 1;
14446                        point = snapshot.clip_point(point, Bias::Left);
14447                        let display_point = point.to_display_point(display_snapshot);
14448                        let goal = SelectionGoal::HorizontalPosition(
14449                            display_snapshot
14450                                .x_for_display_point(display_point, text_layout_details)
14451                                .into(),
14452                        );
14453                        (display_point, goal)
14454                    })
14455                });
14456            }
14457        });
14458    }
14459
14460    pub fn select_enclosing_symbol(
14461        &mut self,
14462        _: &SelectEnclosingSymbol,
14463        window: &mut Window,
14464        cx: &mut Context<Self>,
14465    ) {
14466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14467
14468        let buffer = self.buffer.read(cx).snapshot(cx);
14469        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14470
14471        fn update_selection(
14472            selection: &Selection<usize>,
14473            buffer_snap: &MultiBufferSnapshot,
14474        ) -> Option<Selection<usize>> {
14475            let cursor = selection.head();
14476            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14477            for symbol in symbols.iter().rev() {
14478                let start = symbol.range.start.to_offset(buffer_snap);
14479                let end = symbol.range.end.to_offset(buffer_snap);
14480                let new_range = start..end;
14481                if start < selection.start || end > selection.end {
14482                    return Some(Selection {
14483                        id: selection.id,
14484                        start: new_range.start,
14485                        end: new_range.end,
14486                        goal: SelectionGoal::None,
14487                        reversed: selection.reversed,
14488                    });
14489                }
14490            }
14491            None
14492        }
14493
14494        let mut selected_larger_symbol = false;
14495        let new_selections = old_selections
14496            .iter()
14497            .map(|selection| match update_selection(selection, &buffer) {
14498                Some(new_selection) => {
14499                    if new_selection.range() != selection.range() {
14500                        selected_larger_symbol = true;
14501                    }
14502                    new_selection
14503                }
14504                None => selection.clone(),
14505            })
14506            .collect::<Vec<_>>();
14507
14508        if selected_larger_symbol {
14509            self.change_selections(Default::default(), window, cx, |s| {
14510                s.select(new_selections);
14511            });
14512        }
14513    }
14514
14515    pub fn select_larger_syntax_node(
14516        &mut self,
14517        _: &SelectLargerSyntaxNode,
14518        window: &mut Window,
14519        cx: &mut Context<Self>,
14520    ) {
14521        let Some(visible_row_count) = self.visible_row_count() else {
14522            return;
14523        };
14524        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14525        if old_selections.is_empty() {
14526            return;
14527        }
14528
14529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14530
14531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14532        let buffer = self.buffer.read(cx).snapshot(cx);
14533
14534        let mut selected_larger_node = false;
14535        let mut new_selections = old_selections
14536            .iter()
14537            .map(|selection| {
14538                let old_range = selection.start..selection.end;
14539
14540                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14541                    // manually select word at selection
14542                    if ["string_content", "inline"].contains(&node.kind()) {
14543                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14544                        // ignore if word is already selected
14545                        if !word_range.is_empty() && old_range != word_range {
14546                            let (last_word_range, _) =
14547                                buffer.surrounding_word(old_range.end, false);
14548                            // only select word if start and end point belongs to same word
14549                            if word_range == last_word_range {
14550                                selected_larger_node = true;
14551                                return Selection {
14552                                    id: selection.id,
14553                                    start: word_range.start,
14554                                    end: word_range.end,
14555                                    goal: SelectionGoal::None,
14556                                    reversed: selection.reversed,
14557                                };
14558                            }
14559                        }
14560                    }
14561                }
14562
14563                let mut new_range = old_range.clone();
14564                while let Some((_node, containing_range)) =
14565                    buffer.syntax_ancestor(new_range.clone())
14566                {
14567                    new_range = match containing_range {
14568                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14569                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14570                    };
14571                    if !display_map.intersects_fold(new_range.start)
14572                        && !display_map.intersects_fold(new_range.end)
14573                    {
14574                        break;
14575                    }
14576                }
14577
14578                selected_larger_node |= new_range != old_range;
14579                Selection {
14580                    id: selection.id,
14581                    start: new_range.start,
14582                    end: new_range.end,
14583                    goal: SelectionGoal::None,
14584                    reversed: selection.reversed,
14585                }
14586            })
14587            .collect::<Vec<_>>();
14588
14589        if !selected_larger_node {
14590            return; // don't put this call in the history
14591        }
14592
14593        // scroll based on transformation done to the last selection created by the user
14594        let (last_old, last_new) = old_selections
14595            .last()
14596            .zip(new_selections.last().cloned())
14597            .expect("old_selections isn't empty");
14598
14599        // revert selection
14600        let is_selection_reversed = {
14601            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14602            new_selections.last_mut().expect("checked above").reversed =
14603                should_newest_selection_be_reversed;
14604            should_newest_selection_be_reversed
14605        };
14606
14607        if selected_larger_node {
14608            self.select_syntax_node_history.disable_clearing = true;
14609            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14610                s.select(new_selections.clone());
14611            });
14612            self.select_syntax_node_history.disable_clearing = false;
14613        }
14614
14615        let start_row = last_new.start.to_display_point(&display_map).row().0;
14616        let end_row = last_new.end.to_display_point(&display_map).row().0;
14617        let selection_height = end_row - start_row + 1;
14618        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14619
14620        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14621        let scroll_behavior = if fits_on_the_screen {
14622            self.request_autoscroll(Autoscroll::fit(), cx);
14623            SelectSyntaxNodeScrollBehavior::FitSelection
14624        } else if is_selection_reversed {
14625            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14626            SelectSyntaxNodeScrollBehavior::CursorTop
14627        } else {
14628            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14629            SelectSyntaxNodeScrollBehavior::CursorBottom
14630        };
14631
14632        self.select_syntax_node_history.push((
14633            old_selections,
14634            scroll_behavior,
14635            is_selection_reversed,
14636        ));
14637    }
14638
14639    pub fn select_smaller_syntax_node(
14640        &mut self,
14641        _: &SelectSmallerSyntaxNode,
14642        window: &mut Window,
14643        cx: &mut Context<Self>,
14644    ) {
14645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14646
14647        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14648            self.select_syntax_node_history.pop()
14649        {
14650            if let Some(selection) = selections.last_mut() {
14651                selection.reversed = is_selection_reversed;
14652            }
14653
14654            self.select_syntax_node_history.disable_clearing = true;
14655            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14656                s.select(selections.to_vec());
14657            });
14658            self.select_syntax_node_history.disable_clearing = false;
14659
14660            match scroll_behavior {
14661                SelectSyntaxNodeScrollBehavior::CursorTop => {
14662                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14663                }
14664                SelectSyntaxNodeScrollBehavior::FitSelection => {
14665                    self.request_autoscroll(Autoscroll::fit(), cx);
14666                }
14667                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14668                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14669                }
14670            }
14671        }
14672    }
14673
14674    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14675        if !EditorSettings::get_global(cx).gutter.runnables {
14676            self.clear_tasks();
14677            return Task::ready(());
14678        }
14679        let project = self.project.as_ref().map(Entity::downgrade);
14680        let task_sources = self.lsp_task_sources(cx);
14681        let multi_buffer = self.buffer.downgrade();
14682        cx.spawn_in(window, async move |editor, cx| {
14683            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14684            let Some(project) = project.and_then(|p| p.upgrade()) else {
14685                return;
14686            };
14687            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14688                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14689            }) else {
14690                return;
14691            };
14692
14693            let hide_runnables = project
14694                .update(cx, |project, cx| {
14695                    // Do not display any test indicators in non-dev server remote projects.
14696                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14697                })
14698                .unwrap_or(true);
14699            if hide_runnables {
14700                return;
14701            }
14702            let new_rows =
14703                cx.background_spawn({
14704                    let snapshot = display_snapshot.clone();
14705                    async move {
14706                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14707                    }
14708                })
14709                    .await;
14710            let Ok(lsp_tasks) =
14711                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14712            else {
14713                return;
14714            };
14715            let lsp_tasks = lsp_tasks.await;
14716
14717            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14718                lsp_tasks
14719                    .into_iter()
14720                    .flat_map(|(kind, tasks)| {
14721                        tasks.into_iter().filter_map(move |(location, task)| {
14722                            Some((kind.clone(), location?, task))
14723                        })
14724                    })
14725                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14726                        let buffer = location.target.buffer;
14727                        let buffer_snapshot = buffer.read(cx).snapshot();
14728                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14729                            |(excerpt_id, snapshot, _)| {
14730                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14731                                    display_snapshot
14732                                        .buffer_snapshot
14733                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14734                                } else {
14735                                    None
14736                                }
14737                            },
14738                        );
14739                        if let Some(offset) = offset {
14740                            let task_buffer_range =
14741                                location.target.range.to_point(&buffer_snapshot);
14742                            let context_buffer_range =
14743                                task_buffer_range.to_offset(&buffer_snapshot);
14744                            let context_range = BufferOffset(context_buffer_range.start)
14745                                ..BufferOffset(context_buffer_range.end);
14746
14747                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14748                                .or_insert_with(|| RunnableTasks {
14749                                    templates: Vec::new(),
14750                                    offset,
14751                                    column: task_buffer_range.start.column,
14752                                    extra_variables: HashMap::default(),
14753                                    context_range,
14754                                })
14755                                .templates
14756                                .push((kind, task.original_task().clone()));
14757                        }
14758
14759                        acc
14760                    })
14761            }) else {
14762                return;
14763            };
14764
14765            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14766                buffer.language_settings(cx).tasks.prefer_lsp
14767            }) else {
14768                return;
14769            };
14770
14771            let rows = Self::runnable_rows(
14772                project,
14773                display_snapshot,
14774                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14775                new_rows,
14776                cx.clone(),
14777            )
14778            .await;
14779            editor
14780                .update(cx, |editor, _| {
14781                    editor.clear_tasks();
14782                    for (key, mut value) in rows {
14783                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14784                            value.templates.extend(lsp_tasks.templates);
14785                        }
14786
14787                        editor.insert_tasks(key, value);
14788                    }
14789                    for (key, value) in lsp_tasks_by_rows {
14790                        editor.insert_tasks(key, value);
14791                    }
14792                })
14793                .ok();
14794        })
14795    }
14796    fn fetch_runnable_ranges(
14797        snapshot: &DisplaySnapshot,
14798        range: Range<Anchor>,
14799    ) -> Vec<language::RunnableRange> {
14800        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14801    }
14802
14803    fn runnable_rows(
14804        project: Entity<Project>,
14805        snapshot: DisplaySnapshot,
14806        prefer_lsp: bool,
14807        runnable_ranges: Vec<RunnableRange>,
14808        cx: AsyncWindowContext,
14809    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14810        cx.spawn(async move |cx| {
14811            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14812            for mut runnable in runnable_ranges {
14813                let Some(tasks) = cx
14814                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14815                    .ok()
14816                else {
14817                    continue;
14818                };
14819                let mut tasks = tasks.await;
14820
14821                if prefer_lsp {
14822                    tasks.retain(|(task_kind, _)| {
14823                        !matches!(task_kind, TaskSourceKind::Language { .. })
14824                    });
14825                }
14826                if tasks.is_empty() {
14827                    continue;
14828                }
14829
14830                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14831                let Some(row) = snapshot
14832                    .buffer_snapshot
14833                    .buffer_line_for_row(MultiBufferRow(point.row))
14834                    .map(|(_, range)| range.start.row)
14835                else {
14836                    continue;
14837                };
14838
14839                let context_range =
14840                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14841                runnable_rows.push((
14842                    (runnable.buffer_id, row),
14843                    RunnableTasks {
14844                        templates: tasks,
14845                        offset: snapshot
14846                            .buffer_snapshot
14847                            .anchor_before(runnable.run_range.start),
14848                        context_range,
14849                        column: point.column,
14850                        extra_variables: runnable.extra_captures,
14851                    },
14852                ));
14853            }
14854            runnable_rows
14855        })
14856    }
14857
14858    fn templates_with_tags(
14859        project: &Entity<Project>,
14860        runnable: &mut Runnable,
14861        cx: &mut App,
14862    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14863        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14864            let (worktree_id, file) = project
14865                .buffer_for_id(runnable.buffer, cx)
14866                .and_then(|buffer| buffer.read(cx).file())
14867                .map(|file| (file.worktree_id(cx), file.clone()))
14868                .unzip();
14869
14870            (
14871                project.task_store().read(cx).task_inventory().cloned(),
14872                worktree_id,
14873                file,
14874            )
14875        });
14876
14877        let tags = mem::take(&mut runnable.tags);
14878        let language = runnable.language.clone();
14879        cx.spawn(async move |cx| {
14880            let mut templates_with_tags = Vec::new();
14881            if let Some(inventory) = inventory {
14882                for RunnableTag(tag) in tags {
14883                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14884                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14885                    }) else {
14886                        return templates_with_tags;
14887                    };
14888                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14889                        move |(_, template)| {
14890                            template.tags.iter().any(|source_tag| source_tag == &tag)
14891                        },
14892                    ));
14893                }
14894            }
14895            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14896
14897            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14898                // Strongest source wins; if we have worktree tag binding, prefer that to
14899                // global and language bindings;
14900                // if we have a global binding, prefer that to language binding.
14901                let first_mismatch = templates_with_tags
14902                    .iter()
14903                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14904                if let Some(index) = first_mismatch {
14905                    templates_with_tags.truncate(index);
14906                }
14907            }
14908
14909            templates_with_tags
14910        })
14911    }
14912
14913    pub fn move_to_enclosing_bracket(
14914        &mut self,
14915        _: &MoveToEnclosingBracket,
14916        window: &mut Window,
14917        cx: &mut Context<Self>,
14918    ) {
14919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14920        self.change_selections(Default::default(), window, cx, |s| {
14921            s.move_offsets_with(|snapshot, selection| {
14922                let Some(enclosing_bracket_ranges) =
14923                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14924                else {
14925                    return;
14926                };
14927
14928                let mut best_length = usize::MAX;
14929                let mut best_inside = false;
14930                let mut best_in_bracket_range = false;
14931                let mut best_destination = None;
14932                for (open, close) in enclosing_bracket_ranges {
14933                    let close = close.to_inclusive();
14934                    let length = close.end() - open.start;
14935                    let inside = selection.start >= open.end && selection.end <= *close.start();
14936                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14937                        || close.contains(&selection.head());
14938
14939                    // If best is next to a bracket and current isn't, skip
14940                    if !in_bracket_range && best_in_bracket_range {
14941                        continue;
14942                    }
14943
14944                    // Prefer smaller lengths unless best is inside and current isn't
14945                    if length > best_length && (best_inside || !inside) {
14946                        continue;
14947                    }
14948
14949                    best_length = length;
14950                    best_inside = inside;
14951                    best_in_bracket_range = in_bracket_range;
14952                    best_destination = Some(
14953                        if close.contains(&selection.start) && close.contains(&selection.end) {
14954                            if inside { open.end } else { open.start }
14955                        } else if inside {
14956                            *close.start()
14957                        } else {
14958                            *close.end()
14959                        },
14960                    );
14961                }
14962
14963                if let Some(destination) = best_destination {
14964                    selection.collapse_to(destination, SelectionGoal::None);
14965                }
14966            })
14967        });
14968    }
14969
14970    pub fn undo_selection(
14971        &mut self,
14972        _: &UndoSelection,
14973        window: &mut Window,
14974        cx: &mut Context<Self>,
14975    ) {
14976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14977        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14978            self.selection_history.mode = SelectionHistoryMode::Undoing;
14979            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14980                this.end_selection(window, cx);
14981                this.change_selections(
14982                    SelectionEffects::scroll(Autoscroll::newest()),
14983                    window,
14984                    cx,
14985                    |s| s.select_anchors(entry.selections.to_vec()),
14986                );
14987            });
14988            self.selection_history.mode = SelectionHistoryMode::Normal;
14989
14990            self.select_next_state = entry.select_next_state;
14991            self.select_prev_state = entry.select_prev_state;
14992            self.add_selections_state = entry.add_selections_state;
14993        }
14994    }
14995
14996    pub fn redo_selection(
14997        &mut self,
14998        _: &RedoSelection,
14999        window: &mut Window,
15000        cx: &mut Context<Self>,
15001    ) {
15002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15003        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15004            self.selection_history.mode = SelectionHistoryMode::Redoing;
15005            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15006                this.end_selection(window, cx);
15007                this.change_selections(
15008                    SelectionEffects::scroll(Autoscroll::newest()),
15009                    window,
15010                    cx,
15011                    |s| s.select_anchors(entry.selections.to_vec()),
15012                );
15013            });
15014            self.selection_history.mode = SelectionHistoryMode::Normal;
15015
15016            self.select_next_state = entry.select_next_state;
15017            self.select_prev_state = entry.select_prev_state;
15018            self.add_selections_state = entry.add_selections_state;
15019        }
15020    }
15021
15022    pub fn expand_excerpts(
15023        &mut self,
15024        action: &ExpandExcerpts,
15025        _: &mut Window,
15026        cx: &mut Context<Self>,
15027    ) {
15028        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15029    }
15030
15031    pub fn expand_excerpts_down(
15032        &mut self,
15033        action: &ExpandExcerptsDown,
15034        _: &mut Window,
15035        cx: &mut Context<Self>,
15036    ) {
15037        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15038    }
15039
15040    pub fn expand_excerpts_up(
15041        &mut self,
15042        action: &ExpandExcerptsUp,
15043        _: &mut Window,
15044        cx: &mut Context<Self>,
15045    ) {
15046        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15047    }
15048
15049    pub fn expand_excerpts_for_direction(
15050        &mut self,
15051        lines: u32,
15052        direction: ExpandExcerptDirection,
15053
15054        cx: &mut Context<Self>,
15055    ) {
15056        let selections = self.selections.disjoint_anchors();
15057
15058        let lines = if lines == 0 {
15059            EditorSettings::get_global(cx).expand_excerpt_lines
15060        } else {
15061            lines
15062        };
15063
15064        self.buffer.update(cx, |buffer, cx| {
15065            let snapshot = buffer.snapshot(cx);
15066            let mut excerpt_ids = selections
15067                .iter()
15068                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15069                .collect::<Vec<_>>();
15070            excerpt_ids.sort();
15071            excerpt_ids.dedup();
15072            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15073        })
15074    }
15075
15076    pub fn expand_excerpt(
15077        &mut self,
15078        excerpt: ExcerptId,
15079        direction: ExpandExcerptDirection,
15080        window: &mut Window,
15081        cx: &mut Context<Self>,
15082    ) {
15083        let current_scroll_position = self.scroll_position(cx);
15084        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15085        let mut should_scroll_up = false;
15086
15087        if direction == ExpandExcerptDirection::Down {
15088            let multi_buffer = self.buffer.read(cx);
15089            let snapshot = multi_buffer.snapshot(cx);
15090            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15091                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15092                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15093                        let buffer_snapshot = buffer.read(cx).snapshot();
15094                        let excerpt_end_row =
15095                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15096                        let last_row = buffer_snapshot.max_point().row;
15097                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15098                        should_scroll_up = lines_below >= lines_to_expand;
15099                    }
15100                }
15101            }
15102        }
15103
15104        self.buffer.update(cx, |buffer, cx| {
15105            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15106        });
15107
15108        if should_scroll_up {
15109            let new_scroll_position =
15110                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15111            self.set_scroll_position(new_scroll_position, window, cx);
15112        }
15113    }
15114
15115    pub fn go_to_singleton_buffer_point(
15116        &mut self,
15117        point: Point,
15118        window: &mut Window,
15119        cx: &mut Context<Self>,
15120    ) {
15121        self.go_to_singleton_buffer_range(point..point, window, cx);
15122    }
15123
15124    pub fn go_to_singleton_buffer_range(
15125        &mut self,
15126        range: Range<Point>,
15127        window: &mut Window,
15128        cx: &mut Context<Self>,
15129    ) {
15130        let multibuffer = self.buffer().read(cx);
15131        let Some(buffer) = multibuffer.as_singleton() else {
15132            return;
15133        };
15134        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15135            return;
15136        };
15137        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15138            return;
15139        };
15140        self.change_selections(
15141            SelectionEffects::default().nav_history(true),
15142            window,
15143            cx,
15144            |s| s.select_anchor_ranges([start..end]),
15145        );
15146    }
15147
15148    pub fn go_to_diagnostic(
15149        &mut self,
15150        action: &GoToDiagnostic,
15151        window: &mut Window,
15152        cx: &mut Context<Self>,
15153    ) {
15154        if !self.diagnostics_enabled() {
15155            return;
15156        }
15157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15158        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15159    }
15160
15161    pub fn go_to_prev_diagnostic(
15162        &mut self,
15163        action: &GoToPreviousDiagnostic,
15164        window: &mut Window,
15165        cx: &mut Context<Self>,
15166    ) {
15167        if !self.diagnostics_enabled() {
15168            return;
15169        }
15170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15171        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15172    }
15173
15174    pub fn go_to_diagnostic_impl(
15175        &mut self,
15176        direction: Direction,
15177        severity: GoToDiagnosticSeverityFilter,
15178        window: &mut Window,
15179        cx: &mut Context<Self>,
15180    ) {
15181        let buffer = self.buffer.read(cx).snapshot(cx);
15182        let selection = self.selections.newest::<usize>(cx);
15183
15184        let mut active_group_id = None;
15185        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15186            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15187                active_group_id = Some(active_group.group_id);
15188            }
15189        }
15190
15191        fn filtered(
15192            snapshot: EditorSnapshot,
15193            severity: GoToDiagnosticSeverityFilter,
15194            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15195        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15196            diagnostics
15197                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15198                .filter(|entry| entry.range.start != entry.range.end)
15199                .filter(|entry| !entry.diagnostic.is_unnecessary)
15200                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15201        }
15202
15203        let snapshot = self.snapshot(window, cx);
15204        let before = filtered(
15205            snapshot.clone(),
15206            severity,
15207            buffer
15208                .diagnostics_in_range(0..selection.start)
15209                .filter(|entry| entry.range.start <= selection.start),
15210        );
15211        let after = filtered(
15212            snapshot,
15213            severity,
15214            buffer
15215                .diagnostics_in_range(selection.start..buffer.len())
15216                .filter(|entry| entry.range.start >= selection.start),
15217        );
15218
15219        let mut found: Option<DiagnosticEntry<usize>> = None;
15220        if direction == Direction::Prev {
15221            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15222            {
15223                for diagnostic in prev_diagnostics.into_iter().rev() {
15224                    if diagnostic.range.start != selection.start
15225                        || active_group_id
15226                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15227                    {
15228                        found = Some(diagnostic);
15229                        break 'outer;
15230                    }
15231                }
15232            }
15233        } else {
15234            for diagnostic in after.chain(before) {
15235                if diagnostic.range.start != selection.start
15236                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15237                {
15238                    found = Some(diagnostic);
15239                    break;
15240                }
15241            }
15242        }
15243        let Some(next_diagnostic) = found else {
15244            return;
15245        };
15246
15247        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15248            return;
15249        };
15250        self.change_selections(Default::default(), window, cx, |s| {
15251            s.select_ranges(vec![
15252                next_diagnostic.range.start..next_diagnostic.range.start,
15253            ])
15254        });
15255        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15256        self.refresh_inline_completion(false, true, window, cx);
15257    }
15258
15259    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15260        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15261        let snapshot = self.snapshot(window, cx);
15262        let selection = self.selections.newest::<Point>(cx);
15263        self.go_to_hunk_before_or_after_position(
15264            &snapshot,
15265            selection.head(),
15266            Direction::Next,
15267            window,
15268            cx,
15269        );
15270    }
15271
15272    pub fn go_to_hunk_before_or_after_position(
15273        &mut self,
15274        snapshot: &EditorSnapshot,
15275        position: Point,
15276        direction: Direction,
15277        window: &mut Window,
15278        cx: &mut Context<Editor>,
15279    ) {
15280        let row = if direction == Direction::Next {
15281            self.hunk_after_position(snapshot, position)
15282                .map(|hunk| hunk.row_range.start)
15283        } else {
15284            self.hunk_before_position(snapshot, position)
15285        };
15286
15287        if let Some(row) = row {
15288            let destination = Point::new(row.0, 0);
15289            let autoscroll = Autoscroll::center();
15290
15291            self.unfold_ranges(&[destination..destination], false, false, cx);
15292            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15293                s.select_ranges([destination..destination]);
15294            });
15295        }
15296    }
15297
15298    fn hunk_after_position(
15299        &mut self,
15300        snapshot: &EditorSnapshot,
15301        position: Point,
15302    ) -> Option<MultiBufferDiffHunk> {
15303        snapshot
15304            .buffer_snapshot
15305            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15306            .find(|hunk| hunk.row_range.start.0 > position.row)
15307            .or_else(|| {
15308                snapshot
15309                    .buffer_snapshot
15310                    .diff_hunks_in_range(Point::zero()..position)
15311                    .find(|hunk| hunk.row_range.end.0 < position.row)
15312            })
15313    }
15314
15315    fn go_to_prev_hunk(
15316        &mut self,
15317        _: &GoToPreviousHunk,
15318        window: &mut Window,
15319        cx: &mut Context<Self>,
15320    ) {
15321        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15322        let snapshot = self.snapshot(window, cx);
15323        let selection = self.selections.newest::<Point>(cx);
15324        self.go_to_hunk_before_or_after_position(
15325            &snapshot,
15326            selection.head(),
15327            Direction::Prev,
15328            window,
15329            cx,
15330        );
15331    }
15332
15333    fn hunk_before_position(
15334        &mut self,
15335        snapshot: &EditorSnapshot,
15336        position: Point,
15337    ) -> Option<MultiBufferRow> {
15338        snapshot
15339            .buffer_snapshot
15340            .diff_hunk_before(position)
15341            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15342    }
15343
15344    fn go_to_next_change(
15345        &mut self,
15346        _: &GoToNextChange,
15347        window: &mut Window,
15348        cx: &mut Context<Self>,
15349    ) {
15350        if let Some(selections) = self
15351            .change_list
15352            .next_change(1, Direction::Next)
15353            .map(|s| s.to_vec())
15354        {
15355            self.change_selections(Default::default(), window, cx, |s| {
15356                let map = s.display_map();
15357                s.select_display_ranges(selections.iter().map(|a| {
15358                    let point = a.to_display_point(&map);
15359                    point..point
15360                }))
15361            })
15362        }
15363    }
15364
15365    fn go_to_previous_change(
15366        &mut self,
15367        _: &GoToPreviousChange,
15368        window: &mut Window,
15369        cx: &mut Context<Self>,
15370    ) {
15371        if let Some(selections) = self
15372            .change_list
15373            .next_change(1, Direction::Prev)
15374            .map(|s| s.to_vec())
15375        {
15376            self.change_selections(Default::default(), window, cx, |s| {
15377                let map = s.display_map();
15378                s.select_display_ranges(selections.iter().map(|a| {
15379                    let point = a.to_display_point(&map);
15380                    point..point
15381                }))
15382            })
15383        }
15384    }
15385
15386    fn go_to_line<T: 'static>(
15387        &mut self,
15388        position: Anchor,
15389        highlight_color: Option<Hsla>,
15390        window: &mut Window,
15391        cx: &mut Context<Self>,
15392    ) {
15393        let snapshot = self.snapshot(window, cx).display_snapshot;
15394        let position = position.to_point(&snapshot.buffer_snapshot);
15395        let start = snapshot
15396            .buffer_snapshot
15397            .clip_point(Point::new(position.row, 0), Bias::Left);
15398        let end = start + Point::new(1, 0);
15399        let start = snapshot.buffer_snapshot.anchor_before(start);
15400        let end = snapshot.buffer_snapshot.anchor_before(end);
15401
15402        self.highlight_rows::<T>(
15403            start..end,
15404            highlight_color
15405                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15406            Default::default(),
15407            cx,
15408        );
15409
15410        if self.buffer.read(cx).is_singleton() {
15411            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15412        }
15413    }
15414
15415    pub fn go_to_definition(
15416        &mut self,
15417        _: &GoToDefinition,
15418        window: &mut Window,
15419        cx: &mut Context<Self>,
15420    ) -> Task<Result<Navigated>> {
15421        let definition =
15422            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15423        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15424        cx.spawn_in(window, async move |editor, cx| {
15425            if definition.await? == Navigated::Yes {
15426                return Ok(Navigated::Yes);
15427            }
15428            match fallback_strategy {
15429                GoToDefinitionFallback::None => Ok(Navigated::No),
15430                GoToDefinitionFallback::FindAllReferences => {
15431                    match editor.update_in(cx, |editor, window, cx| {
15432                        editor.find_all_references(&FindAllReferences, window, cx)
15433                    })? {
15434                        Some(references) => references.await,
15435                        None => Ok(Navigated::No),
15436                    }
15437                }
15438            }
15439        })
15440    }
15441
15442    pub fn go_to_declaration(
15443        &mut self,
15444        _: &GoToDeclaration,
15445        window: &mut Window,
15446        cx: &mut Context<Self>,
15447    ) -> Task<Result<Navigated>> {
15448        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15449    }
15450
15451    pub fn go_to_declaration_split(
15452        &mut self,
15453        _: &GoToDeclaration,
15454        window: &mut Window,
15455        cx: &mut Context<Self>,
15456    ) -> Task<Result<Navigated>> {
15457        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15458    }
15459
15460    pub fn go_to_implementation(
15461        &mut self,
15462        _: &GoToImplementation,
15463        window: &mut Window,
15464        cx: &mut Context<Self>,
15465    ) -> Task<Result<Navigated>> {
15466        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15467    }
15468
15469    pub fn go_to_implementation_split(
15470        &mut self,
15471        _: &GoToImplementationSplit,
15472        window: &mut Window,
15473        cx: &mut Context<Self>,
15474    ) -> Task<Result<Navigated>> {
15475        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15476    }
15477
15478    pub fn go_to_type_definition(
15479        &mut self,
15480        _: &GoToTypeDefinition,
15481        window: &mut Window,
15482        cx: &mut Context<Self>,
15483    ) -> Task<Result<Navigated>> {
15484        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15485    }
15486
15487    pub fn go_to_definition_split(
15488        &mut self,
15489        _: &GoToDefinitionSplit,
15490        window: &mut Window,
15491        cx: &mut Context<Self>,
15492    ) -> Task<Result<Navigated>> {
15493        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15494    }
15495
15496    pub fn go_to_type_definition_split(
15497        &mut self,
15498        _: &GoToTypeDefinitionSplit,
15499        window: &mut Window,
15500        cx: &mut Context<Self>,
15501    ) -> Task<Result<Navigated>> {
15502        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15503    }
15504
15505    fn go_to_definition_of_kind(
15506        &mut self,
15507        kind: GotoDefinitionKind,
15508        split: bool,
15509        window: &mut Window,
15510        cx: &mut Context<Self>,
15511    ) -> Task<Result<Navigated>> {
15512        let Some(provider) = self.semantics_provider.clone() else {
15513            return Task::ready(Ok(Navigated::No));
15514        };
15515        let head = self.selections.newest::<usize>(cx).head();
15516        let buffer = self.buffer.read(cx);
15517        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15518            text_anchor
15519        } else {
15520            return Task::ready(Ok(Navigated::No));
15521        };
15522
15523        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15524            return Task::ready(Ok(Navigated::No));
15525        };
15526
15527        cx.spawn_in(window, async move |editor, cx| {
15528            let definitions = definitions.await?;
15529            let navigated = editor
15530                .update_in(cx, |editor, window, cx| {
15531                    editor.navigate_to_hover_links(
15532                        Some(kind),
15533                        definitions
15534                            .into_iter()
15535                            .filter(|location| {
15536                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15537                            })
15538                            .map(HoverLink::Text)
15539                            .collect::<Vec<_>>(),
15540                        split,
15541                        window,
15542                        cx,
15543                    )
15544                })?
15545                .await?;
15546            anyhow::Ok(navigated)
15547        })
15548    }
15549
15550    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15551        let selection = self.selections.newest_anchor();
15552        let head = selection.head();
15553        let tail = selection.tail();
15554
15555        let Some((buffer, start_position)) =
15556            self.buffer.read(cx).text_anchor_for_position(head, cx)
15557        else {
15558            return;
15559        };
15560
15561        let end_position = if head != tail {
15562            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15563                return;
15564            };
15565            Some(pos)
15566        } else {
15567            None
15568        };
15569
15570        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15571            let url = if let Some(end_pos) = end_position {
15572                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15573            } else {
15574                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15575            };
15576
15577            if let Some(url) = url {
15578                editor.update(cx, |_, cx| {
15579                    cx.open_url(&url);
15580                })
15581            } else {
15582                Ok(())
15583            }
15584        });
15585
15586        url_finder.detach();
15587    }
15588
15589    pub fn open_selected_filename(
15590        &mut self,
15591        _: &OpenSelectedFilename,
15592        window: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) {
15595        let Some(workspace) = self.workspace() else {
15596            return;
15597        };
15598
15599        let position = self.selections.newest_anchor().head();
15600
15601        let Some((buffer, buffer_position)) =
15602            self.buffer.read(cx).text_anchor_for_position(position, cx)
15603        else {
15604            return;
15605        };
15606
15607        let project = self.project.clone();
15608
15609        cx.spawn_in(window, async move |_, cx| {
15610            let result = find_file(&buffer, project, buffer_position, cx).await;
15611
15612            if let Some((_, path)) = result {
15613                workspace
15614                    .update_in(cx, |workspace, window, cx| {
15615                        workspace.open_resolved_path(path, window, cx)
15616                    })?
15617                    .await?;
15618            }
15619            anyhow::Ok(())
15620        })
15621        .detach();
15622    }
15623
15624    pub(crate) fn navigate_to_hover_links(
15625        &mut self,
15626        kind: Option<GotoDefinitionKind>,
15627        mut definitions: Vec<HoverLink>,
15628        split: bool,
15629        window: &mut Window,
15630        cx: &mut Context<Editor>,
15631    ) -> Task<Result<Navigated>> {
15632        // If there is one definition, just open it directly
15633        if definitions.len() == 1 {
15634            let definition = definitions.pop().unwrap();
15635
15636            enum TargetTaskResult {
15637                Location(Option<Location>),
15638                AlreadyNavigated,
15639            }
15640
15641            let target_task = match definition {
15642                HoverLink::Text(link) => {
15643                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15644                }
15645                HoverLink::InlayHint(lsp_location, server_id) => {
15646                    let computation =
15647                        self.compute_target_location(lsp_location, server_id, window, cx);
15648                    cx.background_spawn(async move {
15649                        let location = computation.await?;
15650                        Ok(TargetTaskResult::Location(location))
15651                    })
15652                }
15653                HoverLink::Url(url) => {
15654                    cx.open_url(&url);
15655                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15656                }
15657                HoverLink::File(path) => {
15658                    if let Some(workspace) = self.workspace() {
15659                        cx.spawn_in(window, async move |_, cx| {
15660                            workspace
15661                                .update_in(cx, |workspace, window, cx| {
15662                                    workspace.open_resolved_path(path, window, cx)
15663                                })?
15664                                .await
15665                                .map(|_| TargetTaskResult::AlreadyNavigated)
15666                        })
15667                    } else {
15668                        Task::ready(Ok(TargetTaskResult::Location(None)))
15669                    }
15670                }
15671            };
15672            cx.spawn_in(window, async move |editor, cx| {
15673                let target = match target_task.await.context("target resolution task")? {
15674                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15675                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15676                    TargetTaskResult::Location(Some(target)) => target,
15677                };
15678
15679                editor.update_in(cx, |editor, window, cx| {
15680                    let Some(workspace) = editor.workspace() else {
15681                        return Navigated::No;
15682                    };
15683                    let pane = workspace.read(cx).active_pane().clone();
15684
15685                    let range = target.range.to_point(target.buffer.read(cx));
15686                    let range = editor.range_for_match(&range);
15687                    let range = collapse_multiline_range(range);
15688
15689                    if !split
15690                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15691                    {
15692                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15693                    } else {
15694                        window.defer(cx, move |window, cx| {
15695                            let target_editor: Entity<Self> =
15696                                workspace.update(cx, |workspace, cx| {
15697                                    let pane = if split {
15698                                        workspace.adjacent_pane(window, cx)
15699                                    } else {
15700                                        workspace.active_pane().clone()
15701                                    };
15702
15703                                    workspace.open_project_item(
15704                                        pane,
15705                                        target.buffer.clone(),
15706                                        true,
15707                                        true,
15708                                        window,
15709                                        cx,
15710                                    )
15711                                });
15712                            target_editor.update(cx, |target_editor, cx| {
15713                                // When selecting a definition in a different buffer, disable the nav history
15714                                // to avoid creating a history entry at the previous cursor location.
15715                                pane.update(cx, |pane, _| pane.disable_history());
15716                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15717                                pane.update(cx, |pane, _| pane.enable_history());
15718                            });
15719                        });
15720                    }
15721                    Navigated::Yes
15722                })
15723            })
15724        } else if !definitions.is_empty() {
15725            cx.spawn_in(window, async move |editor, cx| {
15726                let (title, location_tasks, workspace) = editor
15727                    .update_in(cx, |editor, window, cx| {
15728                        let tab_kind = match kind {
15729                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15730                            _ => "Definitions",
15731                        };
15732                        let title = definitions
15733                            .iter()
15734                            .find_map(|definition| match definition {
15735                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15736                                    let buffer = origin.buffer.read(cx);
15737                                    format!(
15738                                        "{} for {}",
15739                                        tab_kind,
15740                                        buffer
15741                                            .text_for_range(origin.range.clone())
15742                                            .collect::<String>()
15743                                    )
15744                                }),
15745                                HoverLink::InlayHint(_, _) => None,
15746                                HoverLink::Url(_) => None,
15747                                HoverLink::File(_) => None,
15748                            })
15749                            .unwrap_or(tab_kind.to_string());
15750                        let location_tasks = definitions
15751                            .into_iter()
15752                            .map(|definition| match definition {
15753                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15754                                HoverLink::InlayHint(lsp_location, server_id) => editor
15755                                    .compute_target_location(lsp_location, server_id, window, cx),
15756                                HoverLink::Url(_) => Task::ready(Ok(None)),
15757                                HoverLink::File(_) => Task::ready(Ok(None)),
15758                            })
15759                            .collect::<Vec<_>>();
15760                        (title, location_tasks, editor.workspace().clone())
15761                    })
15762                    .context("location tasks preparation")?;
15763
15764                let locations: Vec<Location> = future::join_all(location_tasks)
15765                    .await
15766                    .into_iter()
15767                    .filter_map(|location| location.transpose())
15768                    .collect::<Result<_>>()
15769                    .context("location tasks")?;
15770
15771                if locations.is_empty() {
15772                    return Ok(Navigated::No);
15773                }
15774
15775                let Some(workspace) = workspace else {
15776                    return Ok(Navigated::No);
15777                };
15778
15779                let opened = workspace
15780                    .update_in(cx, |workspace, window, cx| {
15781                        Self::open_locations_in_multibuffer(
15782                            workspace,
15783                            locations,
15784                            title,
15785                            split,
15786                            MultibufferSelectionMode::First,
15787                            window,
15788                            cx,
15789                        )
15790                    })
15791                    .ok();
15792
15793                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15794            })
15795        } else {
15796            Task::ready(Ok(Navigated::No))
15797        }
15798    }
15799
15800    fn compute_target_location(
15801        &self,
15802        lsp_location: lsp::Location,
15803        server_id: LanguageServerId,
15804        window: &mut Window,
15805        cx: &mut Context<Self>,
15806    ) -> Task<anyhow::Result<Option<Location>>> {
15807        let Some(project) = self.project.clone() else {
15808            return Task::ready(Ok(None));
15809        };
15810
15811        cx.spawn_in(window, async move |editor, cx| {
15812            let location_task = editor.update(cx, |_, cx| {
15813                project.update(cx, |project, cx| {
15814                    let language_server_name = project
15815                        .language_server_statuses(cx)
15816                        .find(|(id, _)| server_id == *id)
15817                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15818                    language_server_name.map(|language_server_name| {
15819                        project.open_local_buffer_via_lsp(
15820                            lsp_location.uri.clone(),
15821                            server_id,
15822                            language_server_name,
15823                            cx,
15824                        )
15825                    })
15826                })
15827            })?;
15828            let location = match location_task {
15829                Some(task) => Some({
15830                    let target_buffer_handle = task.await.context("open local buffer")?;
15831                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15832                        let target_start = target_buffer
15833                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15834                        let target_end = target_buffer
15835                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15836                        target_buffer.anchor_after(target_start)
15837                            ..target_buffer.anchor_before(target_end)
15838                    })?;
15839                    Location {
15840                        buffer: target_buffer_handle,
15841                        range,
15842                    }
15843                }),
15844                None => None,
15845            };
15846            Ok(location)
15847        })
15848    }
15849
15850    pub fn find_all_references(
15851        &mut self,
15852        _: &FindAllReferences,
15853        window: &mut Window,
15854        cx: &mut Context<Self>,
15855    ) -> Option<Task<Result<Navigated>>> {
15856        let selection = self.selections.newest::<usize>(cx);
15857        let multi_buffer = self.buffer.read(cx);
15858        let head = selection.head();
15859
15860        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15861        let head_anchor = multi_buffer_snapshot.anchor_at(
15862            head,
15863            if head < selection.tail() {
15864                Bias::Right
15865            } else {
15866                Bias::Left
15867            },
15868        );
15869
15870        match self
15871            .find_all_references_task_sources
15872            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15873        {
15874            Ok(_) => {
15875                log::info!(
15876                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15877                );
15878                return None;
15879            }
15880            Err(i) => {
15881                self.find_all_references_task_sources.insert(i, head_anchor);
15882            }
15883        }
15884
15885        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15886        let workspace = self.workspace()?;
15887        let project = workspace.read(cx).project().clone();
15888        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15889        Some(cx.spawn_in(window, async move |editor, cx| {
15890            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15891                if let Ok(i) = editor
15892                    .find_all_references_task_sources
15893                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15894                {
15895                    editor.find_all_references_task_sources.remove(i);
15896                }
15897            });
15898
15899            let locations = references.await?;
15900            if locations.is_empty() {
15901                return anyhow::Ok(Navigated::No);
15902            }
15903
15904            workspace.update_in(cx, |workspace, window, cx| {
15905                let title = locations
15906                    .first()
15907                    .as_ref()
15908                    .map(|location| {
15909                        let buffer = location.buffer.read(cx);
15910                        format!(
15911                            "References to `{}`",
15912                            buffer
15913                                .text_for_range(location.range.clone())
15914                                .collect::<String>()
15915                        )
15916                    })
15917                    .unwrap();
15918                Self::open_locations_in_multibuffer(
15919                    workspace,
15920                    locations,
15921                    title,
15922                    false,
15923                    MultibufferSelectionMode::First,
15924                    window,
15925                    cx,
15926                );
15927                Navigated::Yes
15928            })
15929        }))
15930    }
15931
15932    /// Opens a multibuffer with the given project locations in it
15933    pub fn open_locations_in_multibuffer(
15934        workspace: &mut Workspace,
15935        mut locations: Vec<Location>,
15936        title: String,
15937        split: bool,
15938        multibuffer_selection_mode: MultibufferSelectionMode,
15939        window: &mut Window,
15940        cx: &mut Context<Workspace>,
15941    ) {
15942        if locations.is_empty() {
15943            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15944            return;
15945        }
15946
15947        // If there are multiple definitions, open them in a multibuffer
15948        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15949        let mut locations = locations.into_iter().peekable();
15950        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15951        let capability = workspace.project().read(cx).capability();
15952
15953        let excerpt_buffer = cx.new(|cx| {
15954            let mut multibuffer = MultiBuffer::new(capability);
15955            while let Some(location) = locations.next() {
15956                let buffer = location.buffer.read(cx);
15957                let mut ranges_for_buffer = Vec::new();
15958                let range = location.range.to_point(buffer);
15959                ranges_for_buffer.push(range.clone());
15960
15961                while let Some(next_location) = locations.peek() {
15962                    if next_location.buffer == location.buffer {
15963                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15964                        locations.next();
15965                    } else {
15966                        break;
15967                    }
15968                }
15969
15970                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15971                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15972                    PathKey::for_buffer(&location.buffer, cx),
15973                    location.buffer.clone(),
15974                    ranges_for_buffer,
15975                    DEFAULT_MULTIBUFFER_CONTEXT,
15976                    cx,
15977                );
15978                ranges.extend(new_ranges)
15979            }
15980
15981            multibuffer.with_title(title)
15982        });
15983
15984        let editor = cx.new(|cx| {
15985            Editor::for_multibuffer(
15986                excerpt_buffer,
15987                Some(workspace.project().clone()),
15988                window,
15989                cx,
15990            )
15991        });
15992        editor.update(cx, |editor, cx| {
15993            match multibuffer_selection_mode {
15994                MultibufferSelectionMode::First => {
15995                    if let Some(first_range) = ranges.first() {
15996                        editor.change_selections(
15997                            SelectionEffects::no_scroll(),
15998                            window,
15999                            cx,
16000                            |selections| {
16001                                selections.clear_disjoint();
16002                                selections
16003                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16004                            },
16005                        );
16006                    }
16007                    editor.highlight_background::<Self>(
16008                        &ranges,
16009                        |theme| theme.colors().editor_highlighted_line_background,
16010                        cx,
16011                    );
16012                }
16013                MultibufferSelectionMode::All => {
16014                    editor.change_selections(
16015                        SelectionEffects::no_scroll(),
16016                        window,
16017                        cx,
16018                        |selections| {
16019                            selections.clear_disjoint();
16020                            selections.select_anchor_ranges(ranges);
16021                        },
16022                    );
16023                }
16024            }
16025            editor.register_buffers_with_language_servers(cx);
16026        });
16027
16028        let item = Box::new(editor);
16029        let item_id = item.item_id();
16030
16031        if split {
16032            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16033        } else {
16034            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16035                let (preview_item_id, preview_item_idx) =
16036                    workspace.active_pane().read_with(cx, |pane, _| {
16037                        (pane.preview_item_id(), pane.preview_item_idx())
16038                    });
16039
16040                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16041
16042                if let Some(preview_item_id) = preview_item_id {
16043                    workspace.active_pane().update(cx, |pane, cx| {
16044                        pane.remove_item(preview_item_id, false, false, window, cx);
16045                    });
16046                }
16047            } else {
16048                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16049            }
16050        }
16051        workspace.active_pane().update(cx, |pane, cx| {
16052            pane.set_preview_item_id(Some(item_id), cx);
16053        });
16054    }
16055
16056    pub fn rename(
16057        &mut self,
16058        _: &Rename,
16059        window: &mut Window,
16060        cx: &mut Context<Self>,
16061    ) -> Option<Task<Result<()>>> {
16062        use language::ToOffset as _;
16063
16064        let provider = self.semantics_provider.clone()?;
16065        let selection = self.selections.newest_anchor().clone();
16066        let (cursor_buffer, cursor_buffer_position) = self
16067            .buffer
16068            .read(cx)
16069            .text_anchor_for_position(selection.head(), cx)?;
16070        let (tail_buffer, cursor_buffer_position_end) = self
16071            .buffer
16072            .read(cx)
16073            .text_anchor_for_position(selection.tail(), cx)?;
16074        if tail_buffer != cursor_buffer {
16075            return None;
16076        }
16077
16078        let snapshot = cursor_buffer.read(cx).snapshot();
16079        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16080        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16081        let prepare_rename = provider
16082            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16083            .unwrap_or_else(|| Task::ready(Ok(None)));
16084        drop(snapshot);
16085
16086        Some(cx.spawn_in(window, async move |this, cx| {
16087            let rename_range = if let Some(range) = prepare_rename.await? {
16088                Some(range)
16089            } else {
16090                this.update(cx, |this, cx| {
16091                    let buffer = this.buffer.read(cx).snapshot(cx);
16092                    let mut buffer_highlights = this
16093                        .document_highlights_for_position(selection.head(), &buffer)
16094                        .filter(|highlight| {
16095                            highlight.start.excerpt_id == selection.head().excerpt_id
16096                                && highlight.end.excerpt_id == selection.head().excerpt_id
16097                        });
16098                    buffer_highlights
16099                        .next()
16100                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16101                })?
16102            };
16103            if let Some(rename_range) = rename_range {
16104                this.update_in(cx, |this, window, cx| {
16105                    let snapshot = cursor_buffer.read(cx).snapshot();
16106                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16107                    let cursor_offset_in_rename_range =
16108                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16109                    let cursor_offset_in_rename_range_end =
16110                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16111
16112                    this.take_rename(false, window, cx);
16113                    let buffer = this.buffer.read(cx).read(cx);
16114                    let cursor_offset = selection.head().to_offset(&buffer);
16115                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16116                    let rename_end = rename_start + rename_buffer_range.len();
16117                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16118                    let mut old_highlight_id = None;
16119                    let old_name: Arc<str> = buffer
16120                        .chunks(rename_start..rename_end, true)
16121                        .map(|chunk| {
16122                            if old_highlight_id.is_none() {
16123                                old_highlight_id = chunk.syntax_highlight_id;
16124                            }
16125                            chunk.text
16126                        })
16127                        .collect::<String>()
16128                        .into();
16129
16130                    drop(buffer);
16131
16132                    // Position the selection in the rename editor so that it matches the current selection.
16133                    this.show_local_selections = false;
16134                    let rename_editor = cx.new(|cx| {
16135                        let mut editor = Editor::single_line(window, cx);
16136                        editor.buffer.update(cx, |buffer, cx| {
16137                            buffer.edit([(0..0, old_name.clone())], None, cx)
16138                        });
16139                        let rename_selection_range = match cursor_offset_in_rename_range
16140                            .cmp(&cursor_offset_in_rename_range_end)
16141                        {
16142                            Ordering::Equal => {
16143                                editor.select_all(&SelectAll, window, cx);
16144                                return editor;
16145                            }
16146                            Ordering::Less => {
16147                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16148                            }
16149                            Ordering::Greater => {
16150                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16151                            }
16152                        };
16153                        if rename_selection_range.end > old_name.len() {
16154                            editor.select_all(&SelectAll, window, cx);
16155                        } else {
16156                            editor.change_selections(Default::default(), window, cx, |s| {
16157                                s.select_ranges([rename_selection_range]);
16158                            });
16159                        }
16160                        editor
16161                    });
16162                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16163                        if e == &EditorEvent::Focused {
16164                            cx.emit(EditorEvent::FocusedIn)
16165                        }
16166                    })
16167                    .detach();
16168
16169                    let write_highlights =
16170                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16171                    let read_highlights =
16172                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16173                    let ranges = write_highlights
16174                        .iter()
16175                        .flat_map(|(_, ranges)| ranges.iter())
16176                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16177                        .cloned()
16178                        .collect();
16179
16180                    this.highlight_text::<Rename>(
16181                        ranges,
16182                        HighlightStyle {
16183                            fade_out: Some(0.6),
16184                            ..Default::default()
16185                        },
16186                        cx,
16187                    );
16188                    let rename_focus_handle = rename_editor.focus_handle(cx);
16189                    window.focus(&rename_focus_handle);
16190                    let block_id = this.insert_blocks(
16191                        [BlockProperties {
16192                            style: BlockStyle::Flex,
16193                            placement: BlockPlacement::Below(range.start),
16194                            height: Some(1),
16195                            render: Arc::new({
16196                                let rename_editor = rename_editor.clone();
16197                                move |cx: &mut BlockContext| {
16198                                    let mut text_style = cx.editor_style.text.clone();
16199                                    if let Some(highlight_style) = old_highlight_id
16200                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16201                                    {
16202                                        text_style = text_style.highlight(highlight_style);
16203                                    }
16204                                    div()
16205                                        .block_mouse_except_scroll()
16206                                        .pl(cx.anchor_x)
16207                                        .child(EditorElement::new(
16208                                            &rename_editor,
16209                                            EditorStyle {
16210                                                background: cx.theme().system().transparent,
16211                                                local_player: cx.editor_style.local_player,
16212                                                text: text_style,
16213                                                scrollbar_width: cx.editor_style.scrollbar_width,
16214                                                syntax: cx.editor_style.syntax.clone(),
16215                                                status: cx.editor_style.status.clone(),
16216                                                inlay_hints_style: HighlightStyle {
16217                                                    font_weight: Some(FontWeight::BOLD),
16218                                                    ..make_inlay_hints_style(cx.app)
16219                                                },
16220                                                inline_completion_styles: make_suggestion_styles(
16221                                                    cx.app,
16222                                                ),
16223                                                ..EditorStyle::default()
16224                                            },
16225                                        ))
16226                                        .into_any_element()
16227                                }
16228                            }),
16229                            priority: 0,
16230                        }],
16231                        Some(Autoscroll::fit()),
16232                        cx,
16233                    )[0];
16234                    this.pending_rename = Some(RenameState {
16235                        range,
16236                        old_name,
16237                        editor: rename_editor,
16238                        block_id,
16239                    });
16240                })?;
16241            }
16242
16243            Ok(())
16244        }))
16245    }
16246
16247    pub fn confirm_rename(
16248        &mut self,
16249        _: &ConfirmRename,
16250        window: &mut Window,
16251        cx: &mut Context<Self>,
16252    ) -> Option<Task<Result<()>>> {
16253        let rename = self.take_rename(false, window, cx)?;
16254        let workspace = self.workspace()?.downgrade();
16255        let (buffer, start) = self
16256            .buffer
16257            .read(cx)
16258            .text_anchor_for_position(rename.range.start, cx)?;
16259        let (end_buffer, _) = self
16260            .buffer
16261            .read(cx)
16262            .text_anchor_for_position(rename.range.end, cx)?;
16263        if buffer != end_buffer {
16264            return None;
16265        }
16266
16267        let old_name = rename.old_name;
16268        let new_name = rename.editor.read(cx).text(cx);
16269
16270        let rename = self.semantics_provider.as_ref()?.perform_rename(
16271            &buffer,
16272            start,
16273            new_name.clone(),
16274            cx,
16275        )?;
16276
16277        Some(cx.spawn_in(window, async move |editor, cx| {
16278            let project_transaction = rename.await?;
16279            Self::open_project_transaction(
16280                &editor,
16281                workspace,
16282                project_transaction,
16283                format!("Rename: {}{}", old_name, new_name),
16284                cx,
16285            )
16286            .await?;
16287
16288            editor.update(cx, |editor, cx| {
16289                editor.refresh_document_highlights(cx);
16290            })?;
16291            Ok(())
16292        }))
16293    }
16294
16295    fn take_rename(
16296        &mut self,
16297        moving_cursor: bool,
16298        window: &mut Window,
16299        cx: &mut Context<Self>,
16300    ) -> Option<RenameState> {
16301        let rename = self.pending_rename.take()?;
16302        if rename.editor.focus_handle(cx).is_focused(window) {
16303            window.focus(&self.focus_handle);
16304        }
16305
16306        self.remove_blocks(
16307            [rename.block_id].into_iter().collect(),
16308            Some(Autoscroll::fit()),
16309            cx,
16310        );
16311        self.clear_highlights::<Rename>(cx);
16312        self.show_local_selections = true;
16313
16314        if moving_cursor {
16315            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16316                editor.selections.newest::<usize>(cx).head()
16317            });
16318
16319            // Update the selection to match the position of the selection inside
16320            // the rename editor.
16321            let snapshot = self.buffer.read(cx).read(cx);
16322            let rename_range = rename.range.to_offset(&snapshot);
16323            let cursor_in_editor = snapshot
16324                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16325                .min(rename_range.end);
16326            drop(snapshot);
16327
16328            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16329                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16330            });
16331        } else {
16332            self.refresh_document_highlights(cx);
16333        }
16334
16335        Some(rename)
16336    }
16337
16338    pub fn pending_rename(&self) -> Option<&RenameState> {
16339        self.pending_rename.as_ref()
16340    }
16341
16342    fn format(
16343        &mut self,
16344        _: &Format,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) -> Option<Task<Result<()>>> {
16348        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16349
16350        let project = match &self.project {
16351            Some(project) => project.clone(),
16352            None => return None,
16353        };
16354
16355        Some(self.perform_format(
16356            project,
16357            FormatTrigger::Manual,
16358            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16359            window,
16360            cx,
16361        ))
16362    }
16363
16364    fn format_selections(
16365        &mut self,
16366        _: &FormatSelections,
16367        window: &mut Window,
16368        cx: &mut Context<Self>,
16369    ) -> Option<Task<Result<()>>> {
16370        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16371
16372        let project = match &self.project {
16373            Some(project) => project.clone(),
16374            None => return None,
16375        };
16376
16377        let ranges = self
16378            .selections
16379            .all_adjusted(cx)
16380            .into_iter()
16381            .map(|selection| selection.range())
16382            .collect_vec();
16383
16384        Some(self.perform_format(
16385            project,
16386            FormatTrigger::Manual,
16387            FormatTarget::Ranges(ranges),
16388            window,
16389            cx,
16390        ))
16391    }
16392
16393    fn perform_format(
16394        &mut self,
16395        project: Entity<Project>,
16396        trigger: FormatTrigger,
16397        target: FormatTarget,
16398        window: &mut Window,
16399        cx: &mut Context<Self>,
16400    ) -> Task<Result<()>> {
16401        let buffer = self.buffer.clone();
16402        let (buffers, target) = match target {
16403            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16404            FormatTarget::Ranges(selection_ranges) => {
16405                let multi_buffer = buffer.read(cx);
16406                let snapshot = multi_buffer.read(cx);
16407                let mut buffers = HashSet::default();
16408                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16409                    BTreeMap::new();
16410                for selection_range in selection_ranges {
16411                    for (buffer, buffer_range, _) in
16412                        snapshot.range_to_buffer_ranges(selection_range)
16413                    {
16414                        let buffer_id = buffer.remote_id();
16415                        let start = buffer.anchor_before(buffer_range.start);
16416                        let end = buffer.anchor_after(buffer_range.end);
16417                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16418                        buffer_id_to_ranges
16419                            .entry(buffer_id)
16420                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16421                            .or_insert_with(|| vec![start..end]);
16422                    }
16423                }
16424                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16425            }
16426        };
16427
16428        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16429        let selections_prev = transaction_id_prev
16430            .and_then(|transaction_id_prev| {
16431                // default to selections as they were after the last edit, if we have them,
16432                // instead of how they are now.
16433                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16434                // will take you back to where you made the last edit, instead of staying where you scrolled
16435                self.selection_history
16436                    .transaction(transaction_id_prev)
16437                    .map(|t| t.0.clone())
16438            })
16439            .unwrap_or_else(|| {
16440                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16441                self.selections.disjoint_anchors()
16442            });
16443
16444        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16445        let format = project.update(cx, |project, cx| {
16446            project.format(buffers, target, true, trigger, cx)
16447        });
16448
16449        cx.spawn_in(window, async move |editor, cx| {
16450            let transaction = futures::select_biased! {
16451                transaction = format.log_err().fuse() => transaction,
16452                () = timeout => {
16453                    log::warn!("timed out waiting for formatting");
16454                    None
16455                }
16456            };
16457
16458            buffer
16459                .update(cx, |buffer, cx| {
16460                    if let Some(transaction) = transaction {
16461                        if !buffer.is_singleton() {
16462                            buffer.push_transaction(&transaction.0, cx);
16463                        }
16464                    }
16465                    cx.notify();
16466                })
16467                .ok();
16468
16469            if let Some(transaction_id_now) =
16470                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16471            {
16472                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16473                if has_new_transaction {
16474                    _ = editor.update(cx, |editor, _| {
16475                        editor
16476                            .selection_history
16477                            .insert_transaction(transaction_id_now, selections_prev);
16478                    });
16479                }
16480            }
16481
16482            Ok(())
16483        })
16484    }
16485
16486    fn organize_imports(
16487        &mut self,
16488        _: &OrganizeImports,
16489        window: &mut Window,
16490        cx: &mut Context<Self>,
16491    ) -> Option<Task<Result<()>>> {
16492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16493        let project = match &self.project {
16494            Some(project) => project.clone(),
16495            None => return None,
16496        };
16497        Some(self.perform_code_action_kind(
16498            project,
16499            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16500            window,
16501            cx,
16502        ))
16503    }
16504
16505    fn perform_code_action_kind(
16506        &mut self,
16507        project: Entity<Project>,
16508        kind: CodeActionKind,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) -> Task<Result<()>> {
16512        let buffer = self.buffer.clone();
16513        let buffers = buffer.read(cx).all_buffers();
16514        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16515        let apply_action = project.update(cx, |project, cx| {
16516            project.apply_code_action_kind(buffers, kind, true, cx)
16517        });
16518        cx.spawn_in(window, async move |_, cx| {
16519            let transaction = futures::select_biased! {
16520                () = timeout => {
16521                    log::warn!("timed out waiting for executing code action");
16522                    None
16523                }
16524                transaction = apply_action.log_err().fuse() => transaction,
16525            };
16526            buffer
16527                .update(cx, |buffer, cx| {
16528                    // check if we need this
16529                    if let Some(transaction) = transaction {
16530                        if !buffer.is_singleton() {
16531                            buffer.push_transaction(&transaction.0, cx);
16532                        }
16533                    }
16534                    cx.notify();
16535                })
16536                .ok();
16537            Ok(())
16538        })
16539    }
16540
16541    pub fn restart_language_server(
16542        &mut self,
16543        _: &RestartLanguageServer,
16544        _: &mut Window,
16545        cx: &mut Context<Self>,
16546    ) {
16547        if let Some(project) = self.project.clone() {
16548            self.buffer.update(cx, |multi_buffer, cx| {
16549                project.update(cx, |project, cx| {
16550                    project.restart_language_servers_for_buffers(
16551                        multi_buffer.all_buffers().into_iter().collect(),
16552                        HashSet::default(),
16553                        cx,
16554                    );
16555                });
16556            })
16557        }
16558    }
16559
16560    pub fn stop_language_server(
16561        &mut self,
16562        _: &StopLanguageServer,
16563        _: &mut Window,
16564        cx: &mut Context<Self>,
16565    ) {
16566        if let Some(project) = self.project.clone() {
16567            self.buffer.update(cx, |multi_buffer, cx| {
16568                project.update(cx, |project, cx| {
16569                    project.stop_language_servers_for_buffers(
16570                        multi_buffer.all_buffers().into_iter().collect(),
16571                        HashSet::default(),
16572                        cx,
16573                    );
16574                    cx.emit(project::Event::RefreshInlayHints);
16575                });
16576            });
16577        }
16578    }
16579
16580    fn cancel_language_server_work(
16581        workspace: &mut Workspace,
16582        _: &actions::CancelLanguageServerWork,
16583        _: &mut Window,
16584        cx: &mut Context<Workspace>,
16585    ) {
16586        let project = workspace.project();
16587        let buffers = workspace
16588            .active_item(cx)
16589            .and_then(|item| item.act_as::<Editor>(cx))
16590            .map_or(HashSet::default(), |editor| {
16591                editor.read(cx).buffer.read(cx).all_buffers()
16592            });
16593        project.update(cx, |project, cx| {
16594            project.cancel_language_server_work_for_buffers(buffers, cx);
16595        });
16596    }
16597
16598    fn show_character_palette(
16599        &mut self,
16600        _: &ShowCharacterPalette,
16601        window: &mut Window,
16602        _: &mut Context<Self>,
16603    ) {
16604        window.show_character_palette();
16605    }
16606
16607    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16608        if !self.diagnostics_enabled() {
16609            return;
16610        }
16611
16612        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16613            let buffer = self.buffer.read(cx).snapshot(cx);
16614            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16615            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16616            let is_valid = buffer
16617                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16618                .any(|entry| {
16619                    entry.diagnostic.is_primary
16620                        && !entry.range.is_empty()
16621                        && entry.range.start == primary_range_start
16622                        && entry.diagnostic.message == active_diagnostics.active_message
16623                });
16624
16625            if !is_valid {
16626                self.dismiss_diagnostics(cx);
16627            }
16628        }
16629    }
16630
16631    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16632        match &self.active_diagnostics {
16633            ActiveDiagnostic::Group(group) => Some(group),
16634            _ => None,
16635        }
16636    }
16637
16638    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16639        if !self.diagnostics_enabled() {
16640            return;
16641        }
16642        self.dismiss_diagnostics(cx);
16643        self.active_diagnostics = ActiveDiagnostic::All;
16644    }
16645
16646    fn activate_diagnostics(
16647        &mut self,
16648        buffer_id: BufferId,
16649        diagnostic: DiagnosticEntry<usize>,
16650        window: &mut Window,
16651        cx: &mut Context<Self>,
16652    ) {
16653        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16654            return;
16655        }
16656        self.dismiss_diagnostics(cx);
16657        let snapshot = self.snapshot(window, cx);
16658        let buffer = self.buffer.read(cx).snapshot(cx);
16659        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16660            return;
16661        };
16662
16663        let diagnostic_group = buffer
16664            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16665            .collect::<Vec<_>>();
16666
16667        let blocks =
16668            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16669
16670        let blocks = self.display_map.update(cx, |display_map, cx| {
16671            display_map.insert_blocks(blocks, cx).into_iter().collect()
16672        });
16673        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16674            active_range: buffer.anchor_before(diagnostic.range.start)
16675                ..buffer.anchor_after(diagnostic.range.end),
16676            active_message: diagnostic.diagnostic.message.clone(),
16677            group_id: diagnostic.diagnostic.group_id,
16678            blocks,
16679        });
16680        cx.notify();
16681    }
16682
16683    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16684        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16685            return;
16686        };
16687
16688        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16689        if let ActiveDiagnostic::Group(group) = prev {
16690            self.display_map.update(cx, |display_map, cx| {
16691                display_map.remove_blocks(group.blocks, cx);
16692            });
16693            cx.notify();
16694        }
16695    }
16696
16697    /// Disable inline diagnostics rendering for this editor.
16698    pub fn disable_inline_diagnostics(&mut self) {
16699        self.inline_diagnostics_enabled = false;
16700        self.inline_diagnostics_update = Task::ready(());
16701        self.inline_diagnostics.clear();
16702    }
16703
16704    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16705        self.diagnostics_enabled = false;
16706        self.dismiss_diagnostics(cx);
16707        self.inline_diagnostics_update = Task::ready(());
16708        self.inline_diagnostics.clear();
16709    }
16710
16711    pub fn diagnostics_enabled(&self) -> bool {
16712        self.diagnostics_enabled && self.mode.is_full()
16713    }
16714
16715    pub fn inline_diagnostics_enabled(&self) -> bool {
16716        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16717    }
16718
16719    pub fn show_inline_diagnostics(&self) -> bool {
16720        self.show_inline_diagnostics
16721    }
16722
16723    pub fn toggle_inline_diagnostics(
16724        &mut self,
16725        _: &ToggleInlineDiagnostics,
16726        window: &mut Window,
16727        cx: &mut Context<Editor>,
16728    ) {
16729        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16730        self.refresh_inline_diagnostics(false, window, cx);
16731    }
16732
16733    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16734        self.diagnostics_max_severity = severity;
16735        self.display_map.update(cx, |display_map, _| {
16736            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16737        });
16738    }
16739
16740    pub fn toggle_diagnostics(
16741        &mut self,
16742        _: &ToggleDiagnostics,
16743        window: &mut Window,
16744        cx: &mut Context<Editor>,
16745    ) {
16746        if !self.diagnostics_enabled() {
16747            return;
16748        }
16749
16750        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16751            EditorSettings::get_global(cx)
16752                .diagnostics_max_severity
16753                .filter(|severity| severity != &DiagnosticSeverity::Off)
16754                .unwrap_or(DiagnosticSeverity::Hint)
16755        } else {
16756            DiagnosticSeverity::Off
16757        };
16758        self.set_max_diagnostics_severity(new_severity, cx);
16759        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16760            self.active_diagnostics = ActiveDiagnostic::None;
16761            self.inline_diagnostics_update = Task::ready(());
16762            self.inline_diagnostics.clear();
16763        } else {
16764            self.refresh_inline_diagnostics(false, window, cx);
16765        }
16766
16767        cx.notify();
16768    }
16769
16770    pub fn toggle_minimap(
16771        &mut self,
16772        _: &ToggleMinimap,
16773        window: &mut Window,
16774        cx: &mut Context<Editor>,
16775    ) {
16776        if self.supports_minimap(cx) {
16777            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16778        }
16779    }
16780
16781    fn refresh_inline_diagnostics(
16782        &mut self,
16783        debounce: bool,
16784        window: &mut Window,
16785        cx: &mut Context<Self>,
16786    ) {
16787        let max_severity = ProjectSettings::get_global(cx)
16788            .diagnostics
16789            .inline
16790            .max_severity
16791            .unwrap_or(self.diagnostics_max_severity);
16792
16793        if !self.inline_diagnostics_enabled()
16794            || !self.show_inline_diagnostics
16795            || max_severity == DiagnosticSeverity::Off
16796        {
16797            self.inline_diagnostics_update = Task::ready(());
16798            self.inline_diagnostics.clear();
16799            return;
16800        }
16801
16802        let debounce_ms = ProjectSettings::get_global(cx)
16803            .diagnostics
16804            .inline
16805            .update_debounce_ms;
16806        let debounce = if debounce && debounce_ms > 0 {
16807            Some(Duration::from_millis(debounce_ms))
16808        } else {
16809            None
16810        };
16811        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16812            if let Some(debounce) = debounce {
16813                cx.background_executor().timer(debounce).await;
16814            }
16815            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16816                editor
16817                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16818                    .ok()
16819            }) else {
16820                return;
16821            };
16822
16823            let new_inline_diagnostics = cx
16824                .background_spawn(async move {
16825                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16826                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16827                        let message = diagnostic_entry
16828                            .diagnostic
16829                            .message
16830                            .split_once('\n')
16831                            .map(|(line, _)| line)
16832                            .map(SharedString::new)
16833                            .unwrap_or_else(|| {
16834                                SharedString::from(diagnostic_entry.diagnostic.message)
16835                            });
16836                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16837                        let (Ok(i) | Err(i)) = inline_diagnostics
16838                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16839                        inline_diagnostics.insert(
16840                            i,
16841                            (
16842                                start_anchor,
16843                                InlineDiagnostic {
16844                                    message,
16845                                    group_id: diagnostic_entry.diagnostic.group_id,
16846                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16847                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16848                                    severity: diagnostic_entry.diagnostic.severity,
16849                                },
16850                            ),
16851                        );
16852                    }
16853                    inline_diagnostics
16854                })
16855                .await;
16856
16857            editor
16858                .update(cx, |editor, cx| {
16859                    editor.inline_diagnostics = new_inline_diagnostics;
16860                    cx.notify();
16861                })
16862                .ok();
16863        });
16864    }
16865
16866    fn pull_diagnostics(
16867        &mut self,
16868        buffer_id: Option<BufferId>,
16869        window: &Window,
16870        cx: &mut Context<Self>,
16871    ) -> Option<()> {
16872        if !self.mode().is_full() {
16873            return None;
16874        }
16875        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16876            .diagnostics
16877            .lsp_pull_diagnostics;
16878        if !pull_diagnostics_settings.enabled {
16879            return None;
16880        }
16881        let project = self.project.as_ref()?.downgrade();
16882        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16883        let mut buffers = self.buffer.read(cx).all_buffers();
16884        if let Some(buffer_id) = buffer_id {
16885            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16886        }
16887
16888        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16889            cx.background_executor().timer(debounce).await;
16890
16891            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16892                buffers
16893                    .into_iter()
16894                    .filter_map(|buffer| {
16895                        project
16896                            .update(cx, |project, cx| {
16897                                project.lsp_store().update(cx, |lsp_store, cx| {
16898                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16899                                })
16900                            })
16901                            .ok()
16902                    })
16903                    .collect::<FuturesUnordered<_>>()
16904            }) else {
16905                return;
16906            };
16907
16908            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16909                match pull_task {
16910                    Ok(()) => {
16911                        if editor
16912                            .update_in(cx, |editor, window, cx| {
16913                                editor.update_diagnostics_state(window, cx);
16914                            })
16915                            .is_err()
16916                        {
16917                            return;
16918                        }
16919                    }
16920                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16921                }
16922            }
16923        });
16924
16925        Some(())
16926    }
16927
16928    pub fn set_selections_from_remote(
16929        &mut self,
16930        selections: Vec<Selection<Anchor>>,
16931        pending_selection: Option<Selection<Anchor>>,
16932        window: &mut Window,
16933        cx: &mut Context<Self>,
16934    ) {
16935        let old_cursor_position = self.selections.newest_anchor().head();
16936        self.selections.change_with(cx, |s| {
16937            s.select_anchors(selections);
16938            if let Some(pending_selection) = pending_selection {
16939                s.set_pending(pending_selection, SelectMode::Character);
16940            } else {
16941                s.clear_pending();
16942            }
16943        });
16944        self.selections_did_change(
16945            false,
16946            &old_cursor_position,
16947            SelectionEffects::default(),
16948            window,
16949            cx,
16950        );
16951    }
16952
16953    pub fn transact(
16954        &mut self,
16955        window: &mut Window,
16956        cx: &mut Context<Self>,
16957        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16958    ) -> Option<TransactionId> {
16959        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16960            this.start_transaction_at(Instant::now(), window, cx);
16961            update(this, window, cx);
16962            this.end_transaction_at(Instant::now(), cx)
16963        })
16964    }
16965
16966    pub fn start_transaction_at(
16967        &mut self,
16968        now: Instant,
16969        window: &mut Window,
16970        cx: &mut Context<Self>,
16971    ) {
16972        self.end_selection(window, cx);
16973        if let Some(tx_id) = self
16974            .buffer
16975            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16976        {
16977            self.selection_history
16978                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16979            cx.emit(EditorEvent::TransactionBegun {
16980                transaction_id: tx_id,
16981            })
16982        }
16983    }
16984
16985    pub fn end_transaction_at(
16986        &mut self,
16987        now: Instant,
16988        cx: &mut Context<Self>,
16989    ) -> Option<TransactionId> {
16990        if let Some(transaction_id) = self
16991            .buffer
16992            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16993        {
16994            if let Some((_, end_selections)) =
16995                self.selection_history.transaction_mut(transaction_id)
16996            {
16997                *end_selections = Some(self.selections.disjoint_anchors());
16998            } else {
16999                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17000            }
17001
17002            cx.emit(EditorEvent::Edited { transaction_id });
17003            Some(transaction_id)
17004        } else {
17005            None
17006        }
17007    }
17008
17009    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17010        if self.selection_mark_mode {
17011            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17012                s.move_with(|_, sel| {
17013                    sel.collapse_to(sel.head(), SelectionGoal::None);
17014                });
17015            })
17016        }
17017        self.selection_mark_mode = true;
17018        cx.notify();
17019    }
17020
17021    pub fn swap_selection_ends(
17022        &mut self,
17023        _: &actions::SwapSelectionEnds,
17024        window: &mut Window,
17025        cx: &mut Context<Self>,
17026    ) {
17027        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17028            s.move_with(|_, sel| {
17029                if sel.start != sel.end {
17030                    sel.reversed = !sel.reversed
17031                }
17032            });
17033        });
17034        self.request_autoscroll(Autoscroll::newest(), cx);
17035        cx.notify();
17036    }
17037
17038    pub fn toggle_focus(
17039        workspace: &mut Workspace,
17040        _: &actions::ToggleFocus,
17041        window: &mut Window,
17042        cx: &mut Context<Workspace>,
17043    ) {
17044        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17045            return;
17046        };
17047        workspace.activate_item(&item, true, true, window, cx);
17048    }
17049
17050    pub fn toggle_fold(
17051        &mut self,
17052        _: &actions::ToggleFold,
17053        window: &mut Window,
17054        cx: &mut Context<Self>,
17055    ) {
17056        if self.is_singleton(cx) {
17057            let selection = self.selections.newest::<Point>(cx);
17058
17059            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17060            let range = if selection.is_empty() {
17061                let point = selection.head().to_display_point(&display_map);
17062                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17063                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17064                    .to_point(&display_map);
17065                start..end
17066            } else {
17067                selection.range()
17068            };
17069            if display_map.folds_in_range(range).next().is_some() {
17070                self.unfold_lines(&Default::default(), window, cx)
17071            } else {
17072                self.fold(&Default::default(), window, cx)
17073            }
17074        } else {
17075            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17076            let buffer_ids: HashSet<_> = self
17077                .selections
17078                .disjoint_anchor_ranges()
17079                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17080                .collect();
17081
17082            let should_unfold = buffer_ids
17083                .iter()
17084                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17085
17086            for buffer_id in buffer_ids {
17087                if should_unfold {
17088                    self.unfold_buffer(buffer_id, cx);
17089                } else {
17090                    self.fold_buffer(buffer_id, cx);
17091                }
17092            }
17093        }
17094    }
17095
17096    pub fn toggle_fold_recursive(
17097        &mut self,
17098        _: &actions::ToggleFoldRecursive,
17099        window: &mut Window,
17100        cx: &mut Context<Self>,
17101    ) {
17102        let selection = self.selections.newest::<Point>(cx);
17103
17104        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17105        let range = if selection.is_empty() {
17106            let point = selection.head().to_display_point(&display_map);
17107            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17108            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17109                .to_point(&display_map);
17110            start..end
17111        } else {
17112            selection.range()
17113        };
17114        if display_map.folds_in_range(range).next().is_some() {
17115            self.unfold_recursive(&Default::default(), window, cx)
17116        } else {
17117            self.fold_recursive(&Default::default(), window, cx)
17118        }
17119    }
17120
17121    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17122        if self.is_singleton(cx) {
17123            let mut to_fold = Vec::new();
17124            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17125            let selections = self.selections.all_adjusted(cx);
17126
17127            for selection in selections {
17128                let range = selection.range().sorted();
17129                let buffer_start_row = range.start.row;
17130
17131                if range.start.row != range.end.row {
17132                    let mut found = false;
17133                    let mut row = range.start.row;
17134                    while row <= range.end.row {
17135                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17136                        {
17137                            found = true;
17138                            row = crease.range().end.row + 1;
17139                            to_fold.push(crease);
17140                        } else {
17141                            row += 1
17142                        }
17143                    }
17144                    if found {
17145                        continue;
17146                    }
17147                }
17148
17149                for row in (0..=range.start.row).rev() {
17150                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17151                        if crease.range().end.row >= buffer_start_row {
17152                            to_fold.push(crease);
17153                            if row <= range.start.row {
17154                                break;
17155                            }
17156                        }
17157                    }
17158                }
17159            }
17160
17161            self.fold_creases(to_fold, true, window, cx);
17162        } else {
17163            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17164            let buffer_ids = self
17165                .selections
17166                .disjoint_anchor_ranges()
17167                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17168                .collect::<HashSet<_>>();
17169            for buffer_id in buffer_ids {
17170                self.fold_buffer(buffer_id, cx);
17171            }
17172        }
17173    }
17174
17175    pub fn toggle_fold_all(
17176        &mut self,
17177        _: &actions::ToggleFoldAll,
17178        window: &mut Window,
17179        cx: &mut Context<Self>,
17180    ) {
17181        if self.buffer.read(cx).is_singleton() {
17182            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17183            let has_folds = display_map
17184                .folds_in_range(0..display_map.buffer_snapshot.len())
17185                .next()
17186                .is_some();
17187
17188            if has_folds {
17189                self.unfold_all(&actions::UnfoldAll, window, cx);
17190            } else {
17191                self.fold_all(&actions::FoldAll, window, cx);
17192            }
17193        } else {
17194            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17195            let should_unfold = buffer_ids
17196                .iter()
17197                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17198
17199            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17200                editor
17201                    .update_in(cx, |editor, _, cx| {
17202                        for buffer_id in buffer_ids {
17203                            if should_unfold {
17204                                editor.unfold_buffer(buffer_id, cx);
17205                            } else {
17206                                editor.fold_buffer(buffer_id, cx);
17207                            }
17208                        }
17209                    })
17210                    .ok();
17211            });
17212        }
17213    }
17214
17215    fn fold_at_level(
17216        &mut self,
17217        fold_at: &FoldAtLevel,
17218        window: &mut Window,
17219        cx: &mut Context<Self>,
17220    ) {
17221        if !self.buffer.read(cx).is_singleton() {
17222            return;
17223        }
17224
17225        let fold_at_level = fold_at.0;
17226        let snapshot = self.buffer.read(cx).snapshot(cx);
17227        let mut to_fold = Vec::new();
17228        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17229
17230        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17231            while start_row < end_row {
17232                match self
17233                    .snapshot(window, cx)
17234                    .crease_for_buffer_row(MultiBufferRow(start_row))
17235                {
17236                    Some(crease) => {
17237                        let nested_start_row = crease.range().start.row + 1;
17238                        let nested_end_row = crease.range().end.row;
17239
17240                        if current_level < fold_at_level {
17241                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17242                        } else if current_level == fold_at_level {
17243                            to_fold.push(crease);
17244                        }
17245
17246                        start_row = nested_end_row + 1;
17247                    }
17248                    None => start_row += 1,
17249                }
17250            }
17251        }
17252
17253        self.fold_creases(to_fold, true, window, cx);
17254    }
17255
17256    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17257        if self.buffer.read(cx).is_singleton() {
17258            let mut fold_ranges = Vec::new();
17259            let snapshot = self.buffer.read(cx).snapshot(cx);
17260
17261            for row in 0..snapshot.max_row().0 {
17262                if let Some(foldable_range) = self
17263                    .snapshot(window, cx)
17264                    .crease_for_buffer_row(MultiBufferRow(row))
17265                {
17266                    fold_ranges.push(foldable_range);
17267                }
17268            }
17269
17270            self.fold_creases(fold_ranges, true, window, cx);
17271        } else {
17272            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17273                editor
17274                    .update_in(cx, |editor, _, cx| {
17275                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17276                            editor.fold_buffer(buffer_id, cx);
17277                        }
17278                    })
17279                    .ok();
17280            });
17281        }
17282    }
17283
17284    pub fn fold_function_bodies(
17285        &mut self,
17286        _: &actions::FoldFunctionBodies,
17287        window: &mut Window,
17288        cx: &mut Context<Self>,
17289    ) {
17290        let snapshot = self.buffer.read(cx).snapshot(cx);
17291
17292        let ranges = snapshot
17293            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17294            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17295            .collect::<Vec<_>>();
17296
17297        let creases = ranges
17298            .into_iter()
17299            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17300            .collect();
17301
17302        self.fold_creases(creases, true, window, cx);
17303    }
17304
17305    pub fn fold_recursive(
17306        &mut self,
17307        _: &actions::FoldRecursive,
17308        window: &mut Window,
17309        cx: &mut Context<Self>,
17310    ) {
17311        let mut to_fold = Vec::new();
17312        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17313        let selections = self.selections.all_adjusted(cx);
17314
17315        for selection in selections {
17316            let range = selection.range().sorted();
17317            let buffer_start_row = range.start.row;
17318
17319            if range.start.row != range.end.row {
17320                let mut found = false;
17321                for row in range.start.row..=range.end.row {
17322                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17323                        found = true;
17324                        to_fold.push(crease);
17325                    }
17326                }
17327                if found {
17328                    continue;
17329                }
17330            }
17331
17332            for row in (0..=range.start.row).rev() {
17333                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17334                    if crease.range().end.row >= buffer_start_row {
17335                        to_fold.push(crease);
17336                    } else {
17337                        break;
17338                    }
17339                }
17340            }
17341        }
17342
17343        self.fold_creases(to_fold, true, window, cx);
17344    }
17345
17346    pub fn fold_at(
17347        &mut self,
17348        buffer_row: MultiBufferRow,
17349        window: &mut Window,
17350        cx: &mut Context<Self>,
17351    ) {
17352        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17353
17354        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17355            let autoscroll = self
17356                .selections
17357                .all::<Point>(cx)
17358                .iter()
17359                .any(|selection| crease.range().overlaps(&selection.range()));
17360
17361            self.fold_creases(vec![crease], autoscroll, window, cx);
17362        }
17363    }
17364
17365    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17366        if self.is_singleton(cx) {
17367            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17368            let buffer = &display_map.buffer_snapshot;
17369            let selections = self.selections.all::<Point>(cx);
17370            let ranges = selections
17371                .iter()
17372                .map(|s| {
17373                    let range = s.display_range(&display_map).sorted();
17374                    let mut start = range.start.to_point(&display_map);
17375                    let mut end = range.end.to_point(&display_map);
17376                    start.column = 0;
17377                    end.column = buffer.line_len(MultiBufferRow(end.row));
17378                    start..end
17379                })
17380                .collect::<Vec<_>>();
17381
17382            self.unfold_ranges(&ranges, true, true, cx);
17383        } else {
17384            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17385            let buffer_ids = self
17386                .selections
17387                .disjoint_anchor_ranges()
17388                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17389                .collect::<HashSet<_>>();
17390            for buffer_id in buffer_ids {
17391                self.unfold_buffer(buffer_id, cx);
17392            }
17393        }
17394    }
17395
17396    pub fn unfold_recursive(
17397        &mut self,
17398        _: &UnfoldRecursive,
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        let selections = self.selections.all::<Point>(cx);
17404        let ranges = selections
17405            .iter()
17406            .map(|s| {
17407                let mut range = s.display_range(&display_map).sorted();
17408                *range.start.column_mut() = 0;
17409                *range.end.column_mut() = display_map.line_len(range.end.row());
17410                let start = range.start.to_point(&display_map);
17411                let end = range.end.to_point(&display_map);
17412                start..end
17413            })
17414            .collect::<Vec<_>>();
17415
17416        self.unfold_ranges(&ranges, true, true, cx);
17417    }
17418
17419    pub fn unfold_at(
17420        &mut self,
17421        buffer_row: MultiBufferRow,
17422        _window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) {
17425        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17426
17427        let intersection_range = Point::new(buffer_row.0, 0)
17428            ..Point::new(
17429                buffer_row.0,
17430                display_map.buffer_snapshot.line_len(buffer_row),
17431            );
17432
17433        let autoscroll = self
17434            .selections
17435            .all::<Point>(cx)
17436            .iter()
17437            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17438
17439        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17440    }
17441
17442    pub fn unfold_all(
17443        &mut self,
17444        _: &actions::UnfoldAll,
17445        _window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        if self.buffer.read(cx).is_singleton() {
17449            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17450            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17451        } else {
17452            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17453                editor
17454                    .update(cx, |editor, cx| {
17455                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17456                            editor.unfold_buffer(buffer_id, cx);
17457                        }
17458                    })
17459                    .ok();
17460            });
17461        }
17462    }
17463
17464    pub fn fold_selected_ranges(
17465        &mut self,
17466        _: &FoldSelectedRanges,
17467        window: &mut Window,
17468        cx: &mut Context<Self>,
17469    ) {
17470        let selections = self.selections.all_adjusted(cx);
17471        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17472        let ranges = selections
17473            .into_iter()
17474            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17475            .collect::<Vec<_>>();
17476        self.fold_creases(ranges, true, window, cx);
17477    }
17478
17479    pub fn fold_ranges<T: ToOffset + Clone>(
17480        &mut self,
17481        ranges: Vec<Range<T>>,
17482        auto_scroll: bool,
17483        window: &mut Window,
17484        cx: &mut Context<Self>,
17485    ) {
17486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17487        let ranges = ranges
17488            .into_iter()
17489            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17490            .collect::<Vec<_>>();
17491        self.fold_creases(ranges, auto_scroll, window, cx);
17492    }
17493
17494    pub fn fold_creases<T: ToOffset + Clone>(
17495        &mut self,
17496        creases: Vec<Crease<T>>,
17497        auto_scroll: bool,
17498        _window: &mut Window,
17499        cx: &mut Context<Self>,
17500    ) {
17501        if creases.is_empty() {
17502            return;
17503        }
17504
17505        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17506
17507        if auto_scroll {
17508            self.request_autoscroll(Autoscroll::fit(), cx);
17509        }
17510
17511        cx.notify();
17512
17513        self.scrollbar_marker_state.dirty = true;
17514        self.folds_did_change(cx);
17515    }
17516
17517    /// Removes any folds whose ranges intersect any of the given ranges.
17518    pub fn unfold_ranges<T: ToOffset + Clone>(
17519        &mut self,
17520        ranges: &[Range<T>],
17521        inclusive: bool,
17522        auto_scroll: bool,
17523        cx: &mut Context<Self>,
17524    ) {
17525        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17526            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17527        });
17528        self.folds_did_change(cx);
17529    }
17530
17531    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17532        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17533            return;
17534        }
17535        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17536        self.display_map.update(cx, |display_map, cx| {
17537            display_map.fold_buffers([buffer_id], cx)
17538        });
17539        cx.emit(EditorEvent::BufferFoldToggled {
17540            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17541            folded: true,
17542        });
17543        cx.notify();
17544    }
17545
17546    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17547        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17548            return;
17549        }
17550        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17551        self.display_map.update(cx, |display_map, cx| {
17552            display_map.unfold_buffers([buffer_id], cx);
17553        });
17554        cx.emit(EditorEvent::BufferFoldToggled {
17555            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17556            folded: false,
17557        });
17558        cx.notify();
17559    }
17560
17561    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17562        self.display_map.read(cx).is_buffer_folded(buffer)
17563    }
17564
17565    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17566        self.display_map.read(cx).folded_buffers()
17567    }
17568
17569    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17570        self.display_map.update(cx, |display_map, cx| {
17571            display_map.disable_header_for_buffer(buffer_id, cx);
17572        });
17573        cx.notify();
17574    }
17575
17576    /// Removes any folds with the given ranges.
17577    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17578        &mut self,
17579        ranges: &[Range<T>],
17580        type_id: TypeId,
17581        auto_scroll: bool,
17582        cx: &mut Context<Self>,
17583    ) {
17584        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17585            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17586        });
17587        self.folds_did_change(cx);
17588    }
17589
17590    fn remove_folds_with<T: ToOffset + Clone>(
17591        &mut self,
17592        ranges: &[Range<T>],
17593        auto_scroll: bool,
17594        cx: &mut Context<Self>,
17595        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17596    ) {
17597        if ranges.is_empty() {
17598            return;
17599        }
17600
17601        let mut buffers_affected = HashSet::default();
17602        let multi_buffer = self.buffer().read(cx);
17603        for range in ranges {
17604            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17605                buffers_affected.insert(buffer.read(cx).remote_id());
17606            };
17607        }
17608
17609        self.display_map.update(cx, update);
17610
17611        if auto_scroll {
17612            self.request_autoscroll(Autoscroll::fit(), cx);
17613        }
17614
17615        cx.notify();
17616        self.scrollbar_marker_state.dirty = true;
17617        self.active_indent_guides_state.dirty = true;
17618    }
17619
17620    pub fn update_renderer_widths(
17621        &mut self,
17622        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17623        cx: &mut Context<Self>,
17624    ) -> bool {
17625        self.display_map
17626            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17627    }
17628
17629    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17630        self.display_map.read(cx).fold_placeholder.clone()
17631    }
17632
17633    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17634        self.buffer.update(cx, |buffer, cx| {
17635            buffer.set_all_diff_hunks_expanded(cx);
17636        });
17637    }
17638
17639    pub fn expand_all_diff_hunks(
17640        &mut self,
17641        _: &ExpandAllDiffHunks,
17642        _window: &mut Window,
17643        cx: &mut Context<Self>,
17644    ) {
17645        self.buffer.update(cx, |buffer, cx| {
17646            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17647        });
17648    }
17649
17650    pub fn toggle_selected_diff_hunks(
17651        &mut self,
17652        _: &ToggleSelectedDiffHunks,
17653        _window: &mut Window,
17654        cx: &mut Context<Self>,
17655    ) {
17656        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17657        self.toggle_diff_hunks_in_ranges(ranges, cx);
17658    }
17659
17660    pub fn diff_hunks_in_ranges<'a>(
17661        &'a self,
17662        ranges: &'a [Range<Anchor>],
17663        buffer: &'a MultiBufferSnapshot,
17664    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17665        ranges.iter().flat_map(move |range| {
17666            let end_excerpt_id = range.end.excerpt_id;
17667            let range = range.to_point(buffer);
17668            let mut peek_end = range.end;
17669            if range.end.row < buffer.max_row().0 {
17670                peek_end = Point::new(range.end.row + 1, 0);
17671            }
17672            buffer
17673                .diff_hunks_in_range(range.start..peek_end)
17674                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17675        })
17676    }
17677
17678    pub fn has_stageable_diff_hunks_in_ranges(
17679        &self,
17680        ranges: &[Range<Anchor>],
17681        snapshot: &MultiBufferSnapshot,
17682    ) -> bool {
17683        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17684        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17685    }
17686
17687    pub fn toggle_staged_selected_diff_hunks(
17688        &mut self,
17689        _: &::git::ToggleStaged,
17690        _: &mut Window,
17691        cx: &mut Context<Self>,
17692    ) {
17693        let snapshot = self.buffer.read(cx).snapshot(cx);
17694        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17695        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17696        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17697    }
17698
17699    pub fn set_render_diff_hunk_controls(
17700        &mut self,
17701        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17702        cx: &mut Context<Self>,
17703    ) {
17704        self.render_diff_hunk_controls = render_diff_hunk_controls;
17705        cx.notify();
17706    }
17707
17708    pub fn stage_and_next(
17709        &mut self,
17710        _: &::git::StageAndNext,
17711        window: &mut Window,
17712        cx: &mut Context<Self>,
17713    ) {
17714        self.do_stage_or_unstage_and_next(true, window, cx);
17715    }
17716
17717    pub fn unstage_and_next(
17718        &mut self,
17719        _: &::git::UnstageAndNext,
17720        window: &mut Window,
17721        cx: &mut Context<Self>,
17722    ) {
17723        self.do_stage_or_unstage_and_next(false, window, cx);
17724    }
17725
17726    pub fn stage_or_unstage_diff_hunks(
17727        &mut self,
17728        stage: bool,
17729        ranges: Vec<Range<Anchor>>,
17730        cx: &mut Context<Self>,
17731    ) {
17732        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17733        cx.spawn(async move |this, cx| {
17734            task.await?;
17735            this.update(cx, |this, cx| {
17736                let snapshot = this.buffer.read(cx).snapshot(cx);
17737                let chunk_by = this
17738                    .diff_hunks_in_ranges(&ranges, &snapshot)
17739                    .chunk_by(|hunk| hunk.buffer_id);
17740                for (buffer_id, hunks) in &chunk_by {
17741                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17742                }
17743            })
17744        })
17745        .detach_and_log_err(cx);
17746    }
17747
17748    fn save_buffers_for_ranges_if_needed(
17749        &mut self,
17750        ranges: &[Range<Anchor>],
17751        cx: &mut Context<Editor>,
17752    ) -> Task<Result<()>> {
17753        let multibuffer = self.buffer.read(cx);
17754        let snapshot = multibuffer.read(cx);
17755        let buffer_ids: HashSet<_> = ranges
17756            .iter()
17757            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17758            .collect();
17759        drop(snapshot);
17760
17761        let mut buffers = HashSet::default();
17762        for buffer_id in buffer_ids {
17763            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17764                let buffer = buffer_entity.read(cx);
17765                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17766                {
17767                    buffers.insert(buffer_entity);
17768                }
17769            }
17770        }
17771
17772        if let Some(project) = &self.project {
17773            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17774        } else {
17775            Task::ready(Ok(()))
17776        }
17777    }
17778
17779    fn do_stage_or_unstage_and_next(
17780        &mut self,
17781        stage: bool,
17782        window: &mut Window,
17783        cx: &mut Context<Self>,
17784    ) {
17785        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17786
17787        if ranges.iter().any(|range| range.start != range.end) {
17788            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17789            return;
17790        }
17791
17792        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17793        let snapshot = self.snapshot(window, cx);
17794        let position = self.selections.newest::<Point>(cx).head();
17795        let mut row = snapshot
17796            .buffer_snapshot
17797            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17798            .find(|hunk| hunk.row_range.start.0 > position.row)
17799            .map(|hunk| hunk.row_range.start);
17800
17801        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17802        // Outside of the project diff editor, wrap around to the beginning.
17803        if !all_diff_hunks_expanded {
17804            row = row.or_else(|| {
17805                snapshot
17806                    .buffer_snapshot
17807                    .diff_hunks_in_range(Point::zero()..position)
17808                    .find(|hunk| hunk.row_range.end.0 < position.row)
17809                    .map(|hunk| hunk.row_range.start)
17810            });
17811        }
17812
17813        if let Some(row) = row {
17814            let destination = Point::new(row.0, 0);
17815            let autoscroll = Autoscroll::center();
17816
17817            self.unfold_ranges(&[destination..destination], false, false, cx);
17818            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17819                s.select_ranges([destination..destination]);
17820            });
17821        }
17822    }
17823
17824    fn do_stage_or_unstage(
17825        &self,
17826        stage: bool,
17827        buffer_id: BufferId,
17828        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17829        cx: &mut App,
17830    ) -> Option<()> {
17831        let project = self.project.as_ref()?;
17832        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17833        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17834        let buffer_snapshot = buffer.read(cx).snapshot();
17835        let file_exists = buffer_snapshot
17836            .file()
17837            .is_some_and(|file| file.disk_state().exists());
17838        diff.update(cx, |diff, cx| {
17839            diff.stage_or_unstage_hunks(
17840                stage,
17841                &hunks
17842                    .map(|hunk| buffer_diff::DiffHunk {
17843                        buffer_range: hunk.buffer_range,
17844                        diff_base_byte_range: hunk.diff_base_byte_range,
17845                        secondary_status: hunk.secondary_status,
17846                        range: Point::zero()..Point::zero(), // unused
17847                    })
17848                    .collect::<Vec<_>>(),
17849                &buffer_snapshot,
17850                file_exists,
17851                cx,
17852            )
17853        });
17854        None
17855    }
17856
17857    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17858        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17859        self.buffer
17860            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17861    }
17862
17863    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17864        self.buffer.update(cx, |buffer, cx| {
17865            let ranges = vec![Anchor::min()..Anchor::max()];
17866            if !buffer.all_diff_hunks_expanded()
17867                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17868            {
17869                buffer.collapse_diff_hunks(ranges, cx);
17870                true
17871            } else {
17872                false
17873            }
17874        })
17875    }
17876
17877    fn toggle_diff_hunks_in_ranges(
17878        &mut self,
17879        ranges: Vec<Range<Anchor>>,
17880        cx: &mut Context<Editor>,
17881    ) {
17882        self.buffer.update(cx, |buffer, cx| {
17883            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17884            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17885        })
17886    }
17887
17888    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17889        self.buffer.update(cx, |buffer, cx| {
17890            let snapshot = buffer.snapshot(cx);
17891            let excerpt_id = range.end.excerpt_id;
17892            let point_range = range.to_point(&snapshot);
17893            let expand = !buffer.single_hunk_is_expanded(range, cx);
17894            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17895        })
17896    }
17897
17898    pub(crate) fn apply_all_diff_hunks(
17899        &mut self,
17900        _: &ApplyAllDiffHunks,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17905
17906        let buffers = self.buffer.read(cx).all_buffers();
17907        for branch_buffer in buffers {
17908            branch_buffer.update(cx, |branch_buffer, cx| {
17909                branch_buffer.merge_into_base(Vec::new(), cx);
17910            });
17911        }
17912
17913        if let Some(project) = self.project.clone() {
17914            self.save(
17915                SaveOptions {
17916                    format: true,
17917                    autosave: false,
17918                },
17919                project,
17920                window,
17921                cx,
17922            )
17923            .detach_and_log_err(cx);
17924        }
17925    }
17926
17927    pub(crate) fn apply_selected_diff_hunks(
17928        &mut self,
17929        _: &ApplyDiffHunk,
17930        window: &mut Window,
17931        cx: &mut Context<Self>,
17932    ) {
17933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17934        let snapshot = self.snapshot(window, cx);
17935        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17936        let mut ranges_by_buffer = HashMap::default();
17937        self.transact(window, cx, |editor, _window, cx| {
17938            for hunk in hunks {
17939                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17940                    ranges_by_buffer
17941                        .entry(buffer.clone())
17942                        .or_insert_with(Vec::new)
17943                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17944                }
17945            }
17946
17947            for (buffer, ranges) in ranges_by_buffer {
17948                buffer.update(cx, |buffer, cx| {
17949                    buffer.merge_into_base(ranges, cx);
17950                });
17951            }
17952        });
17953
17954        if let Some(project) = self.project.clone() {
17955            self.save(
17956                SaveOptions {
17957                    format: true,
17958                    autosave: false,
17959                },
17960                project,
17961                window,
17962                cx,
17963            )
17964            .detach_and_log_err(cx);
17965        }
17966    }
17967
17968    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17969        if hovered != self.gutter_hovered {
17970            self.gutter_hovered = hovered;
17971            cx.notify();
17972        }
17973    }
17974
17975    pub fn insert_blocks(
17976        &mut self,
17977        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17978        autoscroll: Option<Autoscroll>,
17979        cx: &mut Context<Self>,
17980    ) -> Vec<CustomBlockId> {
17981        let blocks = self
17982            .display_map
17983            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17984        if let Some(autoscroll) = autoscroll {
17985            self.request_autoscroll(autoscroll, cx);
17986        }
17987        cx.notify();
17988        blocks
17989    }
17990
17991    pub fn resize_blocks(
17992        &mut self,
17993        heights: HashMap<CustomBlockId, u32>,
17994        autoscroll: Option<Autoscroll>,
17995        cx: &mut Context<Self>,
17996    ) {
17997        self.display_map
17998            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17999        if let Some(autoscroll) = autoscroll {
18000            self.request_autoscroll(autoscroll, cx);
18001        }
18002        cx.notify();
18003    }
18004
18005    pub fn replace_blocks(
18006        &mut self,
18007        renderers: HashMap<CustomBlockId, RenderBlock>,
18008        autoscroll: Option<Autoscroll>,
18009        cx: &mut Context<Self>,
18010    ) {
18011        self.display_map
18012            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18013        if let Some(autoscroll) = autoscroll {
18014            self.request_autoscroll(autoscroll, cx);
18015        }
18016        cx.notify();
18017    }
18018
18019    pub fn remove_blocks(
18020        &mut self,
18021        block_ids: HashSet<CustomBlockId>,
18022        autoscroll: Option<Autoscroll>,
18023        cx: &mut Context<Self>,
18024    ) {
18025        self.display_map.update(cx, |display_map, cx| {
18026            display_map.remove_blocks(block_ids, cx)
18027        });
18028        if let Some(autoscroll) = autoscroll {
18029            self.request_autoscroll(autoscroll, cx);
18030        }
18031        cx.notify();
18032    }
18033
18034    pub fn row_for_block(
18035        &self,
18036        block_id: CustomBlockId,
18037        cx: &mut Context<Self>,
18038    ) -> Option<DisplayRow> {
18039        self.display_map
18040            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18041    }
18042
18043    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18044        self.focused_block = Some(focused_block);
18045    }
18046
18047    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18048        self.focused_block.take()
18049    }
18050
18051    pub fn insert_creases(
18052        &mut self,
18053        creases: impl IntoIterator<Item = Crease<Anchor>>,
18054        cx: &mut Context<Self>,
18055    ) -> Vec<CreaseId> {
18056        self.display_map
18057            .update(cx, |map, cx| map.insert_creases(creases, cx))
18058    }
18059
18060    pub fn remove_creases(
18061        &mut self,
18062        ids: impl IntoIterator<Item = CreaseId>,
18063        cx: &mut Context<Self>,
18064    ) -> Vec<(CreaseId, Range<Anchor>)> {
18065        self.display_map
18066            .update(cx, |map, cx| map.remove_creases(ids, cx))
18067    }
18068
18069    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18070        self.display_map
18071            .update(cx, |map, cx| map.snapshot(cx))
18072            .longest_row()
18073    }
18074
18075    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18076        self.display_map
18077            .update(cx, |map, cx| map.snapshot(cx))
18078            .max_point()
18079    }
18080
18081    pub fn text(&self, cx: &App) -> String {
18082        self.buffer.read(cx).read(cx).text()
18083    }
18084
18085    pub fn is_empty(&self, cx: &App) -> bool {
18086        self.buffer.read(cx).read(cx).is_empty()
18087    }
18088
18089    pub fn text_option(&self, cx: &App) -> Option<String> {
18090        let text = self.text(cx);
18091        let text = text.trim();
18092
18093        if text.is_empty() {
18094            return None;
18095        }
18096
18097        Some(text.to_string())
18098    }
18099
18100    pub fn set_text(
18101        &mut self,
18102        text: impl Into<Arc<str>>,
18103        window: &mut Window,
18104        cx: &mut Context<Self>,
18105    ) {
18106        self.transact(window, cx, |this, _, cx| {
18107            this.buffer
18108                .read(cx)
18109                .as_singleton()
18110                .expect("you can only call set_text on editors for singleton buffers")
18111                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18112        });
18113    }
18114
18115    pub fn display_text(&self, cx: &mut App) -> String {
18116        self.display_map
18117            .update(cx, |map, cx| map.snapshot(cx))
18118            .text()
18119    }
18120
18121    fn create_minimap(
18122        &self,
18123        minimap_settings: MinimapSettings,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) -> Option<Entity<Self>> {
18127        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18128            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18129    }
18130
18131    fn initialize_new_minimap(
18132        &self,
18133        minimap_settings: MinimapSettings,
18134        window: &mut Window,
18135        cx: &mut Context<Self>,
18136    ) -> Entity<Self> {
18137        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18138
18139        let mut minimap = Editor::new_internal(
18140            EditorMode::Minimap {
18141                parent: cx.weak_entity(),
18142            },
18143            self.buffer.clone(),
18144            None,
18145            Some(self.display_map.clone()),
18146            window,
18147            cx,
18148        );
18149        minimap.scroll_manager.clone_state(&self.scroll_manager);
18150        minimap.set_text_style_refinement(TextStyleRefinement {
18151            font_size: Some(MINIMAP_FONT_SIZE),
18152            font_weight: Some(MINIMAP_FONT_WEIGHT),
18153            ..Default::default()
18154        });
18155        minimap.update_minimap_configuration(minimap_settings, cx);
18156        cx.new(|_| minimap)
18157    }
18158
18159    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18160        let current_line_highlight = minimap_settings
18161            .current_line_highlight
18162            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18163        self.set_current_line_highlight(Some(current_line_highlight));
18164    }
18165
18166    pub fn minimap(&self) -> Option<&Entity<Self>> {
18167        self.minimap
18168            .as_ref()
18169            .filter(|_| self.minimap_visibility.visible())
18170    }
18171
18172    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18173        let mut wrap_guides = smallvec![];
18174
18175        if self.show_wrap_guides == Some(false) {
18176            return wrap_guides;
18177        }
18178
18179        let settings = self.buffer.read(cx).language_settings(cx);
18180        if settings.show_wrap_guides {
18181            match self.soft_wrap_mode(cx) {
18182                SoftWrap::Column(soft_wrap) => {
18183                    wrap_guides.push((soft_wrap as usize, true));
18184                }
18185                SoftWrap::Bounded(soft_wrap) => {
18186                    wrap_guides.push((soft_wrap as usize, true));
18187                }
18188                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18189            }
18190            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18191        }
18192
18193        wrap_guides
18194    }
18195
18196    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18197        let settings = self.buffer.read(cx).language_settings(cx);
18198        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18199        match mode {
18200            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18201                SoftWrap::None
18202            }
18203            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18204            language_settings::SoftWrap::PreferredLineLength => {
18205                SoftWrap::Column(settings.preferred_line_length)
18206            }
18207            language_settings::SoftWrap::Bounded => {
18208                SoftWrap::Bounded(settings.preferred_line_length)
18209            }
18210        }
18211    }
18212
18213    pub fn set_soft_wrap_mode(
18214        &mut self,
18215        mode: language_settings::SoftWrap,
18216
18217        cx: &mut Context<Self>,
18218    ) {
18219        self.soft_wrap_mode_override = Some(mode);
18220        cx.notify();
18221    }
18222
18223    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18224        self.hard_wrap = hard_wrap;
18225        cx.notify();
18226    }
18227
18228    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18229        self.text_style_refinement = Some(style);
18230    }
18231
18232    /// called by the Element so we know what style we were most recently rendered with.
18233    pub(crate) fn set_style(
18234        &mut self,
18235        style: EditorStyle,
18236        window: &mut Window,
18237        cx: &mut Context<Self>,
18238    ) {
18239        // We intentionally do not inform the display map about the minimap style
18240        // so that wrapping is not recalculated and stays consistent for the editor
18241        // and its linked minimap.
18242        if !self.mode.is_minimap() {
18243            let rem_size = window.rem_size();
18244            self.display_map.update(cx, |map, cx| {
18245                map.set_font(
18246                    style.text.font(),
18247                    style.text.font_size.to_pixels(rem_size),
18248                    cx,
18249                )
18250            });
18251        }
18252        self.style = Some(style);
18253    }
18254
18255    pub fn style(&self) -> Option<&EditorStyle> {
18256        self.style.as_ref()
18257    }
18258
18259    // Called by the element. This method is not designed to be called outside of the editor
18260    // element's layout code because it does not notify when rewrapping is computed synchronously.
18261    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18262        self.display_map
18263            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18264    }
18265
18266    pub fn set_soft_wrap(&mut self) {
18267        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18268    }
18269
18270    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18271        if self.soft_wrap_mode_override.is_some() {
18272            self.soft_wrap_mode_override.take();
18273        } else {
18274            let soft_wrap = match self.soft_wrap_mode(cx) {
18275                SoftWrap::GitDiff => return,
18276                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18277                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18278                    language_settings::SoftWrap::None
18279                }
18280            };
18281            self.soft_wrap_mode_override = Some(soft_wrap);
18282        }
18283        cx.notify();
18284    }
18285
18286    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18287        let Some(workspace) = self.workspace() else {
18288            return;
18289        };
18290        let fs = workspace.read(cx).app_state().fs.clone();
18291        let current_show = TabBarSettings::get_global(cx).show;
18292        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18293            setting.show = Some(!current_show);
18294        });
18295    }
18296
18297    pub fn toggle_indent_guides(
18298        &mut self,
18299        _: &ToggleIndentGuides,
18300        _: &mut Window,
18301        cx: &mut Context<Self>,
18302    ) {
18303        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18304            self.buffer
18305                .read(cx)
18306                .language_settings(cx)
18307                .indent_guides
18308                .enabled
18309        });
18310        self.show_indent_guides = Some(!currently_enabled);
18311        cx.notify();
18312    }
18313
18314    fn should_show_indent_guides(&self) -> Option<bool> {
18315        self.show_indent_guides
18316    }
18317
18318    pub fn toggle_line_numbers(
18319        &mut self,
18320        _: &ToggleLineNumbers,
18321        _: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        let mut editor_settings = EditorSettings::get_global(cx).clone();
18325        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18326        EditorSettings::override_global(editor_settings, cx);
18327    }
18328
18329    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18330        if let Some(show_line_numbers) = self.show_line_numbers {
18331            return show_line_numbers;
18332        }
18333        EditorSettings::get_global(cx).gutter.line_numbers
18334    }
18335
18336    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18337        self.use_relative_line_numbers
18338            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18339    }
18340
18341    pub fn toggle_relative_line_numbers(
18342        &mut self,
18343        _: &ToggleRelativeLineNumbers,
18344        _: &mut Window,
18345        cx: &mut Context<Self>,
18346    ) {
18347        let is_relative = self.should_use_relative_line_numbers(cx);
18348        self.set_relative_line_number(Some(!is_relative), cx)
18349    }
18350
18351    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18352        self.use_relative_line_numbers = is_relative;
18353        cx.notify();
18354    }
18355
18356    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18357        self.show_gutter = show_gutter;
18358        cx.notify();
18359    }
18360
18361    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18362        self.show_scrollbars = ScrollbarAxes {
18363            horizontal: show,
18364            vertical: show,
18365        };
18366        cx.notify();
18367    }
18368
18369    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18370        self.show_scrollbars.vertical = show;
18371        cx.notify();
18372    }
18373
18374    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18375        self.show_scrollbars.horizontal = show;
18376        cx.notify();
18377    }
18378
18379    pub fn set_minimap_visibility(
18380        &mut self,
18381        minimap_visibility: MinimapVisibility,
18382        window: &mut Window,
18383        cx: &mut Context<Self>,
18384    ) {
18385        if self.minimap_visibility != minimap_visibility {
18386            if minimap_visibility.visible() && self.minimap.is_none() {
18387                let minimap_settings = EditorSettings::get_global(cx).minimap;
18388                self.minimap =
18389                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18390            }
18391            self.minimap_visibility = minimap_visibility;
18392            cx.notify();
18393        }
18394    }
18395
18396    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18397        self.set_show_scrollbars(false, cx);
18398        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18399    }
18400
18401    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18402        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18403    }
18404
18405    /// Normally the text in full mode and auto height editors is padded on the
18406    /// left side by roughly half a character width for improved hit testing.
18407    ///
18408    /// Use this method to disable this for cases where this is not wanted (e.g.
18409    /// if you want to align the editor text with some other text above or below)
18410    /// or if you want to add this padding to single-line editors.
18411    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18412        self.offset_content = offset_content;
18413        cx.notify();
18414    }
18415
18416    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18417        self.show_line_numbers = Some(show_line_numbers);
18418        cx.notify();
18419    }
18420
18421    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18422        self.disable_expand_excerpt_buttons = true;
18423        cx.notify();
18424    }
18425
18426    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18427        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18428        cx.notify();
18429    }
18430
18431    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18432        self.show_code_actions = Some(show_code_actions);
18433        cx.notify();
18434    }
18435
18436    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18437        self.show_runnables = Some(show_runnables);
18438        cx.notify();
18439    }
18440
18441    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18442        self.show_breakpoints = Some(show_breakpoints);
18443        cx.notify();
18444    }
18445
18446    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18447        if self.display_map.read(cx).masked != masked {
18448            self.display_map.update(cx, |map, _| map.masked = masked);
18449        }
18450        cx.notify()
18451    }
18452
18453    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18454        self.show_wrap_guides = Some(show_wrap_guides);
18455        cx.notify();
18456    }
18457
18458    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18459        self.show_indent_guides = Some(show_indent_guides);
18460        cx.notify();
18461    }
18462
18463    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18464        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18465            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18466                if let Some(dir) = file.abs_path(cx).parent() {
18467                    return Some(dir.to_owned());
18468                }
18469            }
18470
18471            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18472                return Some(project_path.path.to_path_buf());
18473            }
18474        }
18475
18476        None
18477    }
18478
18479    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18480        self.active_excerpt(cx)?
18481            .1
18482            .read(cx)
18483            .file()
18484            .and_then(|f| f.as_local())
18485    }
18486
18487    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18488        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18489            let buffer = buffer.read(cx);
18490            if let Some(project_path) = buffer.project_path(cx) {
18491                let project = self.project.as_ref()?.read(cx);
18492                project.absolute_path(&project_path, cx)
18493            } else {
18494                buffer
18495                    .file()
18496                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18497            }
18498        })
18499    }
18500
18501    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18502        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18503            let project_path = buffer.read(cx).project_path(cx)?;
18504            let project = self.project.as_ref()?.read(cx);
18505            let entry = project.entry_for_path(&project_path, cx)?;
18506            let path = entry.path.to_path_buf();
18507            Some(path)
18508        })
18509    }
18510
18511    pub fn reveal_in_finder(
18512        &mut self,
18513        _: &RevealInFileManager,
18514        _window: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        if let Some(target) = self.target_file(cx) {
18518            cx.reveal_path(&target.abs_path(cx));
18519        }
18520    }
18521
18522    pub fn copy_path(
18523        &mut self,
18524        _: &zed_actions::workspace::CopyPath,
18525        _window: &mut Window,
18526        cx: &mut Context<Self>,
18527    ) {
18528        if let Some(path) = self.target_file_abs_path(cx) {
18529            if let Some(path) = path.to_str() {
18530                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18531            }
18532        }
18533    }
18534
18535    pub fn copy_relative_path(
18536        &mut self,
18537        _: &zed_actions::workspace::CopyRelativePath,
18538        _window: &mut Window,
18539        cx: &mut Context<Self>,
18540    ) {
18541        if let Some(path) = self.target_file_path(cx) {
18542            if let Some(path) = path.to_str() {
18543                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18544            }
18545        }
18546    }
18547
18548    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18549        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18550            buffer.read(cx).project_path(cx)
18551        } else {
18552            None
18553        }
18554    }
18555
18556    // Returns true if the editor handled a go-to-line request
18557    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18558        maybe!({
18559            let breakpoint_store = self.breakpoint_store.as_ref()?;
18560
18561            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18562            else {
18563                self.clear_row_highlights::<ActiveDebugLine>();
18564                return None;
18565            };
18566
18567            let position = active_stack_frame.position;
18568            let buffer_id = position.buffer_id?;
18569            let snapshot = self
18570                .project
18571                .as_ref()?
18572                .read(cx)
18573                .buffer_for_id(buffer_id, cx)?
18574                .read(cx)
18575                .snapshot();
18576
18577            let mut handled = false;
18578            for (id, ExcerptRange { context, .. }) in
18579                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18580            {
18581                if context.start.cmp(&position, &snapshot).is_ge()
18582                    || context.end.cmp(&position, &snapshot).is_lt()
18583                {
18584                    continue;
18585                }
18586                let snapshot = self.buffer.read(cx).snapshot(cx);
18587                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18588
18589                handled = true;
18590                self.clear_row_highlights::<ActiveDebugLine>();
18591
18592                self.go_to_line::<ActiveDebugLine>(
18593                    multibuffer_anchor,
18594                    Some(cx.theme().colors().editor_debugger_active_line_background),
18595                    window,
18596                    cx,
18597                );
18598
18599                cx.notify();
18600            }
18601
18602            handled.then_some(())
18603        })
18604        .is_some()
18605    }
18606
18607    pub fn copy_file_name_without_extension(
18608        &mut self,
18609        _: &CopyFileNameWithoutExtension,
18610        _: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        if let Some(file) = self.target_file(cx) {
18614            if let Some(file_stem) = file.path().file_stem() {
18615                if let Some(name) = file_stem.to_str() {
18616                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18617                }
18618            }
18619        }
18620    }
18621
18622    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18623        if let Some(file) = self.target_file(cx) {
18624            if let Some(file_name) = file.path().file_name() {
18625                if let Some(name) = file_name.to_str() {
18626                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18627                }
18628            }
18629        }
18630    }
18631
18632    pub fn toggle_git_blame(
18633        &mut self,
18634        _: &::git::Blame,
18635        window: &mut Window,
18636        cx: &mut Context<Self>,
18637    ) {
18638        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18639
18640        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18641            self.start_git_blame(true, window, cx);
18642        }
18643
18644        cx.notify();
18645    }
18646
18647    pub fn toggle_git_blame_inline(
18648        &mut self,
18649        _: &ToggleGitBlameInline,
18650        window: &mut Window,
18651        cx: &mut Context<Self>,
18652    ) {
18653        self.toggle_git_blame_inline_internal(true, window, cx);
18654        cx.notify();
18655    }
18656
18657    pub fn open_git_blame_commit(
18658        &mut self,
18659        _: &OpenGitBlameCommit,
18660        window: &mut Window,
18661        cx: &mut Context<Self>,
18662    ) {
18663        self.open_git_blame_commit_internal(window, cx);
18664    }
18665
18666    fn open_git_blame_commit_internal(
18667        &mut self,
18668        window: &mut Window,
18669        cx: &mut Context<Self>,
18670    ) -> Option<()> {
18671        let blame = self.blame.as_ref()?;
18672        let snapshot = self.snapshot(window, cx);
18673        let cursor = self.selections.newest::<Point>(cx).head();
18674        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18675        let blame_entry = blame
18676            .update(cx, |blame, cx| {
18677                blame
18678                    .blame_for_rows(
18679                        &[RowInfo {
18680                            buffer_id: Some(buffer.remote_id()),
18681                            buffer_row: Some(point.row),
18682                            ..Default::default()
18683                        }],
18684                        cx,
18685                    )
18686                    .next()
18687            })
18688            .flatten()?;
18689        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18690        let repo = blame.read(cx).repository(cx)?;
18691        let workspace = self.workspace()?.downgrade();
18692        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18693        None
18694    }
18695
18696    pub fn git_blame_inline_enabled(&self) -> bool {
18697        self.git_blame_inline_enabled
18698    }
18699
18700    pub fn toggle_selection_menu(
18701        &mut self,
18702        _: &ToggleSelectionMenu,
18703        _: &mut Window,
18704        cx: &mut Context<Self>,
18705    ) {
18706        self.show_selection_menu = self
18707            .show_selection_menu
18708            .map(|show_selections_menu| !show_selections_menu)
18709            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18710
18711        cx.notify();
18712    }
18713
18714    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18715        self.show_selection_menu
18716            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18717    }
18718
18719    fn start_git_blame(
18720        &mut self,
18721        user_triggered: bool,
18722        window: &mut Window,
18723        cx: &mut Context<Self>,
18724    ) {
18725        if let Some(project) = self.project.as_ref() {
18726            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18727                return;
18728            };
18729
18730            if buffer.read(cx).file().is_none() {
18731                return;
18732            }
18733
18734            let focused = self.focus_handle(cx).contains_focused(window, cx);
18735
18736            let project = project.clone();
18737            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18738            self.blame_subscription =
18739                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18740            self.blame = Some(blame);
18741        }
18742    }
18743
18744    fn toggle_git_blame_inline_internal(
18745        &mut self,
18746        user_triggered: bool,
18747        window: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        if self.git_blame_inline_enabled {
18751            self.git_blame_inline_enabled = false;
18752            self.show_git_blame_inline = false;
18753            self.show_git_blame_inline_delay_task.take();
18754        } else {
18755            self.git_blame_inline_enabled = true;
18756            self.start_git_blame_inline(user_triggered, window, cx);
18757        }
18758
18759        cx.notify();
18760    }
18761
18762    fn start_git_blame_inline(
18763        &mut self,
18764        user_triggered: bool,
18765        window: &mut Window,
18766        cx: &mut Context<Self>,
18767    ) {
18768        self.start_git_blame(user_triggered, window, cx);
18769
18770        if ProjectSettings::get_global(cx)
18771            .git
18772            .inline_blame_delay()
18773            .is_some()
18774        {
18775            self.start_inline_blame_timer(window, cx);
18776        } else {
18777            self.show_git_blame_inline = true
18778        }
18779    }
18780
18781    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18782        self.blame.as_ref()
18783    }
18784
18785    pub fn show_git_blame_gutter(&self) -> bool {
18786        self.show_git_blame_gutter
18787    }
18788
18789    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18790        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18791    }
18792
18793    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18794        self.show_git_blame_inline
18795            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18796            && !self.newest_selection_head_on_empty_line(cx)
18797            && self.has_blame_entries(cx)
18798    }
18799
18800    fn has_blame_entries(&self, cx: &App) -> bool {
18801        self.blame()
18802            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18803    }
18804
18805    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18806        let cursor_anchor = self.selections.newest_anchor().head();
18807
18808        let snapshot = self.buffer.read(cx).snapshot(cx);
18809        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18810
18811        snapshot.line_len(buffer_row) == 0
18812    }
18813
18814    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18815        let buffer_and_selection = maybe!({
18816            let selection = self.selections.newest::<Point>(cx);
18817            let selection_range = selection.range();
18818
18819            let multi_buffer = self.buffer().read(cx);
18820            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18821            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18822
18823            let (buffer, range, _) = if selection.reversed {
18824                buffer_ranges.first()
18825            } else {
18826                buffer_ranges.last()
18827            }?;
18828
18829            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18830                ..text::ToPoint::to_point(&range.end, &buffer).row;
18831            Some((
18832                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18833                selection,
18834            ))
18835        });
18836
18837        let Some((buffer, selection)) = buffer_and_selection else {
18838            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18839        };
18840
18841        let Some(project) = self.project.as_ref() else {
18842            return Task::ready(Err(anyhow!("editor does not have project")));
18843        };
18844
18845        project.update(cx, |project, cx| {
18846            project.get_permalink_to_line(&buffer, selection, cx)
18847        })
18848    }
18849
18850    pub fn copy_permalink_to_line(
18851        &mut self,
18852        _: &CopyPermalinkToLine,
18853        window: &mut Window,
18854        cx: &mut Context<Self>,
18855    ) {
18856        let permalink_task = self.get_permalink_to_line(cx);
18857        let workspace = self.workspace();
18858
18859        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18860            Ok(permalink) => {
18861                cx.update(|_, cx| {
18862                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18863                })
18864                .ok();
18865            }
18866            Err(err) => {
18867                let message = format!("Failed to copy permalink: {err}");
18868
18869                anyhow::Result::<()>::Err(err).log_err();
18870
18871                if let Some(workspace) = workspace {
18872                    workspace
18873                        .update_in(cx, |workspace, _, cx| {
18874                            struct CopyPermalinkToLine;
18875
18876                            workspace.show_toast(
18877                                Toast::new(
18878                                    NotificationId::unique::<CopyPermalinkToLine>(),
18879                                    message,
18880                                ),
18881                                cx,
18882                            )
18883                        })
18884                        .ok();
18885                }
18886            }
18887        })
18888        .detach();
18889    }
18890
18891    pub fn copy_file_location(
18892        &mut self,
18893        _: &CopyFileLocation,
18894        _: &mut Window,
18895        cx: &mut Context<Self>,
18896    ) {
18897        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18898        if let Some(file) = self.target_file(cx) {
18899            if let Some(path) = file.path().to_str() {
18900                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18901            }
18902        }
18903    }
18904
18905    pub fn open_permalink_to_line(
18906        &mut self,
18907        _: &OpenPermalinkToLine,
18908        window: &mut Window,
18909        cx: &mut Context<Self>,
18910    ) {
18911        let permalink_task = self.get_permalink_to_line(cx);
18912        let workspace = self.workspace();
18913
18914        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18915            Ok(permalink) => {
18916                cx.update(|_, cx| {
18917                    cx.open_url(permalink.as_ref());
18918                })
18919                .ok();
18920            }
18921            Err(err) => {
18922                let message = format!("Failed to open permalink: {err}");
18923
18924                anyhow::Result::<()>::Err(err).log_err();
18925
18926                if let Some(workspace) = workspace {
18927                    workspace
18928                        .update(cx, |workspace, cx| {
18929                            struct OpenPermalinkToLine;
18930
18931                            workspace.show_toast(
18932                                Toast::new(
18933                                    NotificationId::unique::<OpenPermalinkToLine>(),
18934                                    message,
18935                                ),
18936                                cx,
18937                            )
18938                        })
18939                        .ok();
18940                }
18941            }
18942        })
18943        .detach();
18944    }
18945
18946    pub fn insert_uuid_v4(
18947        &mut self,
18948        _: &InsertUuidV4,
18949        window: &mut Window,
18950        cx: &mut Context<Self>,
18951    ) {
18952        self.insert_uuid(UuidVersion::V4, window, cx);
18953    }
18954
18955    pub fn insert_uuid_v7(
18956        &mut self,
18957        _: &InsertUuidV7,
18958        window: &mut Window,
18959        cx: &mut Context<Self>,
18960    ) {
18961        self.insert_uuid(UuidVersion::V7, window, cx);
18962    }
18963
18964    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18965        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18966        self.transact(window, cx, |this, window, cx| {
18967            let edits = this
18968                .selections
18969                .all::<Point>(cx)
18970                .into_iter()
18971                .map(|selection| {
18972                    let uuid = match version {
18973                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18974                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18975                    };
18976
18977                    (selection.range(), uuid.to_string())
18978                });
18979            this.edit(edits, cx);
18980            this.refresh_inline_completion(true, false, window, cx);
18981        });
18982    }
18983
18984    pub fn open_selections_in_multibuffer(
18985        &mut self,
18986        _: &OpenSelectionsInMultibuffer,
18987        window: &mut Window,
18988        cx: &mut Context<Self>,
18989    ) {
18990        let multibuffer = self.buffer.read(cx);
18991
18992        let Some(buffer) = multibuffer.as_singleton() else {
18993            return;
18994        };
18995
18996        let Some(workspace) = self.workspace() else {
18997            return;
18998        };
18999
19000        let title = multibuffer.title(cx).to_string();
19001
19002        let locations = self
19003            .selections
19004            .all_anchors(cx)
19005            .into_iter()
19006            .map(|selection| Location {
19007                buffer: buffer.clone(),
19008                range: selection.start.text_anchor..selection.end.text_anchor,
19009            })
19010            .collect::<Vec<_>>();
19011
19012        cx.spawn_in(window, async move |_, cx| {
19013            workspace.update_in(cx, |workspace, window, cx| {
19014                Self::open_locations_in_multibuffer(
19015                    workspace,
19016                    locations,
19017                    format!("Selections for '{title}'"),
19018                    false,
19019                    MultibufferSelectionMode::All,
19020                    window,
19021                    cx,
19022                );
19023            })
19024        })
19025        .detach();
19026    }
19027
19028    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19029    /// last highlight added will be used.
19030    ///
19031    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19032    pub fn highlight_rows<T: 'static>(
19033        &mut self,
19034        range: Range<Anchor>,
19035        color: Hsla,
19036        options: RowHighlightOptions,
19037        cx: &mut Context<Self>,
19038    ) {
19039        let snapshot = self.buffer().read(cx).snapshot(cx);
19040        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19041        let ix = row_highlights.binary_search_by(|highlight| {
19042            Ordering::Equal
19043                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19044                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19045        });
19046
19047        if let Err(mut ix) = ix {
19048            let index = post_inc(&mut self.highlight_order);
19049
19050            // If this range intersects with the preceding highlight, then merge it with
19051            // the preceding highlight. Otherwise insert a new highlight.
19052            let mut merged = false;
19053            if ix > 0 {
19054                let prev_highlight = &mut row_highlights[ix - 1];
19055                if prev_highlight
19056                    .range
19057                    .end
19058                    .cmp(&range.start, &snapshot)
19059                    .is_ge()
19060                {
19061                    ix -= 1;
19062                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19063                        prev_highlight.range.end = range.end;
19064                    }
19065                    merged = true;
19066                    prev_highlight.index = index;
19067                    prev_highlight.color = color;
19068                    prev_highlight.options = options;
19069                }
19070            }
19071
19072            if !merged {
19073                row_highlights.insert(
19074                    ix,
19075                    RowHighlight {
19076                        range: range.clone(),
19077                        index,
19078                        color,
19079                        options,
19080                        type_id: TypeId::of::<T>(),
19081                    },
19082                );
19083            }
19084
19085            // If any of the following highlights intersect with this one, merge them.
19086            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19087                let highlight = &row_highlights[ix];
19088                if next_highlight
19089                    .range
19090                    .start
19091                    .cmp(&highlight.range.end, &snapshot)
19092                    .is_le()
19093                {
19094                    if next_highlight
19095                        .range
19096                        .end
19097                        .cmp(&highlight.range.end, &snapshot)
19098                        .is_gt()
19099                    {
19100                        row_highlights[ix].range.end = next_highlight.range.end;
19101                    }
19102                    row_highlights.remove(ix + 1);
19103                } else {
19104                    break;
19105                }
19106            }
19107        }
19108    }
19109
19110    /// Remove any highlighted row ranges of the given type that intersect the
19111    /// given ranges.
19112    pub fn remove_highlighted_rows<T: 'static>(
19113        &mut self,
19114        ranges_to_remove: Vec<Range<Anchor>>,
19115        cx: &mut Context<Self>,
19116    ) {
19117        let snapshot = self.buffer().read(cx).snapshot(cx);
19118        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19119        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19120        row_highlights.retain(|highlight| {
19121            while let Some(range_to_remove) = ranges_to_remove.peek() {
19122                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19123                    Ordering::Less | Ordering::Equal => {
19124                        ranges_to_remove.next();
19125                    }
19126                    Ordering::Greater => {
19127                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19128                            Ordering::Less | Ordering::Equal => {
19129                                return false;
19130                            }
19131                            Ordering::Greater => break,
19132                        }
19133                    }
19134                }
19135            }
19136
19137            true
19138        })
19139    }
19140
19141    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19142    pub fn clear_row_highlights<T: 'static>(&mut self) {
19143        self.highlighted_rows.remove(&TypeId::of::<T>());
19144    }
19145
19146    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19147    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19148        self.highlighted_rows
19149            .get(&TypeId::of::<T>())
19150            .map_or(&[] as &[_], |vec| vec.as_slice())
19151            .iter()
19152            .map(|highlight| (highlight.range.clone(), highlight.color))
19153    }
19154
19155    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19156    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19157    /// Allows to ignore certain kinds of highlights.
19158    pub fn highlighted_display_rows(
19159        &self,
19160        window: &mut Window,
19161        cx: &mut App,
19162    ) -> BTreeMap<DisplayRow, LineHighlight> {
19163        let snapshot = self.snapshot(window, cx);
19164        let mut used_highlight_orders = HashMap::default();
19165        self.highlighted_rows
19166            .iter()
19167            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19168            .fold(
19169                BTreeMap::<DisplayRow, LineHighlight>::new(),
19170                |mut unique_rows, highlight| {
19171                    let start = highlight.range.start.to_display_point(&snapshot);
19172                    let end = highlight.range.end.to_display_point(&snapshot);
19173                    let start_row = start.row().0;
19174                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19175                        && end.column() == 0
19176                    {
19177                        end.row().0.saturating_sub(1)
19178                    } else {
19179                        end.row().0
19180                    };
19181                    for row in start_row..=end_row {
19182                        let used_index =
19183                            used_highlight_orders.entry(row).or_insert(highlight.index);
19184                        if highlight.index >= *used_index {
19185                            *used_index = highlight.index;
19186                            unique_rows.insert(
19187                                DisplayRow(row),
19188                                LineHighlight {
19189                                    include_gutter: highlight.options.include_gutter,
19190                                    border: None,
19191                                    background: highlight.color.into(),
19192                                    type_id: Some(highlight.type_id),
19193                                },
19194                            );
19195                        }
19196                    }
19197                    unique_rows
19198                },
19199            )
19200    }
19201
19202    pub fn highlighted_display_row_for_autoscroll(
19203        &self,
19204        snapshot: &DisplaySnapshot,
19205    ) -> Option<DisplayRow> {
19206        self.highlighted_rows
19207            .values()
19208            .flat_map(|highlighted_rows| highlighted_rows.iter())
19209            .filter_map(|highlight| {
19210                if highlight.options.autoscroll {
19211                    Some(highlight.range.start.to_display_point(snapshot).row())
19212                } else {
19213                    None
19214                }
19215            })
19216            .min()
19217    }
19218
19219    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19220        self.highlight_background::<SearchWithinRange>(
19221            ranges,
19222            |colors| colors.colors().editor_document_highlight_read_background,
19223            cx,
19224        )
19225    }
19226
19227    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19228        self.breadcrumb_header = Some(new_header);
19229    }
19230
19231    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19232        self.clear_background_highlights::<SearchWithinRange>(cx);
19233    }
19234
19235    pub fn highlight_background<T: 'static>(
19236        &mut self,
19237        ranges: &[Range<Anchor>],
19238        color_fetcher: fn(&Theme) -> Hsla,
19239        cx: &mut Context<Self>,
19240    ) {
19241        self.background_highlights.insert(
19242            HighlightKey::Type(TypeId::of::<T>()),
19243            (color_fetcher, Arc::from(ranges)),
19244        );
19245        self.scrollbar_marker_state.dirty = true;
19246        cx.notify();
19247    }
19248
19249    pub fn highlight_background_key<T: 'static>(
19250        &mut self,
19251        key: usize,
19252        ranges: &[Range<Anchor>],
19253        color_fetcher: fn(&Theme) -> Hsla,
19254        cx: &mut Context<Self>,
19255    ) {
19256        self.background_highlights.insert(
19257            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19258            (color_fetcher, Arc::from(ranges)),
19259        );
19260        self.scrollbar_marker_state.dirty = true;
19261        cx.notify();
19262    }
19263
19264    pub fn clear_background_highlights<T: 'static>(
19265        &mut self,
19266        cx: &mut Context<Self>,
19267    ) -> Option<BackgroundHighlight> {
19268        let text_highlights = self
19269            .background_highlights
19270            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19271        if !text_highlights.1.is_empty() {
19272            self.scrollbar_marker_state.dirty = true;
19273            cx.notify();
19274        }
19275        Some(text_highlights)
19276    }
19277
19278    pub fn highlight_gutter<T: 'static>(
19279        &mut self,
19280        ranges: impl Into<Vec<Range<Anchor>>>,
19281        color_fetcher: fn(&App) -> Hsla,
19282        cx: &mut Context<Self>,
19283    ) {
19284        self.gutter_highlights
19285            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19286        cx.notify();
19287    }
19288
19289    pub fn clear_gutter_highlights<T: 'static>(
19290        &mut self,
19291        cx: &mut Context<Self>,
19292    ) -> Option<GutterHighlight> {
19293        cx.notify();
19294        self.gutter_highlights.remove(&TypeId::of::<T>())
19295    }
19296
19297    pub fn insert_gutter_highlight<T: 'static>(
19298        &mut self,
19299        range: Range<Anchor>,
19300        color_fetcher: fn(&App) -> Hsla,
19301        cx: &mut Context<Self>,
19302    ) {
19303        let snapshot = self.buffer().read(cx).snapshot(cx);
19304        let mut highlights = self
19305            .gutter_highlights
19306            .remove(&TypeId::of::<T>())
19307            .map(|(_, highlights)| highlights)
19308            .unwrap_or_default();
19309        let ix = highlights.binary_search_by(|highlight| {
19310            Ordering::Equal
19311                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19312                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19313        });
19314        if let Err(ix) = ix {
19315            highlights.insert(ix, range);
19316        }
19317        self.gutter_highlights
19318            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19319    }
19320
19321    pub fn remove_gutter_highlights<T: 'static>(
19322        &mut self,
19323        ranges_to_remove: Vec<Range<Anchor>>,
19324        cx: &mut Context<Self>,
19325    ) {
19326        let snapshot = self.buffer().read(cx).snapshot(cx);
19327        let Some((color_fetcher, mut gutter_highlights)) =
19328            self.gutter_highlights.remove(&TypeId::of::<T>())
19329        else {
19330            return;
19331        };
19332        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19333        gutter_highlights.retain(|highlight| {
19334            while let Some(range_to_remove) = ranges_to_remove.peek() {
19335                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19336                    Ordering::Less | Ordering::Equal => {
19337                        ranges_to_remove.next();
19338                    }
19339                    Ordering::Greater => {
19340                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19341                            Ordering::Less | Ordering::Equal => {
19342                                return false;
19343                            }
19344                            Ordering::Greater => break,
19345                        }
19346                    }
19347                }
19348            }
19349
19350            true
19351        });
19352        self.gutter_highlights
19353            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19354    }
19355
19356    #[cfg(feature = "test-support")]
19357    pub fn all_text_highlights(
19358        &self,
19359        window: &mut Window,
19360        cx: &mut Context<Self>,
19361    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19362        let snapshot = self.snapshot(window, cx);
19363        self.display_map.update(cx, |display_map, _| {
19364            display_map
19365                .all_text_highlights()
19366                .map(|highlight| {
19367                    let (style, ranges) = highlight.as_ref();
19368                    (
19369                        *style,
19370                        ranges
19371                            .iter()
19372                            .map(|range| range.clone().to_display_points(&snapshot))
19373                            .collect(),
19374                    )
19375                })
19376                .collect()
19377        })
19378    }
19379
19380    #[cfg(feature = "test-support")]
19381    pub fn all_text_background_highlights(
19382        &self,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19386        let snapshot = self.snapshot(window, cx);
19387        let buffer = &snapshot.buffer_snapshot;
19388        let start = buffer.anchor_before(0);
19389        let end = buffer.anchor_after(buffer.len());
19390        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19391    }
19392
19393    #[cfg(feature = "test-support")]
19394    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19395        let snapshot = self.buffer().read(cx).snapshot(cx);
19396
19397        let highlights = self
19398            .background_highlights
19399            .get(&HighlightKey::Type(TypeId::of::<
19400                items::BufferSearchHighlights,
19401            >()));
19402
19403        if let Some((_color, ranges)) = highlights {
19404            ranges
19405                .iter()
19406                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19407                .collect_vec()
19408        } else {
19409            vec![]
19410        }
19411    }
19412
19413    fn document_highlights_for_position<'a>(
19414        &'a self,
19415        position: Anchor,
19416        buffer: &'a MultiBufferSnapshot,
19417    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19418        let read_highlights = self
19419            .background_highlights
19420            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19421            .map(|h| &h.1);
19422        let write_highlights = self
19423            .background_highlights
19424            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19425            .map(|h| &h.1);
19426        let left_position = position.bias_left(buffer);
19427        let right_position = position.bias_right(buffer);
19428        read_highlights
19429            .into_iter()
19430            .chain(write_highlights)
19431            .flat_map(move |ranges| {
19432                let start_ix = match ranges.binary_search_by(|probe| {
19433                    let cmp = probe.end.cmp(&left_position, buffer);
19434                    if cmp.is_ge() {
19435                        Ordering::Greater
19436                    } else {
19437                        Ordering::Less
19438                    }
19439                }) {
19440                    Ok(i) | Err(i) => i,
19441                };
19442
19443                ranges[start_ix..]
19444                    .iter()
19445                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19446            })
19447    }
19448
19449    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19450        self.background_highlights
19451            .get(&HighlightKey::Type(TypeId::of::<T>()))
19452            .map_or(false, |(_, highlights)| !highlights.is_empty())
19453    }
19454
19455    pub fn background_highlights_in_range(
19456        &self,
19457        search_range: Range<Anchor>,
19458        display_snapshot: &DisplaySnapshot,
19459        theme: &Theme,
19460    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19461        let mut results = Vec::new();
19462        for (color_fetcher, ranges) in self.background_highlights.values() {
19463            let color = color_fetcher(theme);
19464            let start_ix = match ranges.binary_search_by(|probe| {
19465                let cmp = probe
19466                    .end
19467                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19468                if cmp.is_gt() {
19469                    Ordering::Greater
19470                } else {
19471                    Ordering::Less
19472                }
19473            }) {
19474                Ok(i) | Err(i) => i,
19475            };
19476            for range in &ranges[start_ix..] {
19477                if range
19478                    .start
19479                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19480                    .is_ge()
19481                {
19482                    break;
19483                }
19484
19485                let start = range.start.to_display_point(display_snapshot);
19486                let end = range.end.to_display_point(display_snapshot);
19487                results.push((start..end, color))
19488            }
19489        }
19490        results
19491    }
19492
19493    pub fn background_highlight_row_ranges<T: 'static>(
19494        &self,
19495        search_range: Range<Anchor>,
19496        display_snapshot: &DisplaySnapshot,
19497        count: usize,
19498    ) -> Vec<RangeInclusive<DisplayPoint>> {
19499        let mut results = Vec::new();
19500        let Some((_, ranges)) = self
19501            .background_highlights
19502            .get(&HighlightKey::Type(TypeId::of::<T>()))
19503        else {
19504            return vec![];
19505        };
19506
19507        let start_ix = match ranges.binary_search_by(|probe| {
19508            let cmp = probe
19509                .end
19510                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19511            if cmp.is_gt() {
19512                Ordering::Greater
19513            } else {
19514                Ordering::Less
19515            }
19516        }) {
19517            Ok(i) | Err(i) => i,
19518        };
19519        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19520            if let (Some(start_display), Some(end_display)) = (start, end) {
19521                results.push(
19522                    start_display.to_display_point(display_snapshot)
19523                        ..=end_display.to_display_point(display_snapshot),
19524                );
19525            }
19526        };
19527        let mut start_row: Option<Point> = None;
19528        let mut end_row: Option<Point> = None;
19529        if ranges.len() > count {
19530            return Vec::new();
19531        }
19532        for range in &ranges[start_ix..] {
19533            if range
19534                .start
19535                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19536                .is_ge()
19537            {
19538                break;
19539            }
19540            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19541            if let Some(current_row) = &end_row {
19542                if end.row == current_row.row {
19543                    continue;
19544                }
19545            }
19546            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19547            if start_row.is_none() {
19548                assert_eq!(end_row, None);
19549                start_row = Some(start);
19550                end_row = Some(end);
19551                continue;
19552            }
19553            if let Some(current_end) = end_row.as_mut() {
19554                if start.row > current_end.row + 1 {
19555                    push_region(start_row, end_row);
19556                    start_row = Some(start);
19557                    end_row = Some(end);
19558                } else {
19559                    // Merge two hunks.
19560                    *current_end = end;
19561                }
19562            } else {
19563                unreachable!();
19564            }
19565        }
19566        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19567        push_region(start_row, end_row);
19568        results
19569    }
19570
19571    pub fn gutter_highlights_in_range(
19572        &self,
19573        search_range: Range<Anchor>,
19574        display_snapshot: &DisplaySnapshot,
19575        cx: &App,
19576    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19577        let mut results = Vec::new();
19578        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19579            let color = color_fetcher(cx);
19580            let start_ix = match ranges.binary_search_by(|probe| {
19581                let cmp = probe
19582                    .end
19583                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19584                if cmp.is_gt() {
19585                    Ordering::Greater
19586                } else {
19587                    Ordering::Less
19588                }
19589            }) {
19590                Ok(i) | Err(i) => i,
19591            };
19592            for range in &ranges[start_ix..] {
19593                if range
19594                    .start
19595                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19596                    .is_ge()
19597                {
19598                    break;
19599                }
19600
19601                let start = range.start.to_display_point(display_snapshot);
19602                let end = range.end.to_display_point(display_snapshot);
19603                results.push((start..end, color))
19604            }
19605        }
19606        results
19607    }
19608
19609    /// Get the text ranges corresponding to the redaction query
19610    pub fn redacted_ranges(
19611        &self,
19612        search_range: Range<Anchor>,
19613        display_snapshot: &DisplaySnapshot,
19614        cx: &App,
19615    ) -> Vec<Range<DisplayPoint>> {
19616        display_snapshot
19617            .buffer_snapshot
19618            .redacted_ranges(search_range, |file| {
19619                if let Some(file) = file {
19620                    file.is_private()
19621                        && EditorSettings::get(
19622                            Some(SettingsLocation {
19623                                worktree_id: file.worktree_id(cx),
19624                                path: file.path().as_ref(),
19625                            }),
19626                            cx,
19627                        )
19628                        .redact_private_values
19629                } else {
19630                    false
19631                }
19632            })
19633            .map(|range| {
19634                range.start.to_display_point(display_snapshot)
19635                    ..range.end.to_display_point(display_snapshot)
19636            })
19637            .collect()
19638    }
19639
19640    pub fn highlight_text_key<T: 'static>(
19641        &mut self,
19642        key: usize,
19643        ranges: Vec<Range<Anchor>>,
19644        style: HighlightStyle,
19645        cx: &mut Context<Self>,
19646    ) {
19647        self.display_map.update(cx, |map, _| {
19648            map.highlight_text(
19649                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19650                ranges,
19651                style,
19652            );
19653        });
19654        cx.notify();
19655    }
19656
19657    pub fn highlight_text<T: 'static>(
19658        &mut self,
19659        ranges: Vec<Range<Anchor>>,
19660        style: HighlightStyle,
19661        cx: &mut Context<Self>,
19662    ) {
19663        self.display_map.update(cx, |map, _| {
19664            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19665        });
19666        cx.notify();
19667    }
19668
19669    pub(crate) fn highlight_inlays<T: 'static>(
19670        &mut self,
19671        highlights: Vec<InlayHighlight>,
19672        style: HighlightStyle,
19673        cx: &mut Context<Self>,
19674    ) {
19675        self.display_map.update(cx, |map, _| {
19676            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19677        });
19678        cx.notify();
19679    }
19680
19681    pub fn text_highlights<'a, T: 'static>(
19682        &'a self,
19683        cx: &'a App,
19684    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19685        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19686    }
19687
19688    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19689        let cleared = self
19690            .display_map
19691            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19692        if cleared {
19693            cx.notify();
19694        }
19695    }
19696
19697    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19698        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19699            && self.focus_handle.is_focused(window)
19700    }
19701
19702    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19703        self.show_cursor_when_unfocused = is_enabled;
19704        cx.notify();
19705    }
19706
19707    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19708        cx.notify();
19709    }
19710
19711    fn on_debug_session_event(
19712        &mut self,
19713        _session: Entity<Session>,
19714        event: &SessionEvent,
19715        cx: &mut Context<Self>,
19716    ) {
19717        match event {
19718            SessionEvent::InvalidateInlineValue => {
19719                self.refresh_inline_values(cx);
19720            }
19721            _ => {}
19722        }
19723    }
19724
19725    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19726        let Some(project) = self.project.clone() else {
19727            return;
19728        };
19729
19730        if !self.inline_value_cache.enabled {
19731            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19732            self.splice_inlays(&inlays, Vec::new(), cx);
19733            return;
19734        }
19735
19736        let current_execution_position = self
19737            .highlighted_rows
19738            .get(&TypeId::of::<ActiveDebugLine>())
19739            .and_then(|lines| lines.last().map(|line| line.range.end));
19740
19741        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19742            let inline_values = editor
19743                .update(cx, |editor, cx| {
19744                    let Some(current_execution_position) = current_execution_position else {
19745                        return Some(Task::ready(Ok(Vec::new())));
19746                    };
19747
19748                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19749                        let snapshot = buffer.snapshot(cx);
19750
19751                        let excerpt = snapshot.excerpt_containing(
19752                            current_execution_position..current_execution_position,
19753                        )?;
19754
19755                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19756                    })?;
19757
19758                    let range =
19759                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19760
19761                    project.inline_values(buffer, range, cx)
19762                })
19763                .ok()
19764                .flatten()?
19765                .await
19766                .context("refreshing debugger inlays")
19767                .log_err()?;
19768
19769            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19770
19771            for (buffer_id, inline_value) in inline_values
19772                .into_iter()
19773                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19774            {
19775                buffer_inline_values
19776                    .entry(buffer_id)
19777                    .or_default()
19778                    .push(inline_value);
19779            }
19780
19781            editor
19782                .update(cx, |editor, cx| {
19783                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19784                    let mut new_inlays = Vec::default();
19785
19786                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19787                        let buffer_id = buffer_snapshot.remote_id();
19788                        buffer_inline_values
19789                            .get(&buffer_id)
19790                            .into_iter()
19791                            .flatten()
19792                            .for_each(|hint| {
19793                                let inlay = Inlay::debugger(
19794                                    post_inc(&mut editor.next_inlay_id),
19795                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19796                                    hint.text(),
19797                                );
19798                                if !inlay.text.chars().contains(&'\n') {
19799                                    new_inlays.push(inlay);
19800                                }
19801                            });
19802                    }
19803
19804                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19805                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19806
19807                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19808                })
19809                .ok()?;
19810            Some(())
19811        });
19812    }
19813
19814    fn on_buffer_event(
19815        &mut self,
19816        multibuffer: &Entity<MultiBuffer>,
19817        event: &multi_buffer::Event,
19818        window: &mut Window,
19819        cx: &mut Context<Self>,
19820    ) {
19821        match event {
19822            multi_buffer::Event::Edited {
19823                singleton_buffer_edited,
19824                edited_buffer,
19825            } => {
19826                self.scrollbar_marker_state.dirty = true;
19827                self.active_indent_guides_state.dirty = true;
19828                self.refresh_active_diagnostics(cx);
19829                self.refresh_code_actions(window, cx);
19830                self.refresh_selected_text_highlights(true, window, cx);
19831                self.refresh_single_line_folds(window, cx);
19832                refresh_matching_bracket_highlights(self, window, cx);
19833                if self.has_active_inline_completion() {
19834                    self.update_visible_inline_completion(window, cx);
19835                }
19836                if let Some(project) = self.project.as_ref() {
19837                    if let Some(edited_buffer) = edited_buffer {
19838                        project.update(cx, |project, cx| {
19839                            self.registered_buffers
19840                                .entry(edited_buffer.read(cx).remote_id())
19841                                .or_insert_with(|| {
19842                                    project
19843                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19844                                });
19845                        });
19846                    }
19847                }
19848                cx.emit(EditorEvent::BufferEdited);
19849                cx.emit(SearchEvent::MatchesInvalidated);
19850
19851                if let Some(buffer) = edited_buffer {
19852                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19853                }
19854
19855                if *singleton_buffer_edited {
19856                    if let Some(buffer) = edited_buffer {
19857                        if buffer.read(cx).file().is_none() {
19858                            cx.emit(EditorEvent::TitleChanged);
19859                        }
19860                    }
19861                    if let Some(project) = &self.project {
19862                        #[allow(clippy::mutable_key_type)]
19863                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19864                            multibuffer
19865                                .all_buffers()
19866                                .into_iter()
19867                                .filter_map(|buffer| {
19868                                    buffer.update(cx, |buffer, cx| {
19869                                        let language = buffer.language()?;
19870                                        let should_discard = project.update(cx, |project, cx| {
19871                                            project.is_local()
19872                                                && !project.has_language_servers_for(buffer, cx)
19873                                        });
19874                                        should_discard.not().then_some(language.clone())
19875                                    })
19876                                })
19877                                .collect::<HashSet<_>>()
19878                        });
19879                        if !languages_affected.is_empty() {
19880                            self.refresh_inlay_hints(
19881                                InlayHintRefreshReason::BufferEdited(languages_affected),
19882                                cx,
19883                            );
19884                        }
19885                    }
19886                }
19887
19888                let Some(project) = &self.project else { return };
19889                let (telemetry, is_via_ssh) = {
19890                    let project = project.read(cx);
19891                    let telemetry = project.client().telemetry().clone();
19892                    let is_via_ssh = project.is_via_ssh();
19893                    (telemetry, is_via_ssh)
19894                };
19895                refresh_linked_ranges(self, window, cx);
19896                telemetry.log_edit_event("editor", is_via_ssh);
19897            }
19898            multi_buffer::Event::ExcerptsAdded {
19899                buffer,
19900                predecessor,
19901                excerpts,
19902            } => {
19903                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19904                let buffer_id = buffer.read(cx).remote_id();
19905                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19906                    if let Some(project) = &self.project {
19907                        update_uncommitted_diff_for_buffer(
19908                            cx.entity(),
19909                            project,
19910                            [buffer.clone()],
19911                            self.buffer.clone(),
19912                            cx,
19913                        )
19914                        .detach();
19915                    }
19916                }
19917                self.update_lsp_data(false, Some(buffer_id), window, cx);
19918                cx.emit(EditorEvent::ExcerptsAdded {
19919                    buffer: buffer.clone(),
19920                    predecessor: *predecessor,
19921                    excerpts: excerpts.clone(),
19922                });
19923                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19924            }
19925            multi_buffer::Event::ExcerptsRemoved {
19926                ids,
19927                removed_buffer_ids,
19928            } => {
19929                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19930                let buffer = self.buffer.read(cx);
19931                self.registered_buffers
19932                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19933                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19934                cx.emit(EditorEvent::ExcerptsRemoved {
19935                    ids: ids.clone(),
19936                    removed_buffer_ids: removed_buffer_ids.clone(),
19937                });
19938            }
19939            multi_buffer::Event::ExcerptsEdited {
19940                excerpt_ids,
19941                buffer_ids,
19942            } => {
19943                self.display_map.update(cx, |map, cx| {
19944                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19945                });
19946                cx.emit(EditorEvent::ExcerptsEdited {
19947                    ids: excerpt_ids.clone(),
19948                });
19949            }
19950            multi_buffer::Event::ExcerptsExpanded { ids } => {
19951                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19952                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19953            }
19954            multi_buffer::Event::Reparsed(buffer_id) => {
19955                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19956                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19957
19958                cx.emit(EditorEvent::Reparsed(*buffer_id));
19959            }
19960            multi_buffer::Event::DiffHunksToggled => {
19961                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19962            }
19963            multi_buffer::Event::LanguageChanged(buffer_id) => {
19964                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19965                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19966                cx.emit(EditorEvent::Reparsed(*buffer_id));
19967                cx.notify();
19968            }
19969            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19970            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19971            multi_buffer::Event::FileHandleChanged
19972            | multi_buffer::Event::Reloaded
19973            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19974            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19975            multi_buffer::Event::DiagnosticsUpdated => {
19976                self.update_diagnostics_state(window, cx);
19977            }
19978            _ => {}
19979        };
19980    }
19981
19982    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19983        if !self.diagnostics_enabled() {
19984            return;
19985        }
19986        self.refresh_active_diagnostics(cx);
19987        self.refresh_inline_diagnostics(true, window, cx);
19988        self.scrollbar_marker_state.dirty = true;
19989        cx.notify();
19990    }
19991
19992    pub fn start_temporary_diff_override(&mut self) {
19993        self.load_diff_task.take();
19994        self.temporary_diff_override = true;
19995    }
19996
19997    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19998        self.temporary_diff_override = false;
19999        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20000        self.buffer.update(cx, |buffer, cx| {
20001            buffer.set_all_diff_hunks_collapsed(cx);
20002        });
20003
20004        if let Some(project) = self.project.clone() {
20005            self.load_diff_task = Some(
20006                update_uncommitted_diff_for_buffer(
20007                    cx.entity(),
20008                    &project,
20009                    self.buffer.read(cx).all_buffers(),
20010                    self.buffer.clone(),
20011                    cx,
20012                )
20013                .shared(),
20014            );
20015        }
20016    }
20017
20018    fn on_display_map_changed(
20019        &mut self,
20020        _: Entity<DisplayMap>,
20021        _: &mut Window,
20022        cx: &mut Context<Self>,
20023    ) {
20024        cx.notify();
20025    }
20026
20027    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20028        if self.diagnostics_enabled() {
20029            let new_severity = EditorSettings::get_global(cx)
20030                .diagnostics_max_severity
20031                .unwrap_or(DiagnosticSeverity::Hint);
20032            self.set_max_diagnostics_severity(new_severity, cx);
20033        }
20034        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20035        self.update_edit_prediction_settings(cx);
20036        self.refresh_inline_completion(true, false, window, cx);
20037        self.refresh_inline_values(cx);
20038        self.refresh_inlay_hints(
20039            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20040                self.selections.newest_anchor().head(),
20041                &self.buffer.read(cx).snapshot(cx),
20042                cx,
20043            )),
20044            cx,
20045        );
20046
20047        let old_cursor_shape = self.cursor_shape;
20048
20049        {
20050            let editor_settings = EditorSettings::get_global(cx);
20051            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20052            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20053            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20054            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20055        }
20056
20057        if old_cursor_shape != self.cursor_shape {
20058            cx.emit(EditorEvent::CursorShapeChanged);
20059        }
20060
20061        let project_settings = ProjectSettings::get_global(cx);
20062        self.serialize_dirty_buffers =
20063            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20064
20065        if self.mode.is_full() {
20066            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20067            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20068            if self.show_inline_diagnostics != show_inline_diagnostics {
20069                self.show_inline_diagnostics = show_inline_diagnostics;
20070                self.refresh_inline_diagnostics(false, window, cx);
20071            }
20072
20073            if self.git_blame_inline_enabled != inline_blame_enabled {
20074                self.toggle_git_blame_inline_internal(false, window, cx);
20075            }
20076
20077            let minimap_settings = EditorSettings::get_global(cx).minimap;
20078            if self.minimap_visibility != MinimapVisibility::Disabled {
20079                if self.minimap_visibility.settings_visibility()
20080                    != minimap_settings.minimap_enabled()
20081                {
20082                    self.set_minimap_visibility(
20083                        MinimapVisibility::for_mode(self.mode(), cx),
20084                        window,
20085                        cx,
20086                    );
20087                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20088                    minimap_entity.update(cx, |minimap_editor, cx| {
20089                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20090                    })
20091                }
20092            }
20093        }
20094
20095        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20096            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20097        }) {
20098            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20099                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20100            }
20101            self.refresh_colors(false, None, window, cx);
20102        }
20103
20104        cx.notify();
20105    }
20106
20107    pub fn set_searchable(&mut self, searchable: bool) {
20108        self.searchable = searchable;
20109    }
20110
20111    pub fn searchable(&self) -> bool {
20112        self.searchable
20113    }
20114
20115    fn open_proposed_changes_editor(
20116        &mut self,
20117        _: &OpenProposedChangesEditor,
20118        window: &mut Window,
20119        cx: &mut Context<Self>,
20120    ) {
20121        let Some(workspace) = self.workspace() else {
20122            cx.propagate();
20123            return;
20124        };
20125
20126        let selections = self.selections.all::<usize>(cx);
20127        let multi_buffer = self.buffer.read(cx);
20128        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20129        let mut new_selections_by_buffer = HashMap::default();
20130        for selection in selections {
20131            for (buffer, range, _) in
20132                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20133            {
20134                let mut range = range.to_point(buffer);
20135                range.start.column = 0;
20136                range.end.column = buffer.line_len(range.end.row);
20137                new_selections_by_buffer
20138                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20139                    .or_insert(Vec::new())
20140                    .push(range)
20141            }
20142        }
20143
20144        let proposed_changes_buffers = new_selections_by_buffer
20145            .into_iter()
20146            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20147            .collect::<Vec<_>>();
20148        let proposed_changes_editor = cx.new(|cx| {
20149            ProposedChangesEditor::new(
20150                "Proposed changes",
20151                proposed_changes_buffers,
20152                self.project.clone(),
20153                window,
20154                cx,
20155            )
20156        });
20157
20158        window.defer(cx, move |window, cx| {
20159            workspace.update(cx, |workspace, cx| {
20160                workspace.active_pane().update(cx, |pane, cx| {
20161                    pane.add_item(
20162                        Box::new(proposed_changes_editor),
20163                        true,
20164                        true,
20165                        None,
20166                        window,
20167                        cx,
20168                    );
20169                });
20170            });
20171        });
20172    }
20173
20174    pub fn open_excerpts_in_split(
20175        &mut self,
20176        _: &OpenExcerptsSplit,
20177        window: &mut Window,
20178        cx: &mut Context<Self>,
20179    ) {
20180        self.open_excerpts_common(None, true, window, cx)
20181    }
20182
20183    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20184        self.open_excerpts_common(None, false, window, cx)
20185    }
20186
20187    fn open_excerpts_common(
20188        &mut self,
20189        jump_data: Option<JumpData>,
20190        split: bool,
20191        window: &mut Window,
20192        cx: &mut Context<Self>,
20193    ) {
20194        let Some(workspace) = self.workspace() else {
20195            cx.propagate();
20196            return;
20197        };
20198
20199        if self.buffer.read(cx).is_singleton() {
20200            cx.propagate();
20201            return;
20202        }
20203
20204        let mut new_selections_by_buffer = HashMap::default();
20205        match &jump_data {
20206            Some(JumpData::MultiBufferPoint {
20207                excerpt_id,
20208                position,
20209                anchor,
20210                line_offset_from_top,
20211            }) => {
20212                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20213                if let Some(buffer) = multi_buffer_snapshot
20214                    .buffer_id_for_excerpt(*excerpt_id)
20215                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20216                {
20217                    let buffer_snapshot = buffer.read(cx).snapshot();
20218                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20219                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20220                    } else {
20221                        buffer_snapshot.clip_point(*position, Bias::Left)
20222                    };
20223                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20224                    new_selections_by_buffer.insert(
20225                        buffer,
20226                        (
20227                            vec![jump_to_offset..jump_to_offset],
20228                            Some(*line_offset_from_top),
20229                        ),
20230                    );
20231                }
20232            }
20233            Some(JumpData::MultiBufferRow {
20234                row,
20235                line_offset_from_top,
20236            }) => {
20237                let point = MultiBufferPoint::new(row.0, 0);
20238                if let Some((buffer, buffer_point, _)) =
20239                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20240                {
20241                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20242                    new_selections_by_buffer
20243                        .entry(buffer)
20244                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20245                        .0
20246                        .push(buffer_offset..buffer_offset)
20247                }
20248            }
20249            None => {
20250                let selections = self.selections.all::<usize>(cx);
20251                let multi_buffer = self.buffer.read(cx);
20252                for selection in selections {
20253                    for (snapshot, range, _, anchor) in multi_buffer
20254                        .snapshot(cx)
20255                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20256                    {
20257                        if let Some(anchor) = anchor {
20258                            // selection is in a deleted hunk
20259                            let Some(buffer_id) = anchor.buffer_id else {
20260                                continue;
20261                            };
20262                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20263                                continue;
20264                            };
20265                            let offset = text::ToOffset::to_offset(
20266                                &anchor.text_anchor,
20267                                &buffer_handle.read(cx).snapshot(),
20268                            );
20269                            let range = offset..offset;
20270                            new_selections_by_buffer
20271                                .entry(buffer_handle)
20272                                .or_insert((Vec::new(), None))
20273                                .0
20274                                .push(range)
20275                        } else {
20276                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20277                            else {
20278                                continue;
20279                            };
20280                            new_selections_by_buffer
20281                                .entry(buffer_handle)
20282                                .or_insert((Vec::new(), None))
20283                                .0
20284                                .push(range)
20285                        }
20286                    }
20287                }
20288            }
20289        }
20290
20291        new_selections_by_buffer
20292            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20293
20294        if new_selections_by_buffer.is_empty() {
20295            return;
20296        }
20297
20298        // We defer the pane interaction because we ourselves are a workspace item
20299        // and activating a new item causes the pane to call a method on us reentrantly,
20300        // which panics if we're on the stack.
20301        window.defer(cx, move |window, cx| {
20302            workspace.update(cx, |workspace, cx| {
20303                let pane = if split {
20304                    workspace.adjacent_pane(window, cx)
20305                } else {
20306                    workspace.active_pane().clone()
20307                };
20308
20309                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20310                    let editor = buffer
20311                        .read(cx)
20312                        .file()
20313                        .is_none()
20314                        .then(|| {
20315                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20316                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20317                            // Instead, we try to activate the existing editor in the pane first.
20318                            let (editor, pane_item_index) =
20319                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20320                                    let editor = item.downcast::<Editor>()?;
20321                                    let singleton_buffer =
20322                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20323                                    if singleton_buffer == buffer {
20324                                        Some((editor, i))
20325                                    } else {
20326                                        None
20327                                    }
20328                                })?;
20329                            pane.update(cx, |pane, cx| {
20330                                pane.activate_item(pane_item_index, true, true, window, cx)
20331                            });
20332                            Some(editor)
20333                        })
20334                        .flatten()
20335                        .unwrap_or_else(|| {
20336                            workspace.open_project_item::<Self>(
20337                                pane.clone(),
20338                                buffer,
20339                                true,
20340                                true,
20341                                window,
20342                                cx,
20343                            )
20344                        });
20345
20346                    editor.update(cx, |editor, cx| {
20347                        let autoscroll = match scroll_offset {
20348                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20349                            None => Autoscroll::newest(),
20350                        };
20351                        let nav_history = editor.nav_history.take();
20352                        editor.change_selections(
20353                            SelectionEffects::scroll(autoscroll),
20354                            window,
20355                            cx,
20356                            |s| {
20357                                s.select_ranges(ranges);
20358                            },
20359                        );
20360                        editor.nav_history = nav_history;
20361                    });
20362                }
20363            })
20364        });
20365    }
20366
20367    // For now, don't allow opening excerpts in buffers that aren't backed by
20368    // regular project files.
20369    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20370        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20371    }
20372
20373    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20374        let snapshot = self.buffer.read(cx).read(cx);
20375        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20376        Some(
20377            ranges
20378                .iter()
20379                .map(move |range| {
20380                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20381                })
20382                .collect(),
20383        )
20384    }
20385
20386    fn selection_replacement_ranges(
20387        &self,
20388        range: Range<OffsetUtf16>,
20389        cx: &mut App,
20390    ) -> Vec<Range<OffsetUtf16>> {
20391        let selections = self.selections.all::<OffsetUtf16>(cx);
20392        let newest_selection = selections
20393            .iter()
20394            .max_by_key(|selection| selection.id)
20395            .unwrap();
20396        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20397        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20398        let snapshot = self.buffer.read(cx).read(cx);
20399        selections
20400            .into_iter()
20401            .map(|mut selection| {
20402                selection.start.0 =
20403                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20404                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20405                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20406                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20407            })
20408            .collect()
20409    }
20410
20411    fn report_editor_event(
20412        &self,
20413        event_type: &'static str,
20414        file_extension: Option<String>,
20415        cx: &App,
20416    ) {
20417        if cfg!(any(test, feature = "test-support")) {
20418            return;
20419        }
20420
20421        let Some(project) = &self.project else { return };
20422
20423        // If None, we are in a file without an extension
20424        let file = self
20425            .buffer
20426            .read(cx)
20427            .as_singleton()
20428            .and_then(|b| b.read(cx).file());
20429        let file_extension = file_extension.or(file
20430            .as_ref()
20431            .and_then(|file| Path::new(file.file_name(cx)).extension())
20432            .and_then(|e| e.to_str())
20433            .map(|a| a.to_string()));
20434
20435        let vim_mode = vim_enabled(cx);
20436
20437        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20438        let copilot_enabled = edit_predictions_provider
20439            == language::language_settings::EditPredictionProvider::Copilot;
20440        let copilot_enabled_for_language = self
20441            .buffer
20442            .read(cx)
20443            .language_settings(cx)
20444            .show_edit_predictions;
20445
20446        let project = project.read(cx);
20447        telemetry::event!(
20448            event_type,
20449            file_extension,
20450            vim_mode,
20451            copilot_enabled,
20452            copilot_enabled_for_language,
20453            edit_predictions_provider,
20454            is_via_ssh = project.is_via_ssh(),
20455        );
20456    }
20457
20458    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20459    /// with each line being an array of {text, highlight} objects.
20460    fn copy_highlight_json(
20461        &mut self,
20462        _: &CopyHighlightJson,
20463        window: &mut Window,
20464        cx: &mut Context<Self>,
20465    ) {
20466        #[derive(Serialize)]
20467        struct Chunk<'a> {
20468            text: String,
20469            highlight: Option<&'a str>,
20470        }
20471
20472        let snapshot = self.buffer.read(cx).snapshot(cx);
20473        let range = self
20474            .selected_text_range(false, window, cx)
20475            .and_then(|selection| {
20476                if selection.range.is_empty() {
20477                    None
20478                } else {
20479                    Some(selection.range)
20480                }
20481            })
20482            .unwrap_or_else(|| 0..snapshot.len());
20483
20484        let chunks = snapshot.chunks(range, true);
20485        let mut lines = Vec::new();
20486        let mut line: VecDeque<Chunk> = VecDeque::new();
20487
20488        let Some(style) = self.style.as_ref() else {
20489            return;
20490        };
20491
20492        for chunk in chunks {
20493            let highlight = chunk
20494                .syntax_highlight_id
20495                .and_then(|id| id.name(&style.syntax));
20496            let mut chunk_lines = chunk.text.split('\n').peekable();
20497            while let Some(text) = chunk_lines.next() {
20498                let mut merged_with_last_token = false;
20499                if let Some(last_token) = line.back_mut() {
20500                    if last_token.highlight == highlight {
20501                        last_token.text.push_str(text);
20502                        merged_with_last_token = true;
20503                    }
20504                }
20505
20506                if !merged_with_last_token {
20507                    line.push_back(Chunk {
20508                        text: text.into(),
20509                        highlight,
20510                    });
20511                }
20512
20513                if chunk_lines.peek().is_some() {
20514                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20515                        line.pop_front();
20516                    }
20517                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20518                        line.pop_back();
20519                    }
20520
20521                    lines.push(mem::take(&mut line));
20522                }
20523            }
20524        }
20525
20526        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20527            return;
20528        };
20529        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20530    }
20531
20532    pub fn open_context_menu(
20533        &mut self,
20534        _: &OpenContextMenu,
20535        window: &mut Window,
20536        cx: &mut Context<Self>,
20537    ) {
20538        self.request_autoscroll(Autoscroll::newest(), cx);
20539        let position = self.selections.newest_display(cx).start;
20540        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20541    }
20542
20543    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20544        &self.inlay_hint_cache
20545    }
20546
20547    pub fn replay_insert_event(
20548        &mut self,
20549        text: &str,
20550        relative_utf16_range: Option<Range<isize>>,
20551        window: &mut Window,
20552        cx: &mut Context<Self>,
20553    ) {
20554        if !self.input_enabled {
20555            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20556            return;
20557        }
20558        if let Some(relative_utf16_range) = relative_utf16_range {
20559            let selections = self.selections.all::<OffsetUtf16>(cx);
20560            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20561                let new_ranges = selections.into_iter().map(|range| {
20562                    let start = OffsetUtf16(
20563                        range
20564                            .head()
20565                            .0
20566                            .saturating_add_signed(relative_utf16_range.start),
20567                    );
20568                    let end = OffsetUtf16(
20569                        range
20570                            .head()
20571                            .0
20572                            .saturating_add_signed(relative_utf16_range.end),
20573                    );
20574                    start..end
20575                });
20576                s.select_ranges(new_ranges);
20577            });
20578        }
20579
20580        self.handle_input(text, window, cx);
20581    }
20582
20583    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20584        let Some(provider) = self.semantics_provider.as_ref() else {
20585            return false;
20586        };
20587
20588        let mut supports = false;
20589        self.buffer().update(cx, |this, cx| {
20590            this.for_each_buffer(|buffer| {
20591                supports |= provider.supports_inlay_hints(buffer, cx);
20592            });
20593        });
20594
20595        supports
20596    }
20597
20598    pub fn is_focused(&self, window: &Window) -> bool {
20599        self.focus_handle.is_focused(window)
20600    }
20601
20602    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20603        cx.emit(EditorEvent::Focused);
20604
20605        if let Some(descendant) = self
20606            .last_focused_descendant
20607            .take()
20608            .and_then(|descendant| descendant.upgrade())
20609        {
20610            window.focus(&descendant);
20611        } else {
20612            if let Some(blame) = self.blame.as_ref() {
20613                blame.update(cx, GitBlame::focus)
20614            }
20615
20616            self.blink_manager.update(cx, BlinkManager::enable);
20617            self.show_cursor_names(window, cx);
20618            self.buffer.update(cx, |buffer, cx| {
20619                buffer.finalize_last_transaction(cx);
20620                if self.leader_id.is_none() {
20621                    buffer.set_active_selections(
20622                        &self.selections.disjoint_anchors(),
20623                        self.selections.line_mode,
20624                        self.cursor_shape,
20625                        cx,
20626                    );
20627                }
20628            });
20629        }
20630    }
20631
20632    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20633        cx.emit(EditorEvent::FocusedIn)
20634    }
20635
20636    fn handle_focus_out(
20637        &mut self,
20638        event: FocusOutEvent,
20639        _window: &mut Window,
20640        cx: &mut Context<Self>,
20641    ) {
20642        if event.blurred != self.focus_handle {
20643            self.last_focused_descendant = Some(event.blurred);
20644        }
20645        self.selection_drag_state = SelectionDragState::None;
20646        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20647    }
20648
20649    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20650        self.blink_manager.update(cx, BlinkManager::disable);
20651        self.buffer
20652            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20653
20654        if let Some(blame) = self.blame.as_ref() {
20655            blame.update(cx, GitBlame::blur)
20656        }
20657        if !self.hover_state.focused(window, cx) {
20658            hide_hover(self, cx);
20659        }
20660        if !self
20661            .context_menu
20662            .borrow()
20663            .as_ref()
20664            .is_some_and(|context_menu| context_menu.focused(window, cx))
20665        {
20666            self.hide_context_menu(window, cx);
20667        }
20668        self.discard_inline_completion(false, cx);
20669        cx.emit(EditorEvent::Blurred);
20670        cx.notify();
20671    }
20672
20673    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20674        let mut pending: String = window
20675            .pending_input_keystrokes()
20676            .into_iter()
20677            .flatten()
20678            .filter_map(|keystroke| {
20679                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20680                    keystroke.key_char.clone()
20681                } else {
20682                    None
20683                }
20684            })
20685            .collect();
20686
20687        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20688            pending = "".to_string();
20689        }
20690
20691        let existing_pending = self
20692            .text_highlights::<PendingInput>(cx)
20693            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20694        if existing_pending.is_none() && pending.is_empty() {
20695            return;
20696        }
20697        let transaction =
20698            self.transact(window, cx, |this, window, cx| {
20699                let selections = this.selections.all::<usize>(cx);
20700                let edits = selections
20701                    .iter()
20702                    .map(|selection| (selection.end..selection.end, pending.clone()));
20703                this.edit(edits, cx);
20704                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20705                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20706                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20707                    }));
20708                });
20709                if let Some(existing_ranges) = existing_pending {
20710                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20711                    this.edit(edits, cx);
20712                }
20713            });
20714
20715        let snapshot = self.snapshot(window, cx);
20716        let ranges = self
20717            .selections
20718            .all::<usize>(cx)
20719            .into_iter()
20720            .map(|selection| {
20721                snapshot.buffer_snapshot.anchor_after(selection.end)
20722                    ..snapshot
20723                        .buffer_snapshot
20724                        .anchor_before(selection.end + pending.len())
20725            })
20726            .collect();
20727
20728        if pending.is_empty() {
20729            self.clear_highlights::<PendingInput>(cx);
20730        } else {
20731            self.highlight_text::<PendingInput>(
20732                ranges,
20733                HighlightStyle {
20734                    underline: Some(UnderlineStyle {
20735                        thickness: px(1.),
20736                        color: None,
20737                        wavy: false,
20738                    }),
20739                    ..Default::default()
20740                },
20741                cx,
20742            );
20743        }
20744
20745        self.ime_transaction = self.ime_transaction.or(transaction);
20746        if let Some(transaction) = self.ime_transaction {
20747            self.buffer.update(cx, |buffer, cx| {
20748                buffer.group_until_transaction(transaction, cx);
20749            });
20750        }
20751
20752        if self.text_highlights::<PendingInput>(cx).is_none() {
20753            self.ime_transaction.take();
20754        }
20755    }
20756
20757    pub fn register_action_renderer(
20758        &mut self,
20759        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20760    ) -> Subscription {
20761        let id = self.next_editor_action_id.post_inc();
20762        self.editor_actions
20763            .borrow_mut()
20764            .insert(id, Box::new(listener));
20765
20766        let editor_actions = self.editor_actions.clone();
20767        Subscription::new(move || {
20768            editor_actions.borrow_mut().remove(&id);
20769        })
20770    }
20771
20772    pub fn register_action<A: Action>(
20773        &mut self,
20774        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20775    ) -> Subscription {
20776        let id = self.next_editor_action_id.post_inc();
20777        let listener = Arc::new(listener);
20778        self.editor_actions.borrow_mut().insert(
20779            id,
20780            Box::new(move |_, window, _| {
20781                let listener = listener.clone();
20782                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20783                    let action = action.downcast_ref().unwrap();
20784                    if phase == DispatchPhase::Bubble {
20785                        listener(action, window, cx)
20786                    }
20787                })
20788            }),
20789        );
20790
20791        let editor_actions = self.editor_actions.clone();
20792        Subscription::new(move || {
20793            editor_actions.borrow_mut().remove(&id);
20794        })
20795    }
20796
20797    pub fn file_header_size(&self) -> u32 {
20798        FILE_HEADER_HEIGHT
20799    }
20800
20801    pub fn restore(
20802        &mut self,
20803        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20804        window: &mut Window,
20805        cx: &mut Context<Self>,
20806    ) {
20807        let workspace = self.workspace();
20808        let project = self.project.as_ref();
20809        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20810            let mut tasks = Vec::new();
20811            for (buffer_id, changes) in revert_changes {
20812                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20813                    buffer.update(cx, |buffer, cx| {
20814                        buffer.edit(
20815                            changes
20816                                .into_iter()
20817                                .map(|(range, text)| (range, text.to_string())),
20818                            None,
20819                            cx,
20820                        );
20821                    });
20822
20823                    if let Some(project) =
20824                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20825                    {
20826                        project.update(cx, |project, cx| {
20827                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20828                        })
20829                    }
20830                }
20831            }
20832            tasks
20833        });
20834        cx.spawn_in(window, async move |_, cx| {
20835            for (buffer, task) in save_tasks {
20836                let result = task.await;
20837                if result.is_err() {
20838                    let Some(path) = buffer
20839                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20840                        .ok()
20841                    else {
20842                        continue;
20843                    };
20844                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20845                        let Some(task) = cx
20846                            .update_window_entity(&workspace, |workspace, window, cx| {
20847                                workspace
20848                                    .open_path_preview(path, None, false, false, false, window, cx)
20849                            })
20850                            .ok()
20851                        else {
20852                            continue;
20853                        };
20854                        task.await.log_err();
20855                    }
20856                }
20857            }
20858        })
20859        .detach();
20860        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20861            selections.refresh()
20862        });
20863    }
20864
20865    pub fn to_pixel_point(
20866        &self,
20867        source: multi_buffer::Anchor,
20868        editor_snapshot: &EditorSnapshot,
20869        window: &mut Window,
20870    ) -> Option<gpui::Point<Pixels>> {
20871        let source_point = source.to_display_point(editor_snapshot);
20872        self.display_to_pixel_point(source_point, editor_snapshot, window)
20873    }
20874
20875    pub fn display_to_pixel_point(
20876        &self,
20877        source: DisplayPoint,
20878        editor_snapshot: &EditorSnapshot,
20879        window: &mut Window,
20880    ) -> Option<gpui::Point<Pixels>> {
20881        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20882        let text_layout_details = self.text_layout_details(window);
20883        let scroll_top = text_layout_details
20884            .scroll_anchor
20885            .scroll_position(editor_snapshot)
20886            .y;
20887
20888        if source.row().as_f32() < scroll_top.floor() {
20889            return None;
20890        }
20891        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20892        let source_y = line_height * (source.row().as_f32() - scroll_top);
20893        Some(gpui::Point::new(source_x, source_y))
20894    }
20895
20896    pub fn has_visible_completions_menu(&self) -> bool {
20897        !self.edit_prediction_preview_is_active()
20898            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20899                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20900            })
20901    }
20902
20903    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20904        if self.mode.is_minimap() {
20905            return;
20906        }
20907        self.addons
20908            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20909    }
20910
20911    pub fn unregister_addon<T: Addon>(&mut self) {
20912        self.addons.remove(&std::any::TypeId::of::<T>());
20913    }
20914
20915    pub fn addon<T: Addon>(&self) -> Option<&T> {
20916        let type_id = std::any::TypeId::of::<T>();
20917        self.addons
20918            .get(&type_id)
20919            .and_then(|item| item.to_any().downcast_ref::<T>())
20920    }
20921
20922    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20923        let type_id = std::any::TypeId::of::<T>();
20924        self.addons
20925            .get_mut(&type_id)
20926            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20927    }
20928
20929    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20930        let text_layout_details = self.text_layout_details(window);
20931        let style = &text_layout_details.editor_style;
20932        let font_id = window.text_system().resolve_font(&style.text.font());
20933        let font_size = style.text.font_size.to_pixels(window.rem_size());
20934        let line_height = style.text.line_height_in_pixels(window.rem_size());
20935        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20936        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20937
20938        CharacterDimensions {
20939            em_width,
20940            em_advance,
20941            line_height,
20942        }
20943    }
20944
20945    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20946        self.load_diff_task.clone()
20947    }
20948
20949    fn read_metadata_from_db(
20950        &mut self,
20951        item_id: u64,
20952        workspace_id: WorkspaceId,
20953        window: &mut Window,
20954        cx: &mut Context<Editor>,
20955    ) {
20956        if self.is_singleton(cx)
20957            && !self.mode.is_minimap()
20958            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20959        {
20960            let buffer_snapshot = OnceCell::new();
20961
20962            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20963                if !folds.is_empty() {
20964                    let snapshot =
20965                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20966                    self.fold_ranges(
20967                        folds
20968                            .into_iter()
20969                            .map(|(start, end)| {
20970                                snapshot.clip_offset(start, Bias::Left)
20971                                    ..snapshot.clip_offset(end, Bias::Right)
20972                            })
20973                            .collect(),
20974                        false,
20975                        window,
20976                        cx,
20977                    );
20978                }
20979            }
20980
20981            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20982                if !selections.is_empty() {
20983                    let snapshot =
20984                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20985                    // skip adding the initial selection to selection history
20986                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20987                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20988                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20989                            snapshot.clip_offset(start, Bias::Left)
20990                                ..snapshot.clip_offset(end, Bias::Right)
20991                        }));
20992                    });
20993                    self.selection_history.mode = SelectionHistoryMode::Normal;
20994                }
20995            };
20996        }
20997
20998        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20999    }
21000
21001    fn update_lsp_data(
21002        &mut self,
21003        ignore_cache: bool,
21004        for_buffer: Option<BufferId>,
21005        window: &mut Window,
21006        cx: &mut Context<'_, Self>,
21007    ) {
21008        self.pull_diagnostics(for_buffer, window, cx);
21009        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21010    }
21011}
21012
21013fn vim_enabled(cx: &App) -> bool {
21014    cx.global::<SettingsStore>()
21015        .raw_user_settings()
21016        .get("vim_mode")
21017        == Some(&serde_json::Value::Bool(true))
21018}
21019
21020fn process_completion_for_edit(
21021    completion: &Completion,
21022    intent: CompletionIntent,
21023    buffer: &Entity<Buffer>,
21024    cursor_position: &text::Anchor,
21025    cx: &mut Context<Editor>,
21026) -> CompletionEdit {
21027    let buffer = buffer.read(cx);
21028    let buffer_snapshot = buffer.snapshot();
21029    let (snippet, new_text) = if completion.is_snippet() {
21030        // Workaround for typescript language server issues so that methods don't expand within
21031        // strings and functions with type expressions. The previous point is used because the query
21032        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21033        let mut snippet_source = completion.new_text.clone();
21034        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21035        previous_point.column = previous_point.column.saturating_sub(1);
21036        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21037            if scope.prefers_label_for_snippet_in_completion() {
21038                if let Some(label) = completion.label() {
21039                    if matches!(
21040                        completion.kind(),
21041                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21042                    ) {
21043                        snippet_source = label;
21044                    }
21045                }
21046            }
21047        }
21048        match Snippet::parse(&snippet_source).log_err() {
21049            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21050            None => (None, completion.new_text.clone()),
21051        }
21052    } else {
21053        (None, completion.new_text.clone())
21054    };
21055
21056    let mut range_to_replace = {
21057        let replace_range = &completion.replace_range;
21058        if let CompletionSource::Lsp {
21059            insert_range: Some(insert_range),
21060            ..
21061        } = &completion.source
21062        {
21063            debug_assert_eq!(
21064                insert_range.start, replace_range.start,
21065                "insert_range and replace_range should start at the same position"
21066            );
21067            debug_assert!(
21068                insert_range
21069                    .start
21070                    .cmp(&cursor_position, &buffer_snapshot)
21071                    .is_le(),
21072                "insert_range should start before or at cursor position"
21073            );
21074            debug_assert!(
21075                replace_range
21076                    .start
21077                    .cmp(&cursor_position, &buffer_snapshot)
21078                    .is_le(),
21079                "replace_range should start before or at cursor position"
21080            );
21081            debug_assert!(
21082                insert_range
21083                    .end
21084                    .cmp(&cursor_position, &buffer_snapshot)
21085                    .is_le(),
21086                "insert_range should end before or at cursor position"
21087            );
21088
21089            let should_replace = match intent {
21090                CompletionIntent::CompleteWithInsert => false,
21091                CompletionIntent::CompleteWithReplace => true,
21092                CompletionIntent::Complete | CompletionIntent::Compose => {
21093                    let insert_mode =
21094                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21095                            .completions
21096                            .lsp_insert_mode;
21097                    match insert_mode {
21098                        LspInsertMode::Insert => false,
21099                        LspInsertMode::Replace => true,
21100                        LspInsertMode::ReplaceSubsequence => {
21101                            let mut text_to_replace = buffer.chars_for_range(
21102                                buffer.anchor_before(replace_range.start)
21103                                    ..buffer.anchor_after(replace_range.end),
21104                            );
21105                            let mut current_needle = text_to_replace.next();
21106                            for haystack_ch in completion.label.text.chars() {
21107                                if let Some(needle_ch) = current_needle {
21108                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21109                                        current_needle = text_to_replace.next();
21110                                    }
21111                                }
21112                            }
21113                            current_needle.is_none()
21114                        }
21115                        LspInsertMode::ReplaceSuffix => {
21116                            if replace_range
21117                                .end
21118                                .cmp(&cursor_position, &buffer_snapshot)
21119                                .is_gt()
21120                            {
21121                                let range_after_cursor = *cursor_position..replace_range.end;
21122                                let text_after_cursor = buffer
21123                                    .text_for_range(
21124                                        buffer.anchor_before(range_after_cursor.start)
21125                                            ..buffer.anchor_after(range_after_cursor.end),
21126                                    )
21127                                    .collect::<String>()
21128                                    .to_ascii_lowercase();
21129                                completion
21130                                    .label
21131                                    .text
21132                                    .to_ascii_lowercase()
21133                                    .ends_with(&text_after_cursor)
21134                            } else {
21135                                true
21136                            }
21137                        }
21138                    }
21139                }
21140            };
21141
21142            if should_replace {
21143                replace_range.clone()
21144            } else {
21145                insert_range.clone()
21146            }
21147        } else {
21148            replace_range.clone()
21149        }
21150    };
21151
21152    if range_to_replace
21153        .end
21154        .cmp(&cursor_position, &buffer_snapshot)
21155        .is_lt()
21156    {
21157        range_to_replace.end = *cursor_position;
21158    }
21159
21160    CompletionEdit {
21161        new_text,
21162        replace_range: range_to_replace.to_offset(&buffer),
21163        snippet,
21164    }
21165}
21166
21167struct CompletionEdit {
21168    new_text: String,
21169    replace_range: Range<usize>,
21170    snippet: Option<Snippet>,
21171}
21172
21173fn insert_extra_newline_brackets(
21174    buffer: &MultiBufferSnapshot,
21175    range: Range<usize>,
21176    language: &language::LanguageScope,
21177) -> bool {
21178    let leading_whitespace_len = buffer
21179        .reversed_chars_at(range.start)
21180        .take_while(|c| c.is_whitespace() && *c != '\n')
21181        .map(|c| c.len_utf8())
21182        .sum::<usize>();
21183    let trailing_whitespace_len = buffer
21184        .chars_at(range.end)
21185        .take_while(|c| c.is_whitespace() && *c != '\n')
21186        .map(|c| c.len_utf8())
21187        .sum::<usize>();
21188    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21189
21190    language.brackets().any(|(pair, enabled)| {
21191        let pair_start = pair.start.trim_end();
21192        let pair_end = pair.end.trim_start();
21193
21194        enabled
21195            && pair.newline
21196            && buffer.contains_str_at(range.end, pair_end)
21197            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21198    })
21199}
21200
21201fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21202    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21203        [(buffer, range, _)] => (*buffer, range.clone()),
21204        _ => return false,
21205    };
21206    let pair = {
21207        let mut result: Option<BracketMatch> = None;
21208
21209        for pair in buffer
21210            .all_bracket_ranges(range.clone())
21211            .filter(move |pair| {
21212                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21213            })
21214        {
21215            let len = pair.close_range.end - pair.open_range.start;
21216
21217            if let Some(existing) = &result {
21218                let existing_len = existing.close_range.end - existing.open_range.start;
21219                if len > existing_len {
21220                    continue;
21221                }
21222            }
21223
21224            result = Some(pair);
21225        }
21226
21227        result
21228    };
21229    let Some(pair) = pair else {
21230        return false;
21231    };
21232    pair.newline_only
21233        && buffer
21234            .chars_for_range(pair.open_range.end..range.start)
21235            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21236            .all(|c| c.is_whitespace() && c != '\n')
21237}
21238
21239fn update_uncommitted_diff_for_buffer(
21240    editor: Entity<Editor>,
21241    project: &Entity<Project>,
21242    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21243    buffer: Entity<MultiBuffer>,
21244    cx: &mut App,
21245) -> Task<()> {
21246    let mut tasks = Vec::new();
21247    project.update(cx, |project, cx| {
21248        for buffer in buffers {
21249            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21250                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21251            }
21252        }
21253    });
21254    cx.spawn(async move |cx| {
21255        let diffs = future::join_all(tasks).await;
21256        if editor
21257            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21258            .unwrap_or(false)
21259        {
21260            return;
21261        }
21262
21263        buffer
21264            .update(cx, |buffer, cx| {
21265                for diff in diffs.into_iter().flatten() {
21266                    buffer.add_diff(diff, cx);
21267                }
21268            })
21269            .ok();
21270    })
21271}
21272
21273fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21274    let tab_size = tab_size.get() as usize;
21275    let mut width = offset;
21276
21277    for ch in text.chars() {
21278        width += if ch == '\t' {
21279            tab_size - (width % tab_size)
21280        } else {
21281            1
21282        };
21283    }
21284
21285    width - offset
21286}
21287
21288#[cfg(test)]
21289mod tests {
21290    use super::*;
21291
21292    #[test]
21293    fn test_string_size_with_expanded_tabs() {
21294        let nz = |val| NonZeroU32::new(val).unwrap();
21295        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21296        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21297        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21298        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21299        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21300        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21301        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21302        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21303    }
21304}
21305
21306/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21307struct WordBreakingTokenizer<'a> {
21308    input: &'a str,
21309}
21310
21311impl<'a> WordBreakingTokenizer<'a> {
21312    fn new(input: &'a str) -> Self {
21313        Self { input }
21314    }
21315}
21316
21317fn is_char_ideographic(ch: char) -> bool {
21318    use unicode_script::Script::*;
21319    use unicode_script::UnicodeScript;
21320    matches!(ch.script(), Han | Tangut | Yi)
21321}
21322
21323fn is_grapheme_ideographic(text: &str) -> bool {
21324    text.chars().any(is_char_ideographic)
21325}
21326
21327fn is_grapheme_whitespace(text: &str) -> bool {
21328    text.chars().any(|x| x.is_whitespace())
21329}
21330
21331fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21332    text.chars().next().map_or(false, |ch| {
21333        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21334    })
21335}
21336
21337#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21338enum WordBreakToken<'a> {
21339    Word { token: &'a str, grapheme_len: usize },
21340    InlineWhitespace { token: &'a str, grapheme_len: usize },
21341    Newline,
21342}
21343
21344impl<'a> Iterator for WordBreakingTokenizer<'a> {
21345    /// Yields a span, the count of graphemes in the token, and whether it was
21346    /// whitespace. Note that it also breaks at word boundaries.
21347    type Item = WordBreakToken<'a>;
21348
21349    fn next(&mut self) -> Option<Self::Item> {
21350        use unicode_segmentation::UnicodeSegmentation;
21351        if self.input.is_empty() {
21352            return None;
21353        }
21354
21355        let mut iter = self.input.graphemes(true).peekable();
21356        let mut offset = 0;
21357        let mut grapheme_len = 0;
21358        if let Some(first_grapheme) = iter.next() {
21359            let is_newline = first_grapheme == "\n";
21360            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21361            offset += first_grapheme.len();
21362            grapheme_len += 1;
21363            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21364                if let Some(grapheme) = iter.peek().copied() {
21365                    if should_stay_with_preceding_ideograph(grapheme) {
21366                        offset += grapheme.len();
21367                        grapheme_len += 1;
21368                    }
21369                }
21370            } else {
21371                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21372                let mut next_word_bound = words.peek().copied();
21373                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21374                    next_word_bound = words.next();
21375                }
21376                while let Some(grapheme) = iter.peek().copied() {
21377                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21378                        break;
21379                    };
21380                    if is_grapheme_whitespace(grapheme) != is_whitespace
21381                        || (grapheme == "\n") != is_newline
21382                    {
21383                        break;
21384                    };
21385                    offset += grapheme.len();
21386                    grapheme_len += 1;
21387                    iter.next();
21388                }
21389            }
21390            let token = &self.input[..offset];
21391            self.input = &self.input[offset..];
21392            if token == "\n" {
21393                Some(WordBreakToken::Newline)
21394            } else if is_whitespace {
21395                Some(WordBreakToken::InlineWhitespace {
21396                    token,
21397                    grapheme_len,
21398                })
21399            } else {
21400                Some(WordBreakToken::Word {
21401                    token,
21402                    grapheme_len,
21403                })
21404            }
21405        } else {
21406            None
21407        }
21408    }
21409}
21410
21411#[test]
21412fn test_word_breaking_tokenizer() {
21413    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21414        ("", &[]),
21415        ("  ", &[whitespace("  ", 2)]),
21416        ("Ʒ", &[word("Ʒ", 1)]),
21417        ("Ǽ", &[word("Ǽ", 1)]),
21418        ("", &[word("", 1)]),
21419        ("⋑⋑", &[word("⋑⋑", 2)]),
21420        (
21421            "原理,进而",
21422            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21423        ),
21424        (
21425            "hello world",
21426            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21427        ),
21428        (
21429            "hello, world",
21430            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21431        ),
21432        (
21433            "  hello world",
21434            &[
21435                whitespace("  ", 2),
21436                word("hello", 5),
21437                whitespace(" ", 1),
21438                word("world", 5),
21439            ],
21440        ),
21441        (
21442            "这是什么 \n 钢笔",
21443            &[
21444                word("", 1),
21445                word("", 1),
21446                word("", 1),
21447                word("", 1),
21448                whitespace(" ", 1),
21449                newline(),
21450                whitespace(" ", 1),
21451                word("", 1),
21452                word("", 1),
21453            ],
21454        ),
21455        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21456    ];
21457
21458    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21459        WordBreakToken::Word {
21460            token,
21461            grapheme_len,
21462        }
21463    }
21464
21465    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21466        WordBreakToken::InlineWhitespace {
21467            token,
21468            grapheme_len,
21469        }
21470    }
21471
21472    fn newline() -> WordBreakToken<'static> {
21473        WordBreakToken::Newline
21474    }
21475
21476    for (input, result) in tests {
21477        assert_eq!(
21478            WordBreakingTokenizer::new(input)
21479                .collect::<Vec<_>>()
21480                .as_slice(),
21481            *result,
21482        );
21483    }
21484}
21485
21486fn wrap_with_prefix(
21487    first_line_prefix: String,
21488    subsequent_lines_prefix: String,
21489    unwrapped_text: String,
21490    wrap_column: usize,
21491    tab_size: NonZeroU32,
21492    preserve_existing_whitespace: bool,
21493) -> String {
21494    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21495    let subsequent_lines_prefix_len =
21496        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21497    let mut wrapped_text = String::new();
21498    let mut current_line = first_line_prefix.clone();
21499    let mut is_first_line = true;
21500
21501    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21502    let mut current_line_len = first_line_prefix_len;
21503    let mut in_whitespace = false;
21504    for token in tokenizer {
21505        let have_preceding_whitespace = in_whitespace;
21506        match token {
21507            WordBreakToken::Word {
21508                token,
21509                grapheme_len,
21510            } => {
21511                in_whitespace = false;
21512                let current_prefix_len = if is_first_line {
21513                    first_line_prefix_len
21514                } else {
21515                    subsequent_lines_prefix_len
21516                };
21517                if current_line_len + grapheme_len > wrap_column
21518                    && current_line_len != current_prefix_len
21519                {
21520                    wrapped_text.push_str(current_line.trim_end());
21521                    wrapped_text.push('\n');
21522                    is_first_line = false;
21523                    current_line = subsequent_lines_prefix.clone();
21524                    current_line_len = subsequent_lines_prefix_len;
21525                }
21526                current_line.push_str(token);
21527                current_line_len += grapheme_len;
21528            }
21529            WordBreakToken::InlineWhitespace {
21530                mut token,
21531                mut grapheme_len,
21532            } => {
21533                in_whitespace = true;
21534                if have_preceding_whitespace && !preserve_existing_whitespace {
21535                    continue;
21536                }
21537                if !preserve_existing_whitespace {
21538                    token = " ";
21539                    grapheme_len = 1;
21540                }
21541                let current_prefix_len = if is_first_line {
21542                    first_line_prefix_len
21543                } else {
21544                    subsequent_lines_prefix_len
21545                };
21546                if current_line_len + grapheme_len > wrap_column {
21547                    wrapped_text.push_str(current_line.trim_end());
21548                    wrapped_text.push('\n');
21549                    is_first_line = false;
21550                    current_line = subsequent_lines_prefix.clone();
21551                    current_line_len = subsequent_lines_prefix_len;
21552                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21553                    current_line.push_str(token);
21554                    current_line_len += grapheme_len;
21555                }
21556            }
21557            WordBreakToken::Newline => {
21558                in_whitespace = true;
21559                let current_prefix_len = if is_first_line {
21560                    first_line_prefix_len
21561                } else {
21562                    subsequent_lines_prefix_len
21563                };
21564                if preserve_existing_whitespace {
21565                    wrapped_text.push_str(current_line.trim_end());
21566                    wrapped_text.push('\n');
21567                    is_first_line = false;
21568                    current_line = subsequent_lines_prefix.clone();
21569                    current_line_len = subsequent_lines_prefix_len;
21570                } else if have_preceding_whitespace {
21571                    continue;
21572                } else if current_line_len + 1 > wrap_column
21573                    && current_line_len != current_prefix_len
21574                {
21575                    wrapped_text.push_str(current_line.trim_end());
21576                    wrapped_text.push('\n');
21577                    is_first_line = false;
21578                    current_line = subsequent_lines_prefix.clone();
21579                    current_line_len = subsequent_lines_prefix_len;
21580                } else if current_line_len != current_prefix_len {
21581                    current_line.push(' ');
21582                    current_line_len += 1;
21583                }
21584            }
21585        }
21586    }
21587
21588    if !current_line.is_empty() {
21589        wrapped_text.push_str(&current_line);
21590    }
21591    wrapped_text
21592}
21593
21594#[test]
21595fn test_wrap_with_prefix() {
21596    assert_eq!(
21597        wrap_with_prefix(
21598            "# ".to_string(),
21599            "# ".to_string(),
21600            "abcdefg".to_string(),
21601            4,
21602            NonZeroU32::new(4).unwrap(),
21603            false,
21604        ),
21605        "# abcdefg"
21606    );
21607    assert_eq!(
21608        wrap_with_prefix(
21609            "".to_string(),
21610            "".to_string(),
21611            "\thello world".to_string(),
21612            8,
21613            NonZeroU32::new(4).unwrap(),
21614            false,
21615        ),
21616        "hello\nworld"
21617    );
21618    assert_eq!(
21619        wrap_with_prefix(
21620            "// ".to_string(),
21621            "// ".to_string(),
21622            "xx \nyy zz aa bb cc".to_string(),
21623            12,
21624            NonZeroU32::new(4).unwrap(),
21625            false,
21626        ),
21627        "// xx yy zz\n// aa bb cc"
21628    );
21629    assert_eq!(
21630        wrap_with_prefix(
21631            String::new(),
21632            String::new(),
21633            "这是什么 \n 钢笔".to_string(),
21634            3,
21635            NonZeroU32::new(4).unwrap(),
21636            false,
21637        ),
21638        "这是什\n么 钢\n"
21639    );
21640}
21641
21642pub trait CollaborationHub {
21643    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21644    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21645    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21646}
21647
21648impl CollaborationHub for Entity<Project> {
21649    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21650        self.read(cx).collaborators()
21651    }
21652
21653    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21654        self.read(cx).user_store().read(cx).participant_indices()
21655    }
21656
21657    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21658        let this = self.read(cx);
21659        let user_ids = this.collaborators().values().map(|c| c.user_id);
21660        this.user_store().read(cx).participant_names(user_ids, cx)
21661    }
21662}
21663
21664pub trait SemanticsProvider {
21665    fn hover(
21666        &self,
21667        buffer: &Entity<Buffer>,
21668        position: text::Anchor,
21669        cx: &mut App,
21670    ) -> Option<Task<Vec<project::Hover>>>;
21671
21672    fn inline_values(
21673        &self,
21674        buffer_handle: Entity<Buffer>,
21675        range: Range<text::Anchor>,
21676        cx: &mut App,
21677    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21678
21679    fn inlay_hints(
21680        &self,
21681        buffer_handle: Entity<Buffer>,
21682        range: Range<text::Anchor>,
21683        cx: &mut App,
21684    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21685
21686    fn resolve_inlay_hint(
21687        &self,
21688        hint: InlayHint,
21689        buffer_handle: Entity<Buffer>,
21690        server_id: LanguageServerId,
21691        cx: &mut App,
21692    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21693
21694    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21695
21696    fn document_highlights(
21697        &self,
21698        buffer: &Entity<Buffer>,
21699        position: text::Anchor,
21700        cx: &mut App,
21701    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21702
21703    fn definitions(
21704        &self,
21705        buffer: &Entity<Buffer>,
21706        position: text::Anchor,
21707        kind: GotoDefinitionKind,
21708        cx: &mut App,
21709    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21710
21711    fn range_for_rename(
21712        &self,
21713        buffer: &Entity<Buffer>,
21714        position: text::Anchor,
21715        cx: &mut App,
21716    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21717
21718    fn perform_rename(
21719        &self,
21720        buffer: &Entity<Buffer>,
21721        position: text::Anchor,
21722        new_name: String,
21723        cx: &mut App,
21724    ) -> Option<Task<Result<ProjectTransaction>>>;
21725}
21726
21727pub trait CompletionProvider {
21728    fn completions(
21729        &self,
21730        excerpt_id: ExcerptId,
21731        buffer: &Entity<Buffer>,
21732        buffer_position: text::Anchor,
21733        trigger: CompletionContext,
21734        window: &mut Window,
21735        cx: &mut Context<Editor>,
21736    ) -> Task<Result<Vec<CompletionResponse>>>;
21737
21738    fn resolve_completions(
21739        &self,
21740        _buffer: Entity<Buffer>,
21741        _completion_indices: Vec<usize>,
21742        _completions: Rc<RefCell<Box<[Completion]>>>,
21743        _cx: &mut Context<Editor>,
21744    ) -> Task<Result<bool>> {
21745        Task::ready(Ok(false))
21746    }
21747
21748    fn apply_additional_edits_for_completion(
21749        &self,
21750        _buffer: Entity<Buffer>,
21751        _completions: Rc<RefCell<Box<[Completion]>>>,
21752        _completion_index: usize,
21753        _push_to_history: bool,
21754        _cx: &mut Context<Editor>,
21755    ) -> Task<Result<Option<language::Transaction>>> {
21756        Task::ready(Ok(None))
21757    }
21758
21759    fn is_completion_trigger(
21760        &self,
21761        buffer: &Entity<Buffer>,
21762        position: language::Anchor,
21763        text: &str,
21764        trigger_in_words: bool,
21765        menu_is_open: bool,
21766        cx: &mut Context<Editor>,
21767    ) -> bool;
21768
21769    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21770
21771    fn sort_completions(&self) -> bool {
21772        true
21773    }
21774
21775    fn filter_completions(&self) -> bool {
21776        true
21777    }
21778}
21779
21780pub trait CodeActionProvider {
21781    fn id(&self) -> Arc<str>;
21782
21783    fn code_actions(
21784        &self,
21785        buffer: &Entity<Buffer>,
21786        range: Range<text::Anchor>,
21787        window: &mut Window,
21788        cx: &mut App,
21789    ) -> Task<Result<Vec<CodeAction>>>;
21790
21791    fn apply_code_action(
21792        &self,
21793        buffer_handle: Entity<Buffer>,
21794        action: CodeAction,
21795        excerpt_id: ExcerptId,
21796        push_to_history: bool,
21797        window: &mut Window,
21798        cx: &mut App,
21799    ) -> Task<Result<ProjectTransaction>>;
21800}
21801
21802impl CodeActionProvider for Entity<Project> {
21803    fn id(&self) -> Arc<str> {
21804        "project".into()
21805    }
21806
21807    fn code_actions(
21808        &self,
21809        buffer: &Entity<Buffer>,
21810        range: Range<text::Anchor>,
21811        _window: &mut Window,
21812        cx: &mut App,
21813    ) -> Task<Result<Vec<CodeAction>>> {
21814        self.update(cx, |project, cx| {
21815            let code_lens = project.code_lens(buffer, range.clone(), cx);
21816            let code_actions = project.code_actions(buffer, range, None, cx);
21817            cx.background_spawn(async move {
21818                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21819                Ok(code_lens
21820                    .context("code lens fetch")?
21821                    .into_iter()
21822                    .chain(code_actions.context("code action fetch")?)
21823                    .collect())
21824            })
21825        })
21826    }
21827
21828    fn apply_code_action(
21829        &self,
21830        buffer_handle: Entity<Buffer>,
21831        action: CodeAction,
21832        _excerpt_id: ExcerptId,
21833        push_to_history: bool,
21834        _window: &mut Window,
21835        cx: &mut App,
21836    ) -> Task<Result<ProjectTransaction>> {
21837        self.update(cx, |project, cx| {
21838            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21839        })
21840    }
21841}
21842
21843fn snippet_completions(
21844    project: &Project,
21845    buffer: &Entity<Buffer>,
21846    buffer_position: text::Anchor,
21847    cx: &mut App,
21848) -> Task<Result<CompletionResponse>> {
21849    let languages = buffer.read(cx).languages_at(buffer_position);
21850    let snippet_store = project.snippets().read(cx);
21851
21852    let scopes: Vec<_> = languages
21853        .iter()
21854        .filter_map(|language| {
21855            let language_name = language.lsp_id();
21856            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21857
21858            if snippets.is_empty() {
21859                None
21860            } else {
21861                Some((language.default_scope(), snippets))
21862            }
21863        })
21864        .collect();
21865
21866    if scopes.is_empty() {
21867        return Task::ready(Ok(CompletionResponse {
21868            completions: vec![],
21869            is_incomplete: false,
21870        }));
21871    }
21872
21873    let snapshot = buffer.read(cx).text_snapshot();
21874    let chars: String = snapshot
21875        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21876        .collect();
21877    let executor = cx.background_executor().clone();
21878
21879    cx.background_spawn(async move {
21880        let mut is_incomplete = false;
21881        let mut completions: Vec<Completion> = Vec::new();
21882        for (scope, snippets) in scopes.into_iter() {
21883            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21884            let mut last_word = chars
21885                .chars()
21886                .take_while(|c| classifier.is_word(*c))
21887                .collect::<String>();
21888            last_word = last_word.chars().rev().collect();
21889
21890            if last_word.is_empty() {
21891                return Ok(CompletionResponse {
21892                    completions: vec![],
21893                    is_incomplete: true,
21894                });
21895            }
21896
21897            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21898            let to_lsp = |point: &text::Anchor| {
21899                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21900                point_to_lsp(end)
21901            };
21902            let lsp_end = to_lsp(&buffer_position);
21903
21904            let candidates = snippets
21905                .iter()
21906                .enumerate()
21907                .flat_map(|(ix, snippet)| {
21908                    snippet
21909                        .prefix
21910                        .iter()
21911                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21912                })
21913                .collect::<Vec<StringMatchCandidate>>();
21914
21915            const MAX_RESULTS: usize = 100;
21916            let mut matches = fuzzy::match_strings(
21917                &candidates,
21918                &last_word,
21919                last_word.chars().any(|c| c.is_uppercase()),
21920                true,
21921                MAX_RESULTS,
21922                &Default::default(),
21923                executor.clone(),
21924            )
21925            .await;
21926
21927            if matches.len() >= MAX_RESULTS {
21928                is_incomplete = true;
21929            }
21930
21931            // Remove all candidates where the query's start does not match the start of any word in the candidate
21932            if let Some(query_start) = last_word.chars().next() {
21933                matches.retain(|string_match| {
21934                    split_words(&string_match.string).any(|word| {
21935                        // Check that the first codepoint of the word as lowercase matches the first
21936                        // codepoint of the query as lowercase
21937                        word.chars()
21938                            .flat_map(|codepoint| codepoint.to_lowercase())
21939                            .zip(query_start.to_lowercase())
21940                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21941                    })
21942                });
21943            }
21944
21945            let matched_strings = matches
21946                .into_iter()
21947                .map(|m| m.string)
21948                .collect::<HashSet<_>>();
21949
21950            completions.extend(snippets.iter().filter_map(|snippet| {
21951                let matching_prefix = snippet
21952                    .prefix
21953                    .iter()
21954                    .find(|prefix| matched_strings.contains(*prefix))?;
21955                let start = as_offset - last_word.len();
21956                let start = snapshot.anchor_before(start);
21957                let range = start..buffer_position;
21958                let lsp_start = to_lsp(&start);
21959                let lsp_range = lsp::Range {
21960                    start: lsp_start,
21961                    end: lsp_end,
21962                };
21963                Some(Completion {
21964                    replace_range: range,
21965                    new_text: snippet.body.clone(),
21966                    source: CompletionSource::Lsp {
21967                        insert_range: None,
21968                        server_id: LanguageServerId(usize::MAX),
21969                        resolved: true,
21970                        lsp_completion: Box::new(lsp::CompletionItem {
21971                            label: snippet.prefix.first().unwrap().clone(),
21972                            kind: Some(CompletionItemKind::SNIPPET),
21973                            label_details: snippet.description.as_ref().map(|description| {
21974                                lsp::CompletionItemLabelDetails {
21975                                    detail: Some(description.clone()),
21976                                    description: None,
21977                                }
21978                            }),
21979                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21980                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21981                                lsp::InsertReplaceEdit {
21982                                    new_text: snippet.body.clone(),
21983                                    insert: lsp_range,
21984                                    replace: lsp_range,
21985                                },
21986                            )),
21987                            filter_text: Some(snippet.body.clone()),
21988                            sort_text: Some(char::MAX.to_string()),
21989                            ..lsp::CompletionItem::default()
21990                        }),
21991                        lsp_defaults: None,
21992                    },
21993                    label: CodeLabel {
21994                        text: matching_prefix.clone(),
21995                        runs: Vec::new(),
21996                        filter_range: 0..matching_prefix.len(),
21997                    },
21998                    icon_path: None,
21999                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22000                        single_line: snippet.name.clone().into(),
22001                        plain_text: snippet
22002                            .description
22003                            .clone()
22004                            .map(|description| description.into()),
22005                    }),
22006                    insert_text_mode: None,
22007                    confirm: None,
22008                })
22009            }))
22010        }
22011
22012        Ok(CompletionResponse {
22013            completions,
22014            is_incomplete,
22015        })
22016    })
22017}
22018
22019impl CompletionProvider for Entity<Project> {
22020    fn completions(
22021        &self,
22022        _excerpt_id: ExcerptId,
22023        buffer: &Entity<Buffer>,
22024        buffer_position: text::Anchor,
22025        options: CompletionContext,
22026        _window: &mut Window,
22027        cx: &mut Context<Editor>,
22028    ) -> Task<Result<Vec<CompletionResponse>>> {
22029        self.update(cx, |project, cx| {
22030            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22031            let project_completions = project.completions(buffer, buffer_position, options, cx);
22032            cx.background_spawn(async move {
22033                let mut responses = project_completions.await?;
22034                let snippets = snippets.await?;
22035                if !snippets.completions.is_empty() {
22036                    responses.push(snippets);
22037                }
22038                Ok(responses)
22039            })
22040        })
22041    }
22042
22043    fn resolve_completions(
22044        &self,
22045        buffer: Entity<Buffer>,
22046        completion_indices: Vec<usize>,
22047        completions: Rc<RefCell<Box<[Completion]>>>,
22048        cx: &mut Context<Editor>,
22049    ) -> Task<Result<bool>> {
22050        self.update(cx, |project, cx| {
22051            project.lsp_store().update(cx, |lsp_store, cx| {
22052                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22053            })
22054        })
22055    }
22056
22057    fn apply_additional_edits_for_completion(
22058        &self,
22059        buffer: Entity<Buffer>,
22060        completions: Rc<RefCell<Box<[Completion]>>>,
22061        completion_index: usize,
22062        push_to_history: bool,
22063        cx: &mut Context<Editor>,
22064    ) -> Task<Result<Option<language::Transaction>>> {
22065        self.update(cx, |project, cx| {
22066            project.lsp_store().update(cx, |lsp_store, cx| {
22067                lsp_store.apply_additional_edits_for_completion(
22068                    buffer,
22069                    completions,
22070                    completion_index,
22071                    push_to_history,
22072                    cx,
22073                )
22074            })
22075        })
22076    }
22077
22078    fn is_completion_trigger(
22079        &self,
22080        buffer: &Entity<Buffer>,
22081        position: language::Anchor,
22082        text: &str,
22083        trigger_in_words: bool,
22084        menu_is_open: bool,
22085        cx: &mut Context<Editor>,
22086    ) -> bool {
22087        let mut chars = text.chars();
22088        let char = if let Some(char) = chars.next() {
22089            char
22090        } else {
22091            return false;
22092        };
22093        if chars.next().is_some() {
22094            return false;
22095        }
22096
22097        let buffer = buffer.read(cx);
22098        let snapshot = buffer.snapshot();
22099        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22100            return false;
22101        }
22102        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22103        if trigger_in_words && classifier.is_word(char) {
22104            return true;
22105        }
22106
22107        buffer.completion_triggers().contains(text)
22108    }
22109}
22110
22111impl SemanticsProvider for Entity<Project> {
22112    fn hover(
22113        &self,
22114        buffer: &Entity<Buffer>,
22115        position: text::Anchor,
22116        cx: &mut App,
22117    ) -> Option<Task<Vec<project::Hover>>> {
22118        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22119    }
22120
22121    fn document_highlights(
22122        &self,
22123        buffer: &Entity<Buffer>,
22124        position: text::Anchor,
22125        cx: &mut App,
22126    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22127        Some(self.update(cx, |project, cx| {
22128            project.document_highlights(buffer, position, cx)
22129        }))
22130    }
22131
22132    fn definitions(
22133        &self,
22134        buffer: &Entity<Buffer>,
22135        position: text::Anchor,
22136        kind: GotoDefinitionKind,
22137        cx: &mut App,
22138    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22139        Some(self.update(cx, |project, cx| match kind {
22140            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22141            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22142            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22143            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22144        }))
22145    }
22146
22147    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22148        // TODO: make this work for remote projects
22149        self.update(cx, |project, cx| {
22150            if project
22151                .active_debug_session(cx)
22152                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22153            {
22154                return true;
22155            }
22156
22157            buffer.update(cx, |buffer, cx| {
22158                project.any_language_server_supports_inlay_hints(buffer, cx)
22159            })
22160        })
22161    }
22162
22163    fn inline_values(
22164        &self,
22165        buffer_handle: Entity<Buffer>,
22166        range: Range<text::Anchor>,
22167        cx: &mut App,
22168    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22169        self.update(cx, |project, cx| {
22170            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22171
22172            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22173        })
22174    }
22175
22176    fn inlay_hints(
22177        &self,
22178        buffer_handle: Entity<Buffer>,
22179        range: Range<text::Anchor>,
22180        cx: &mut App,
22181    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22182        Some(self.update(cx, |project, cx| {
22183            project.inlay_hints(buffer_handle, range, cx)
22184        }))
22185    }
22186
22187    fn resolve_inlay_hint(
22188        &self,
22189        hint: InlayHint,
22190        buffer_handle: Entity<Buffer>,
22191        server_id: LanguageServerId,
22192        cx: &mut App,
22193    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22194        Some(self.update(cx, |project, cx| {
22195            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22196        }))
22197    }
22198
22199    fn range_for_rename(
22200        &self,
22201        buffer: &Entity<Buffer>,
22202        position: text::Anchor,
22203        cx: &mut App,
22204    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22205        Some(self.update(cx, |project, cx| {
22206            let buffer = buffer.clone();
22207            let task = project.prepare_rename(buffer.clone(), position, cx);
22208            cx.spawn(async move |_, cx| {
22209                Ok(match task.await? {
22210                    PrepareRenameResponse::Success(range) => Some(range),
22211                    PrepareRenameResponse::InvalidPosition => None,
22212                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22213                        // Fallback on using TreeSitter info to determine identifier range
22214                        buffer.read_with(cx, |buffer, _| {
22215                            let snapshot = buffer.snapshot();
22216                            let (range, kind) = snapshot.surrounding_word(position, false);
22217                            if kind != Some(CharKind::Word) {
22218                                return None;
22219                            }
22220                            Some(
22221                                snapshot.anchor_before(range.start)
22222                                    ..snapshot.anchor_after(range.end),
22223                            )
22224                        })?
22225                    }
22226                })
22227            })
22228        }))
22229    }
22230
22231    fn perform_rename(
22232        &self,
22233        buffer: &Entity<Buffer>,
22234        position: text::Anchor,
22235        new_name: String,
22236        cx: &mut App,
22237    ) -> Option<Task<Result<ProjectTransaction>>> {
22238        Some(self.update(cx, |project, cx| {
22239            project.perform_rename(buffer.clone(), position, new_name, cx)
22240        }))
22241    }
22242}
22243
22244fn inlay_hint_settings(
22245    location: Anchor,
22246    snapshot: &MultiBufferSnapshot,
22247    cx: &mut Context<Editor>,
22248) -> InlayHintSettings {
22249    let file = snapshot.file_at(location);
22250    let language = snapshot.language_at(location).map(|l| l.name());
22251    language_settings(language, file, cx).inlay_hints
22252}
22253
22254fn consume_contiguous_rows(
22255    contiguous_row_selections: &mut Vec<Selection<Point>>,
22256    selection: &Selection<Point>,
22257    display_map: &DisplaySnapshot,
22258    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22259) -> (MultiBufferRow, MultiBufferRow) {
22260    contiguous_row_selections.push(selection.clone());
22261    let start_row = MultiBufferRow(selection.start.row);
22262    let mut end_row = ending_row(selection, display_map);
22263
22264    while let Some(next_selection) = selections.peek() {
22265        if next_selection.start.row <= end_row.0 {
22266            end_row = ending_row(next_selection, display_map);
22267            contiguous_row_selections.push(selections.next().unwrap().clone());
22268        } else {
22269            break;
22270        }
22271    }
22272    (start_row, end_row)
22273}
22274
22275fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22276    if next_selection.end.column > 0 || next_selection.is_empty() {
22277        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22278    } else {
22279        MultiBufferRow(next_selection.end.row)
22280    }
22281}
22282
22283impl EditorSnapshot {
22284    pub fn remote_selections_in_range<'a>(
22285        &'a self,
22286        range: &'a Range<Anchor>,
22287        collaboration_hub: &dyn CollaborationHub,
22288        cx: &'a App,
22289    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22290        let participant_names = collaboration_hub.user_names(cx);
22291        let participant_indices = collaboration_hub.user_participant_indices(cx);
22292        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22293        let collaborators_by_replica_id = collaborators_by_peer_id
22294            .values()
22295            .map(|collaborator| (collaborator.replica_id, collaborator))
22296            .collect::<HashMap<_, _>>();
22297        self.buffer_snapshot
22298            .selections_in_range(range, false)
22299            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22300                if replica_id == AGENT_REPLICA_ID {
22301                    Some(RemoteSelection {
22302                        replica_id,
22303                        selection,
22304                        cursor_shape,
22305                        line_mode,
22306                        collaborator_id: CollaboratorId::Agent,
22307                        user_name: Some("Agent".into()),
22308                        color: cx.theme().players().agent(),
22309                    })
22310                } else {
22311                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22312                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22313                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22314                    Some(RemoteSelection {
22315                        replica_id,
22316                        selection,
22317                        cursor_shape,
22318                        line_mode,
22319                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22320                        user_name,
22321                        color: if let Some(index) = participant_index {
22322                            cx.theme().players().color_for_participant(index.0)
22323                        } else {
22324                            cx.theme().players().absent()
22325                        },
22326                    })
22327                }
22328            })
22329    }
22330
22331    pub fn hunks_for_ranges(
22332        &self,
22333        ranges: impl IntoIterator<Item = Range<Point>>,
22334    ) -> Vec<MultiBufferDiffHunk> {
22335        let mut hunks = Vec::new();
22336        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22337            HashMap::default();
22338        for query_range in ranges {
22339            let query_rows =
22340                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22341            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22342                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22343            ) {
22344                // Include deleted hunks that are adjacent to the query range, because
22345                // otherwise they would be missed.
22346                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22347                if hunk.status().is_deleted() {
22348                    intersects_range |= hunk.row_range.start == query_rows.end;
22349                    intersects_range |= hunk.row_range.end == query_rows.start;
22350                }
22351                if intersects_range {
22352                    if !processed_buffer_rows
22353                        .entry(hunk.buffer_id)
22354                        .or_default()
22355                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22356                    {
22357                        continue;
22358                    }
22359                    hunks.push(hunk);
22360                }
22361            }
22362        }
22363
22364        hunks
22365    }
22366
22367    fn display_diff_hunks_for_rows<'a>(
22368        &'a self,
22369        display_rows: Range<DisplayRow>,
22370        folded_buffers: &'a HashSet<BufferId>,
22371    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22372        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22373        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22374
22375        self.buffer_snapshot
22376            .diff_hunks_in_range(buffer_start..buffer_end)
22377            .filter_map(|hunk| {
22378                if folded_buffers.contains(&hunk.buffer_id) {
22379                    return None;
22380                }
22381
22382                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22383                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22384
22385                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22386                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22387
22388                let display_hunk = if hunk_display_start.column() != 0 {
22389                    DisplayDiffHunk::Folded {
22390                        display_row: hunk_display_start.row(),
22391                    }
22392                } else {
22393                    let mut end_row = hunk_display_end.row();
22394                    if hunk_display_end.column() > 0 {
22395                        end_row.0 += 1;
22396                    }
22397                    let is_created_file = hunk.is_created_file();
22398                    DisplayDiffHunk::Unfolded {
22399                        status: hunk.status(),
22400                        diff_base_byte_range: hunk.diff_base_byte_range,
22401                        display_row_range: hunk_display_start.row()..end_row,
22402                        multi_buffer_range: Anchor::range_in_buffer(
22403                            hunk.excerpt_id,
22404                            hunk.buffer_id,
22405                            hunk.buffer_range,
22406                        ),
22407                        is_created_file,
22408                    }
22409                };
22410
22411                Some(display_hunk)
22412            })
22413    }
22414
22415    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22416        self.display_snapshot.buffer_snapshot.language_at(position)
22417    }
22418
22419    pub fn is_focused(&self) -> bool {
22420        self.is_focused
22421    }
22422
22423    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22424        self.placeholder_text.as_ref()
22425    }
22426
22427    pub fn scroll_position(&self) -> gpui::Point<f32> {
22428        self.scroll_anchor.scroll_position(&self.display_snapshot)
22429    }
22430
22431    fn gutter_dimensions(
22432        &self,
22433        font_id: FontId,
22434        font_size: Pixels,
22435        max_line_number_width: Pixels,
22436        cx: &App,
22437    ) -> Option<GutterDimensions> {
22438        if !self.show_gutter {
22439            return None;
22440        }
22441
22442        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22443        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22444
22445        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22446            matches!(
22447                ProjectSettings::get_global(cx).git.git_gutter,
22448                Some(GitGutterSetting::TrackedFiles)
22449            )
22450        });
22451        let gutter_settings = EditorSettings::get_global(cx).gutter;
22452        let show_line_numbers = self
22453            .show_line_numbers
22454            .unwrap_or(gutter_settings.line_numbers);
22455        let line_gutter_width = if show_line_numbers {
22456            // Avoid flicker-like gutter resizes when the line number gains another digit by
22457            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22458            let min_width_for_number_on_gutter =
22459                ch_advance * gutter_settings.min_line_number_digits as f32;
22460            max_line_number_width.max(min_width_for_number_on_gutter)
22461        } else {
22462            0.0.into()
22463        };
22464
22465        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22466        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22467
22468        let git_blame_entries_width =
22469            self.git_blame_gutter_max_author_length
22470                .map(|max_author_length| {
22471                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22472                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22473
22474                    /// The number of characters to dedicate to gaps and margins.
22475                    const SPACING_WIDTH: usize = 4;
22476
22477                    let max_char_count = max_author_length.min(renderer.max_author_length())
22478                        + ::git::SHORT_SHA_LENGTH
22479                        + MAX_RELATIVE_TIMESTAMP.len()
22480                        + SPACING_WIDTH;
22481
22482                    ch_advance * max_char_count
22483                });
22484
22485        let is_singleton = self.buffer_snapshot.is_singleton();
22486
22487        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22488        left_padding += if !is_singleton {
22489            ch_width * 4.0
22490        } else if show_runnables || show_breakpoints {
22491            ch_width * 3.0
22492        } else if show_git_gutter && show_line_numbers {
22493            ch_width * 2.0
22494        } else if show_git_gutter || show_line_numbers {
22495            ch_width
22496        } else {
22497            px(0.)
22498        };
22499
22500        let shows_folds = is_singleton && gutter_settings.folds;
22501
22502        let right_padding = if shows_folds && show_line_numbers {
22503            ch_width * 4.0
22504        } else if shows_folds || (!is_singleton && show_line_numbers) {
22505            ch_width * 3.0
22506        } else if show_line_numbers {
22507            ch_width
22508        } else {
22509            px(0.)
22510        };
22511
22512        Some(GutterDimensions {
22513            left_padding,
22514            right_padding,
22515            width: line_gutter_width + left_padding + right_padding,
22516            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22517            git_blame_entries_width,
22518        })
22519    }
22520
22521    pub fn render_crease_toggle(
22522        &self,
22523        buffer_row: MultiBufferRow,
22524        row_contains_cursor: bool,
22525        editor: Entity<Editor>,
22526        window: &mut Window,
22527        cx: &mut App,
22528    ) -> Option<AnyElement> {
22529        let folded = self.is_line_folded(buffer_row);
22530        let mut is_foldable = false;
22531
22532        if let Some(crease) = self
22533            .crease_snapshot
22534            .query_row(buffer_row, &self.buffer_snapshot)
22535        {
22536            is_foldable = true;
22537            match crease {
22538                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22539                    if let Some(render_toggle) = render_toggle {
22540                        let toggle_callback =
22541                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22542                                if folded {
22543                                    editor.update(cx, |editor, cx| {
22544                                        editor.fold_at(buffer_row, window, cx)
22545                                    });
22546                                } else {
22547                                    editor.update(cx, |editor, cx| {
22548                                        editor.unfold_at(buffer_row, window, cx)
22549                                    });
22550                                }
22551                            });
22552                        return Some((render_toggle)(
22553                            buffer_row,
22554                            folded,
22555                            toggle_callback,
22556                            window,
22557                            cx,
22558                        ));
22559                    }
22560                }
22561            }
22562        }
22563
22564        is_foldable |= self.starts_indent(buffer_row);
22565
22566        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22567            Some(
22568                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22569                    .toggle_state(folded)
22570                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22571                        if folded {
22572                            this.unfold_at(buffer_row, window, cx);
22573                        } else {
22574                            this.fold_at(buffer_row, window, cx);
22575                        }
22576                    }))
22577                    .into_any_element(),
22578            )
22579        } else {
22580            None
22581        }
22582    }
22583
22584    pub fn render_crease_trailer(
22585        &self,
22586        buffer_row: MultiBufferRow,
22587        window: &mut Window,
22588        cx: &mut App,
22589    ) -> Option<AnyElement> {
22590        let folded = self.is_line_folded(buffer_row);
22591        if let Crease::Inline { render_trailer, .. } = self
22592            .crease_snapshot
22593            .query_row(buffer_row, &self.buffer_snapshot)?
22594        {
22595            let render_trailer = render_trailer.as_ref()?;
22596            Some(render_trailer(buffer_row, folded, window, cx))
22597        } else {
22598            None
22599        }
22600    }
22601}
22602
22603impl Deref for EditorSnapshot {
22604    type Target = DisplaySnapshot;
22605
22606    fn deref(&self) -> &Self::Target {
22607        &self.display_snapshot
22608    }
22609}
22610
22611#[derive(Clone, Debug, PartialEq, Eq)]
22612pub enum EditorEvent {
22613    InputIgnored {
22614        text: Arc<str>,
22615    },
22616    InputHandled {
22617        utf16_range_to_replace: Option<Range<isize>>,
22618        text: Arc<str>,
22619    },
22620    ExcerptsAdded {
22621        buffer: Entity<Buffer>,
22622        predecessor: ExcerptId,
22623        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22624    },
22625    ExcerptsRemoved {
22626        ids: Vec<ExcerptId>,
22627        removed_buffer_ids: Vec<BufferId>,
22628    },
22629    BufferFoldToggled {
22630        ids: Vec<ExcerptId>,
22631        folded: bool,
22632    },
22633    ExcerptsEdited {
22634        ids: Vec<ExcerptId>,
22635    },
22636    ExcerptsExpanded {
22637        ids: Vec<ExcerptId>,
22638    },
22639    BufferEdited,
22640    Edited {
22641        transaction_id: clock::Lamport,
22642    },
22643    Reparsed(BufferId),
22644    Focused,
22645    FocusedIn,
22646    Blurred,
22647    DirtyChanged,
22648    Saved,
22649    TitleChanged,
22650    DiffBaseChanged,
22651    SelectionsChanged {
22652        local: bool,
22653    },
22654    ScrollPositionChanged {
22655        local: bool,
22656        autoscroll: bool,
22657    },
22658    Closed,
22659    TransactionUndone {
22660        transaction_id: clock::Lamport,
22661    },
22662    TransactionBegun {
22663        transaction_id: clock::Lamport,
22664    },
22665    Reloaded,
22666    CursorShapeChanged,
22667    PushedToNavHistory {
22668        anchor: Anchor,
22669        is_deactivate: bool,
22670    },
22671}
22672
22673impl EventEmitter<EditorEvent> for Editor {}
22674
22675impl Focusable for Editor {
22676    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22677        self.focus_handle.clone()
22678    }
22679}
22680
22681impl Render for Editor {
22682    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22683        let settings = ThemeSettings::get_global(cx);
22684
22685        let mut text_style = match self.mode {
22686            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22687                color: cx.theme().colors().editor_foreground,
22688                font_family: settings.ui_font.family.clone(),
22689                font_features: settings.ui_font.features.clone(),
22690                font_fallbacks: settings.ui_font.fallbacks.clone(),
22691                font_size: rems(0.875).into(),
22692                font_weight: settings.ui_font.weight,
22693                line_height: relative(settings.buffer_line_height.value()),
22694                ..Default::default()
22695            },
22696            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22697                color: cx.theme().colors().editor_foreground,
22698                font_family: settings.buffer_font.family.clone(),
22699                font_features: settings.buffer_font.features.clone(),
22700                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22701                font_size: settings.buffer_font_size(cx).into(),
22702                font_weight: settings.buffer_font.weight,
22703                line_height: relative(settings.buffer_line_height.value()),
22704                ..Default::default()
22705            },
22706        };
22707        if let Some(text_style_refinement) = &self.text_style_refinement {
22708            text_style.refine(text_style_refinement)
22709        }
22710
22711        let background = match self.mode {
22712            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22713            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22714            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22715            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22716        };
22717
22718        EditorElement::new(
22719            &cx.entity(),
22720            EditorStyle {
22721                background,
22722                border: cx.theme().colors().border,
22723                local_player: cx.theme().players().local(),
22724                text: text_style,
22725                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22726                syntax: cx.theme().syntax().clone(),
22727                status: cx.theme().status().clone(),
22728                inlay_hints_style: make_inlay_hints_style(cx),
22729                inline_completion_styles: make_suggestion_styles(cx),
22730                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22731                show_underlines: self.diagnostics_enabled(),
22732            },
22733        )
22734    }
22735}
22736
22737impl EntityInputHandler for Editor {
22738    fn text_for_range(
22739        &mut self,
22740        range_utf16: Range<usize>,
22741        adjusted_range: &mut Option<Range<usize>>,
22742        _: &mut Window,
22743        cx: &mut Context<Self>,
22744    ) -> Option<String> {
22745        let snapshot = self.buffer.read(cx).read(cx);
22746        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22747        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22748        if (start.0..end.0) != range_utf16 {
22749            adjusted_range.replace(start.0..end.0);
22750        }
22751        Some(snapshot.text_for_range(start..end).collect())
22752    }
22753
22754    fn selected_text_range(
22755        &mut self,
22756        ignore_disabled_input: bool,
22757        _: &mut Window,
22758        cx: &mut Context<Self>,
22759    ) -> Option<UTF16Selection> {
22760        // Prevent the IME menu from appearing when holding down an alphabetic key
22761        // while input is disabled.
22762        if !ignore_disabled_input && !self.input_enabled {
22763            return None;
22764        }
22765
22766        let selection = self.selections.newest::<OffsetUtf16>(cx);
22767        let range = selection.range();
22768
22769        Some(UTF16Selection {
22770            range: range.start.0..range.end.0,
22771            reversed: selection.reversed,
22772        })
22773    }
22774
22775    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22776        let snapshot = self.buffer.read(cx).read(cx);
22777        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22778        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22779    }
22780
22781    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22782        self.clear_highlights::<InputComposition>(cx);
22783        self.ime_transaction.take();
22784    }
22785
22786    fn replace_text_in_range(
22787        &mut self,
22788        range_utf16: Option<Range<usize>>,
22789        text: &str,
22790        window: &mut Window,
22791        cx: &mut Context<Self>,
22792    ) {
22793        if !self.input_enabled {
22794            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22795            return;
22796        }
22797
22798        self.transact(window, cx, |this, window, cx| {
22799            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22800                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22801                Some(this.selection_replacement_ranges(range_utf16, cx))
22802            } else {
22803                this.marked_text_ranges(cx)
22804            };
22805
22806            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22807                let newest_selection_id = this.selections.newest_anchor().id;
22808                this.selections
22809                    .all::<OffsetUtf16>(cx)
22810                    .iter()
22811                    .zip(ranges_to_replace.iter())
22812                    .find_map(|(selection, range)| {
22813                        if selection.id == newest_selection_id {
22814                            Some(
22815                                (range.start.0 as isize - selection.head().0 as isize)
22816                                    ..(range.end.0 as isize - selection.head().0 as isize),
22817                            )
22818                        } else {
22819                            None
22820                        }
22821                    })
22822            });
22823
22824            cx.emit(EditorEvent::InputHandled {
22825                utf16_range_to_replace: range_to_replace,
22826                text: text.into(),
22827            });
22828
22829            if let Some(new_selected_ranges) = new_selected_ranges {
22830                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22831                    selections.select_ranges(new_selected_ranges)
22832                });
22833                this.backspace(&Default::default(), window, cx);
22834            }
22835
22836            this.handle_input(text, window, cx);
22837        });
22838
22839        if let Some(transaction) = self.ime_transaction {
22840            self.buffer.update(cx, |buffer, cx| {
22841                buffer.group_until_transaction(transaction, cx);
22842            });
22843        }
22844
22845        self.unmark_text(window, cx);
22846    }
22847
22848    fn replace_and_mark_text_in_range(
22849        &mut self,
22850        range_utf16: Option<Range<usize>>,
22851        text: &str,
22852        new_selected_range_utf16: Option<Range<usize>>,
22853        window: &mut Window,
22854        cx: &mut Context<Self>,
22855    ) {
22856        if !self.input_enabled {
22857            return;
22858        }
22859
22860        let transaction = self.transact(window, cx, |this, window, cx| {
22861            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22862                let snapshot = this.buffer.read(cx).read(cx);
22863                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22864                    for marked_range in &mut marked_ranges {
22865                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22866                        marked_range.start.0 += relative_range_utf16.start;
22867                        marked_range.start =
22868                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22869                        marked_range.end =
22870                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22871                    }
22872                }
22873                Some(marked_ranges)
22874            } else if let Some(range_utf16) = range_utf16 {
22875                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22876                Some(this.selection_replacement_ranges(range_utf16, cx))
22877            } else {
22878                None
22879            };
22880
22881            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22882                let newest_selection_id = this.selections.newest_anchor().id;
22883                this.selections
22884                    .all::<OffsetUtf16>(cx)
22885                    .iter()
22886                    .zip(ranges_to_replace.iter())
22887                    .find_map(|(selection, range)| {
22888                        if selection.id == newest_selection_id {
22889                            Some(
22890                                (range.start.0 as isize - selection.head().0 as isize)
22891                                    ..(range.end.0 as isize - selection.head().0 as isize),
22892                            )
22893                        } else {
22894                            None
22895                        }
22896                    })
22897            });
22898
22899            cx.emit(EditorEvent::InputHandled {
22900                utf16_range_to_replace: range_to_replace,
22901                text: text.into(),
22902            });
22903
22904            if let Some(ranges) = ranges_to_replace {
22905                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22906                    s.select_ranges(ranges)
22907                });
22908            }
22909
22910            let marked_ranges = {
22911                let snapshot = this.buffer.read(cx).read(cx);
22912                this.selections
22913                    .disjoint_anchors()
22914                    .iter()
22915                    .map(|selection| {
22916                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22917                    })
22918                    .collect::<Vec<_>>()
22919            };
22920
22921            if text.is_empty() {
22922                this.unmark_text(window, cx);
22923            } else {
22924                this.highlight_text::<InputComposition>(
22925                    marked_ranges.clone(),
22926                    HighlightStyle {
22927                        underline: Some(UnderlineStyle {
22928                            thickness: px(1.),
22929                            color: None,
22930                            wavy: false,
22931                        }),
22932                        ..Default::default()
22933                    },
22934                    cx,
22935                );
22936            }
22937
22938            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22939            let use_autoclose = this.use_autoclose;
22940            let use_auto_surround = this.use_auto_surround;
22941            this.set_use_autoclose(false);
22942            this.set_use_auto_surround(false);
22943            this.handle_input(text, window, cx);
22944            this.set_use_autoclose(use_autoclose);
22945            this.set_use_auto_surround(use_auto_surround);
22946
22947            if let Some(new_selected_range) = new_selected_range_utf16 {
22948                let snapshot = this.buffer.read(cx).read(cx);
22949                let new_selected_ranges = marked_ranges
22950                    .into_iter()
22951                    .map(|marked_range| {
22952                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22953                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22954                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22955                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22956                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22957                    })
22958                    .collect::<Vec<_>>();
22959
22960                drop(snapshot);
22961                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22962                    selections.select_ranges(new_selected_ranges)
22963                });
22964            }
22965        });
22966
22967        self.ime_transaction = self.ime_transaction.or(transaction);
22968        if let Some(transaction) = self.ime_transaction {
22969            self.buffer.update(cx, |buffer, cx| {
22970                buffer.group_until_transaction(transaction, cx);
22971            });
22972        }
22973
22974        if self.text_highlights::<InputComposition>(cx).is_none() {
22975            self.ime_transaction.take();
22976        }
22977    }
22978
22979    fn bounds_for_range(
22980        &mut self,
22981        range_utf16: Range<usize>,
22982        element_bounds: gpui::Bounds<Pixels>,
22983        window: &mut Window,
22984        cx: &mut Context<Self>,
22985    ) -> Option<gpui::Bounds<Pixels>> {
22986        let text_layout_details = self.text_layout_details(window);
22987        let CharacterDimensions {
22988            em_width,
22989            em_advance,
22990            line_height,
22991        } = self.character_dimensions(window);
22992
22993        let snapshot = self.snapshot(window, cx);
22994        let scroll_position = snapshot.scroll_position();
22995        let scroll_left = scroll_position.x * em_advance;
22996
22997        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22998        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22999            + self.gutter_dimensions.full_width();
23000        let y = line_height * (start.row().as_f32() - scroll_position.y);
23001
23002        Some(Bounds {
23003            origin: element_bounds.origin + point(x, y),
23004            size: size(em_width, line_height),
23005        })
23006    }
23007
23008    fn character_index_for_point(
23009        &mut self,
23010        point: gpui::Point<Pixels>,
23011        _window: &mut Window,
23012        _cx: &mut Context<Self>,
23013    ) -> Option<usize> {
23014        let position_map = self.last_position_map.as_ref()?;
23015        if !position_map.text_hitbox.contains(&point) {
23016            return None;
23017        }
23018        let display_point = position_map.point_for_position(point).previous_valid;
23019        let anchor = position_map
23020            .snapshot
23021            .display_point_to_anchor(display_point, Bias::Left);
23022        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23023        Some(utf16_offset.0)
23024    }
23025}
23026
23027trait SelectionExt {
23028    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23029    fn spanned_rows(
23030        &self,
23031        include_end_if_at_line_start: bool,
23032        map: &DisplaySnapshot,
23033    ) -> Range<MultiBufferRow>;
23034}
23035
23036impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23037    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23038        let start = self
23039            .start
23040            .to_point(&map.buffer_snapshot)
23041            .to_display_point(map);
23042        let end = self
23043            .end
23044            .to_point(&map.buffer_snapshot)
23045            .to_display_point(map);
23046        if self.reversed {
23047            end..start
23048        } else {
23049            start..end
23050        }
23051    }
23052
23053    fn spanned_rows(
23054        &self,
23055        include_end_if_at_line_start: bool,
23056        map: &DisplaySnapshot,
23057    ) -> Range<MultiBufferRow> {
23058        let start = self.start.to_point(&map.buffer_snapshot);
23059        let mut end = self.end.to_point(&map.buffer_snapshot);
23060        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23061            end.row -= 1;
23062        }
23063
23064        let buffer_start = map.prev_line_boundary(start).0;
23065        let buffer_end = map.next_line_boundary(end).0;
23066        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23067    }
23068}
23069
23070impl<T: InvalidationRegion> InvalidationStack<T> {
23071    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23072    where
23073        S: Clone + ToOffset,
23074    {
23075        while let Some(region) = self.last() {
23076            let all_selections_inside_invalidation_ranges =
23077                if selections.len() == region.ranges().len() {
23078                    selections
23079                        .iter()
23080                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23081                        .all(|(selection, invalidation_range)| {
23082                            let head = selection.head().to_offset(buffer);
23083                            invalidation_range.start <= head && invalidation_range.end >= head
23084                        })
23085                } else {
23086                    false
23087                };
23088
23089            if all_selections_inside_invalidation_ranges {
23090                break;
23091            } else {
23092                self.pop();
23093            }
23094        }
23095    }
23096}
23097
23098impl<T> Default for InvalidationStack<T> {
23099    fn default() -> Self {
23100        Self(Default::default())
23101    }
23102}
23103
23104impl<T> Deref for InvalidationStack<T> {
23105    type Target = Vec<T>;
23106
23107    fn deref(&self) -> &Self::Target {
23108        &self.0
23109    }
23110}
23111
23112impl<T> DerefMut for InvalidationStack<T> {
23113    fn deref_mut(&mut self) -> &mut Self::Target {
23114        &mut self.0
23115    }
23116}
23117
23118impl InvalidationRegion for SnippetState {
23119    fn ranges(&self) -> &[Range<Anchor>] {
23120        &self.ranges[self.active_index]
23121    }
23122}
23123
23124fn inline_completion_edit_text(
23125    current_snapshot: &BufferSnapshot,
23126    edits: &[(Range<Anchor>, String)],
23127    edit_preview: &EditPreview,
23128    include_deletions: bool,
23129    cx: &App,
23130) -> HighlightedText {
23131    let edits = edits
23132        .iter()
23133        .map(|(anchor, text)| {
23134            (
23135                anchor.start.text_anchor..anchor.end.text_anchor,
23136                text.clone(),
23137            )
23138        })
23139        .collect::<Vec<_>>();
23140
23141    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23142}
23143
23144pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23145    match severity {
23146        lsp::DiagnosticSeverity::ERROR => colors.error,
23147        lsp::DiagnosticSeverity::WARNING => colors.warning,
23148        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23149        lsp::DiagnosticSeverity::HINT => colors.info,
23150        _ => colors.ignored,
23151    }
23152}
23153
23154pub fn styled_runs_for_code_label<'a>(
23155    label: &'a CodeLabel,
23156    syntax_theme: &'a theme::SyntaxTheme,
23157) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23158    let fade_out = HighlightStyle {
23159        fade_out: Some(0.35),
23160        ..Default::default()
23161    };
23162
23163    let mut prev_end = label.filter_range.end;
23164    label
23165        .runs
23166        .iter()
23167        .enumerate()
23168        .flat_map(move |(ix, (range, highlight_id))| {
23169            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23170                style
23171            } else {
23172                return Default::default();
23173            };
23174            let mut muted_style = style;
23175            muted_style.highlight(fade_out);
23176
23177            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23178            if range.start >= label.filter_range.end {
23179                if range.start > prev_end {
23180                    runs.push((prev_end..range.start, fade_out));
23181                }
23182                runs.push((range.clone(), muted_style));
23183            } else if range.end <= label.filter_range.end {
23184                runs.push((range.clone(), style));
23185            } else {
23186                runs.push((range.start..label.filter_range.end, style));
23187                runs.push((label.filter_range.end..range.end, muted_style));
23188            }
23189            prev_end = cmp::max(prev_end, range.end);
23190
23191            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23192                runs.push((prev_end..label.text.len(), fade_out));
23193            }
23194
23195            runs
23196        })
23197}
23198
23199pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23200    let mut prev_index = 0;
23201    let mut prev_codepoint: Option<char> = None;
23202    text.char_indices()
23203        .chain([(text.len(), '\0')])
23204        .filter_map(move |(index, codepoint)| {
23205            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23206            let is_boundary = index == text.len()
23207                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23208                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23209            if is_boundary {
23210                let chunk = &text[prev_index..index];
23211                prev_index = index;
23212                Some(chunk)
23213            } else {
23214                None
23215            }
23216        })
23217}
23218
23219pub trait RangeToAnchorExt: Sized {
23220    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23221
23222    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23223        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23224        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23225    }
23226}
23227
23228impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23229    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23230        let start_offset = self.start.to_offset(snapshot);
23231        let end_offset = self.end.to_offset(snapshot);
23232        if start_offset == end_offset {
23233            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23234        } else {
23235            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23236        }
23237    }
23238}
23239
23240pub trait RowExt {
23241    fn as_f32(&self) -> f32;
23242
23243    fn next_row(&self) -> Self;
23244
23245    fn previous_row(&self) -> Self;
23246
23247    fn minus(&self, other: Self) -> u32;
23248}
23249
23250impl RowExt for DisplayRow {
23251    fn as_f32(&self) -> f32 {
23252        self.0 as f32
23253    }
23254
23255    fn next_row(&self) -> Self {
23256        Self(self.0 + 1)
23257    }
23258
23259    fn previous_row(&self) -> Self {
23260        Self(self.0.saturating_sub(1))
23261    }
23262
23263    fn minus(&self, other: Self) -> u32 {
23264        self.0 - other.0
23265    }
23266}
23267
23268impl RowExt for MultiBufferRow {
23269    fn as_f32(&self) -> f32 {
23270        self.0 as f32
23271    }
23272
23273    fn next_row(&self) -> Self {
23274        Self(self.0 + 1)
23275    }
23276
23277    fn previous_row(&self) -> Self {
23278        Self(self.0.saturating_sub(1))
23279    }
23280
23281    fn minus(&self, other: Self) -> u32 {
23282        self.0 - other.0
23283    }
23284}
23285
23286trait RowRangeExt {
23287    type Row;
23288
23289    fn len(&self) -> usize;
23290
23291    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23292}
23293
23294impl RowRangeExt for Range<MultiBufferRow> {
23295    type Row = MultiBufferRow;
23296
23297    fn len(&self) -> usize {
23298        (self.end.0 - self.start.0) as usize
23299    }
23300
23301    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23302        (self.start.0..self.end.0).map(MultiBufferRow)
23303    }
23304}
23305
23306impl RowRangeExt for Range<DisplayRow> {
23307    type Row = DisplayRow;
23308
23309    fn len(&self) -> usize {
23310        (self.end.0 - self.start.0) as usize
23311    }
23312
23313    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23314        (self.start.0..self.end.0).map(DisplayRow)
23315    }
23316}
23317
23318/// If select range has more than one line, we
23319/// just point the cursor to range.start.
23320fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23321    if range.start.row == range.end.row {
23322        range
23323    } else {
23324        range.start..range.start
23325    }
23326}
23327pub struct KillRing(ClipboardItem);
23328impl Global for KillRing {}
23329
23330const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23331
23332enum BreakpointPromptEditAction {
23333    Log,
23334    Condition,
23335    HitCondition,
23336}
23337
23338struct BreakpointPromptEditor {
23339    pub(crate) prompt: Entity<Editor>,
23340    editor: WeakEntity<Editor>,
23341    breakpoint_anchor: Anchor,
23342    breakpoint: Breakpoint,
23343    edit_action: BreakpointPromptEditAction,
23344    block_ids: HashSet<CustomBlockId>,
23345    editor_margins: Arc<Mutex<EditorMargins>>,
23346    _subscriptions: Vec<Subscription>,
23347}
23348
23349impl BreakpointPromptEditor {
23350    const MAX_LINES: u8 = 4;
23351
23352    fn new(
23353        editor: WeakEntity<Editor>,
23354        breakpoint_anchor: Anchor,
23355        breakpoint: Breakpoint,
23356        edit_action: BreakpointPromptEditAction,
23357        window: &mut Window,
23358        cx: &mut Context<Self>,
23359    ) -> Self {
23360        let base_text = match edit_action {
23361            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23362            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23363            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23364        }
23365        .map(|msg| msg.to_string())
23366        .unwrap_or_default();
23367
23368        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23369        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23370
23371        let prompt = cx.new(|cx| {
23372            let mut prompt = Editor::new(
23373                EditorMode::AutoHeight {
23374                    min_lines: 1,
23375                    max_lines: Some(Self::MAX_LINES as usize),
23376                },
23377                buffer,
23378                None,
23379                window,
23380                cx,
23381            );
23382            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23383            prompt.set_show_cursor_when_unfocused(false, cx);
23384            prompt.set_placeholder_text(
23385                match edit_action {
23386                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23387                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23388                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23389                },
23390                cx,
23391            );
23392
23393            prompt
23394        });
23395
23396        Self {
23397            prompt,
23398            editor,
23399            breakpoint_anchor,
23400            breakpoint,
23401            edit_action,
23402            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23403            block_ids: Default::default(),
23404            _subscriptions: vec![],
23405        }
23406    }
23407
23408    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23409        self.block_ids.extend(block_ids)
23410    }
23411
23412    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23413        if let Some(editor) = self.editor.upgrade() {
23414            let message = self
23415                .prompt
23416                .read(cx)
23417                .buffer
23418                .read(cx)
23419                .as_singleton()
23420                .expect("A multi buffer in breakpoint prompt isn't possible")
23421                .read(cx)
23422                .as_rope()
23423                .to_string();
23424
23425            editor.update(cx, |editor, cx| {
23426                editor.edit_breakpoint_at_anchor(
23427                    self.breakpoint_anchor,
23428                    self.breakpoint.clone(),
23429                    match self.edit_action {
23430                        BreakpointPromptEditAction::Log => {
23431                            BreakpointEditAction::EditLogMessage(message.into())
23432                        }
23433                        BreakpointPromptEditAction::Condition => {
23434                            BreakpointEditAction::EditCondition(message.into())
23435                        }
23436                        BreakpointPromptEditAction::HitCondition => {
23437                            BreakpointEditAction::EditHitCondition(message.into())
23438                        }
23439                    },
23440                    cx,
23441                );
23442
23443                editor.remove_blocks(self.block_ids.clone(), None, cx);
23444                cx.focus_self(window);
23445            });
23446        }
23447    }
23448
23449    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23450        self.editor
23451            .update(cx, |editor, cx| {
23452                editor.remove_blocks(self.block_ids.clone(), None, cx);
23453                window.focus(&editor.focus_handle);
23454            })
23455            .log_err();
23456    }
23457
23458    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23459        let settings = ThemeSettings::get_global(cx);
23460        let text_style = TextStyle {
23461            color: if self.prompt.read(cx).read_only(cx) {
23462                cx.theme().colors().text_disabled
23463            } else {
23464                cx.theme().colors().text
23465            },
23466            font_family: settings.buffer_font.family.clone(),
23467            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23468            font_size: settings.buffer_font_size(cx).into(),
23469            font_weight: settings.buffer_font.weight,
23470            line_height: relative(settings.buffer_line_height.value()),
23471            ..Default::default()
23472        };
23473        EditorElement::new(
23474            &self.prompt,
23475            EditorStyle {
23476                background: cx.theme().colors().editor_background,
23477                local_player: cx.theme().players().local(),
23478                text: text_style,
23479                ..Default::default()
23480            },
23481        )
23482    }
23483}
23484
23485impl Render for BreakpointPromptEditor {
23486    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23487        let editor_margins = *self.editor_margins.lock();
23488        let gutter_dimensions = editor_margins.gutter;
23489        h_flex()
23490            .key_context("Editor")
23491            .bg(cx.theme().colors().editor_background)
23492            .border_y_1()
23493            .border_color(cx.theme().status().info_border)
23494            .size_full()
23495            .py(window.line_height() / 2.5)
23496            .on_action(cx.listener(Self::confirm))
23497            .on_action(cx.listener(Self::cancel))
23498            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23499            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23500    }
23501}
23502
23503impl Focusable for BreakpointPromptEditor {
23504    fn focus_handle(&self, cx: &App) -> FocusHandle {
23505        self.prompt.focus_handle(cx)
23506    }
23507}
23508
23509fn all_edits_insertions_or_deletions(
23510    edits: &Vec<(Range<Anchor>, String)>,
23511    snapshot: &MultiBufferSnapshot,
23512) -> bool {
23513    let mut all_insertions = true;
23514    let mut all_deletions = true;
23515
23516    for (range, new_text) in edits.iter() {
23517        let range_is_empty = range.to_offset(&snapshot).is_empty();
23518        let text_is_empty = new_text.is_empty();
23519
23520        if range_is_empty != text_is_empty {
23521            if range_is_empty {
23522                all_deletions = false;
23523            } else {
23524                all_insertions = false;
23525            }
23526        } else {
23527            return false;
23528        }
23529
23530        if !all_insertions && !all_deletions {
23531            return false;
23532        }
23533    }
23534    all_insertions || all_deletions
23535}
23536
23537struct MissingEditPredictionKeybindingTooltip;
23538
23539impl Render for MissingEditPredictionKeybindingTooltip {
23540    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23541        ui::tooltip_container(window, cx, |container, _, cx| {
23542            container
23543                .flex_shrink_0()
23544                .max_w_80()
23545                .min_h(rems_from_px(124.))
23546                .justify_between()
23547                .child(
23548                    v_flex()
23549                        .flex_1()
23550                        .text_ui_sm(cx)
23551                        .child(Label::new("Conflict with Accept Keybinding"))
23552                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23553                )
23554                .child(
23555                    h_flex()
23556                        .pb_1()
23557                        .gap_1()
23558                        .items_end()
23559                        .w_full()
23560                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23561                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23562                        }))
23563                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23564                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23565                        })),
23566                )
23567        })
23568    }
23569}
23570
23571#[derive(Debug, Clone, Copy, PartialEq)]
23572pub struct LineHighlight {
23573    pub background: Background,
23574    pub border: Option<gpui::Hsla>,
23575    pub include_gutter: bool,
23576    pub type_id: Option<TypeId>,
23577}
23578
23579struct LineManipulationResult {
23580    pub new_text: String,
23581    pub line_count_before: usize,
23582    pub line_count_after: usize,
23583}
23584
23585fn render_diff_hunk_controls(
23586    row: u32,
23587    status: &DiffHunkStatus,
23588    hunk_range: Range<Anchor>,
23589    is_created_file: bool,
23590    line_height: Pixels,
23591    editor: &Entity<Editor>,
23592    _window: &mut Window,
23593    cx: &mut App,
23594) -> AnyElement {
23595    h_flex()
23596        .h(line_height)
23597        .mr_1()
23598        .gap_1()
23599        .px_0p5()
23600        .pb_1()
23601        .border_x_1()
23602        .border_b_1()
23603        .border_color(cx.theme().colors().border_variant)
23604        .rounded_b_lg()
23605        .bg(cx.theme().colors().editor_background)
23606        .gap_1()
23607        .block_mouse_except_scroll()
23608        .shadow_md()
23609        .child(if status.has_secondary_hunk() {
23610            Button::new(("stage", row as u64), "Stage")
23611                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23612                .tooltip({
23613                    let focus_handle = editor.focus_handle(cx);
23614                    move |window, cx| {
23615                        Tooltip::for_action_in(
23616                            "Stage Hunk",
23617                            &::git::ToggleStaged,
23618                            &focus_handle,
23619                            window,
23620                            cx,
23621                        )
23622                    }
23623                })
23624                .on_click({
23625                    let editor = editor.clone();
23626                    move |_event, _window, cx| {
23627                        editor.update(cx, |editor, cx| {
23628                            editor.stage_or_unstage_diff_hunks(
23629                                true,
23630                                vec![hunk_range.start..hunk_range.start],
23631                                cx,
23632                            );
23633                        });
23634                    }
23635                })
23636        } else {
23637            Button::new(("unstage", row as u64), "Unstage")
23638                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23639                .tooltip({
23640                    let focus_handle = editor.focus_handle(cx);
23641                    move |window, cx| {
23642                        Tooltip::for_action_in(
23643                            "Unstage Hunk",
23644                            &::git::ToggleStaged,
23645                            &focus_handle,
23646                            window,
23647                            cx,
23648                        )
23649                    }
23650                })
23651                .on_click({
23652                    let editor = editor.clone();
23653                    move |_event, _window, cx| {
23654                        editor.update(cx, |editor, cx| {
23655                            editor.stage_or_unstage_diff_hunks(
23656                                false,
23657                                vec![hunk_range.start..hunk_range.start],
23658                                cx,
23659                            );
23660                        });
23661                    }
23662                })
23663        })
23664        .child(
23665            Button::new(("restore", row as u64), "Restore")
23666                .tooltip({
23667                    let focus_handle = editor.focus_handle(cx);
23668                    move |window, cx| {
23669                        Tooltip::for_action_in(
23670                            "Restore Hunk",
23671                            &::git::Restore,
23672                            &focus_handle,
23673                            window,
23674                            cx,
23675                        )
23676                    }
23677                })
23678                .on_click({
23679                    let editor = editor.clone();
23680                    move |_event, window, cx| {
23681                        editor.update(cx, |editor, cx| {
23682                            let snapshot = editor.snapshot(window, cx);
23683                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23684                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23685                        });
23686                    }
23687                })
23688                .disabled(is_created_file),
23689        )
23690        .when(
23691            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23692            |el| {
23693                el.child(
23694                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23695                        .shape(IconButtonShape::Square)
23696                        .icon_size(IconSize::Small)
23697                        // .disabled(!has_multiple_hunks)
23698                        .tooltip({
23699                            let focus_handle = editor.focus_handle(cx);
23700                            move |window, cx| {
23701                                Tooltip::for_action_in(
23702                                    "Next Hunk",
23703                                    &GoToHunk,
23704                                    &focus_handle,
23705                                    window,
23706                                    cx,
23707                                )
23708                            }
23709                        })
23710                        .on_click({
23711                            let editor = editor.clone();
23712                            move |_event, window, cx| {
23713                                editor.update(cx, |editor, cx| {
23714                                    let snapshot = editor.snapshot(window, cx);
23715                                    let position =
23716                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23717                                    editor.go_to_hunk_before_or_after_position(
23718                                        &snapshot,
23719                                        position,
23720                                        Direction::Next,
23721                                        window,
23722                                        cx,
23723                                    );
23724                                    editor.expand_selected_diff_hunks(cx);
23725                                });
23726                            }
23727                        }),
23728                )
23729                .child(
23730                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23731                        .shape(IconButtonShape::Square)
23732                        .icon_size(IconSize::Small)
23733                        // .disabled(!has_multiple_hunks)
23734                        .tooltip({
23735                            let focus_handle = editor.focus_handle(cx);
23736                            move |window, cx| {
23737                                Tooltip::for_action_in(
23738                                    "Previous Hunk",
23739                                    &GoToPreviousHunk,
23740                                    &focus_handle,
23741                                    window,
23742                                    cx,
23743                                )
23744                            }
23745                        })
23746                        .on_click({
23747                            let editor = editor.clone();
23748                            move |_event, window, cx| {
23749                                editor.update(cx, |editor, cx| {
23750                                    let snapshot = editor.snapshot(window, cx);
23751                                    let point =
23752                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23753                                    editor.go_to_hunk_before_or_after_position(
23754                                        &snapshot,
23755                                        point,
23756                                        Direction::Prev,
23757                                        window,
23758                                        cx,
23759                                    );
23760                                    editor.expand_selected_diff_hunks(cx);
23761                                });
23762                            }
23763                        }),
23764                )
23765            },
23766        )
23767        .into_any_element()
23768}