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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    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, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221
  222pub const FILE_HEADER_HEIGHT: u32 = 2;
  223pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  224pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  225const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  226const MAX_LINE_LEN: usize = 1024;
  227const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  228const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  229pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  230#[doc(hidden)]
  231pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  232const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  233
  234pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  235pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  236pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  237
  238pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  239pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  240pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  241pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  242
  243pub type RenderDiffHunkControlsFn = Arc<
  244    dyn Fn(
  245        u32,
  246        &DiffHunkStatus,
  247        Range<Anchor>,
  248        bool,
  249        Pixels,
  250        &Entity<Editor>,
  251        &mut Window,
  252        &mut App,
  253    ) -> AnyElement,
  254>;
  255
  256const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  257    alt: true,
  258    shift: true,
  259    control: false,
  260    platform: false,
  261    function: false,
  262};
  263
  264struct InlineValueCache {
  265    enabled: bool,
  266    inlays: Vec<InlayId>,
  267    refresh_task: Task<Option<()>>,
  268}
  269
  270impl InlineValueCache {
  271    fn new(enabled: bool) -> Self {
  272        Self {
  273            enabled,
  274            inlays: Vec::new(),
  275            refresh_task: Task::ready(None),
  276        }
  277    }
  278}
  279
  280#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  281pub enum InlayId {
  282    InlineCompletion(usize),
  283    Hint(usize),
  284    DebuggerValue(usize),
  285}
  286
  287impl InlayId {
  288    fn id(&self) -> usize {
  289        match self {
  290            Self::InlineCompletion(id) => *id,
  291            Self::Hint(id) => *id,
  292            Self::DebuggerValue(id) => *id,
  293        }
  294    }
  295}
  296
  297pub enum ActiveDebugLine {}
  298pub enum DebugStackFrameLine {}
  299enum DocumentHighlightRead {}
  300enum DocumentHighlightWrite {}
  301enum InputComposition {}
  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        },
  361    )
  362    .detach();
  363
  364    cx.on_action(move |_: &workspace::NewFile, cx| {
  365        let app_state = workspace::AppState::global(cx);
  366        if let Some(app_state) = app_state.upgrade() {
  367            workspace::open_new(
  368                Default::default(),
  369                app_state,
  370                cx,
  371                |workspace, window, cx| {
  372                    Editor::new_file(workspace, &Default::default(), window, cx)
  373                },
  374            )
  375            .detach();
  376        }
  377    });
  378    cx.on_action(move |_: &workspace::NewWindow, cx| {
  379        let app_state = workspace::AppState::global(cx);
  380        if let Some(app_state) = app_state.upgrade() {
  381            workspace::open_new(
  382                Default::default(),
  383                app_state,
  384                cx,
  385                |workspace, window, cx| {
  386                    cx.activate(true);
  387                    Editor::new_file(workspace, &Default::default(), window, cx)
  388                },
  389            )
  390            .detach();
  391        }
  392    });
  393}
  394
  395pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  396    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  397}
  398
  399pub trait DiagnosticRenderer {
  400    fn render_group(
  401        &self,
  402        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  403        buffer_id: BufferId,
  404        snapshot: EditorSnapshot,
  405        editor: WeakEntity<Editor>,
  406        cx: &mut App,
  407    ) -> Vec<BlockProperties<Anchor>>;
  408
  409    fn render_hover(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        range: Range<Point>,
  413        buffer_id: BufferId,
  414        cx: &mut App,
  415    ) -> Option<Entity<markdown::Markdown>>;
  416
  417    fn open_link(
  418        &self,
  419        editor: &mut Editor,
  420        link: SharedString,
  421        window: &mut Window,
  422        cx: &mut Context<Editor>,
  423    );
  424}
  425
  426pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  427
  428impl GlobalDiagnosticRenderer {
  429    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  430        cx.try_global::<Self>().map(|g| g.0.clone())
  431    }
  432}
  433
  434impl gpui::Global for GlobalDiagnosticRenderer {}
  435pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  436    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  437}
  438
  439pub struct SearchWithinRange;
  440
  441trait InvalidationRegion {
  442    fn ranges(&self) -> &[Range<Anchor>];
  443}
  444
  445#[derive(Clone, Debug, PartialEq)]
  446pub enum SelectPhase {
  447    Begin {
  448        position: DisplayPoint,
  449        add: bool,
  450        click_count: usize,
  451    },
  452    BeginColumnar {
  453        position: DisplayPoint,
  454        reset: bool,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug)]
  470pub enum SelectMode {
  471    Character,
  472    Word(Range<Anchor>),
  473    Line(Range<Anchor>),
  474    All,
  475}
  476
  477#[derive(Clone, PartialEq, Eq, Debug)]
  478pub enum EditorMode {
  479    SingleLine {
  480        auto_width: bool,
  481    },
  482    AutoHeight {
  483        max_lines: usize,
  484    },
  485    Full {
  486        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  487        scale_ui_elements_with_buffer_font_size: bool,
  488        /// When set to `true`, the editor will render a background for the active line.
  489        show_active_line_background: bool,
  490        /// When set to `true`, the editor's height will be determined by its content.
  491        sized_by_content: bool,
  492    },
  493    Minimap {
  494        parent: WeakEntity<Editor>,
  495    },
  496}
  497
  498impl EditorMode {
  499    pub fn full() -> Self {
  500        Self::Full {
  501            scale_ui_elements_with_buffer_font_size: true,
  502            show_active_line_background: true,
  503            sized_by_content: false,
  504        }
  505    }
  506
  507    pub fn is_full(&self) -> bool {
  508        matches!(self, Self::Full { .. })
  509    }
  510
  511    fn is_minimap(&self) -> bool {
  512        matches!(self, Self::Minimap { .. })
  513    }
  514}
  515
  516#[derive(Copy, Clone, Debug)]
  517pub enum SoftWrap {
  518    /// Prefer not to wrap at all.
  519    ///
  520    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  521    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  522    GitDiff,
  523    /// Prefer a single line generally, unless an overly long line is encountered.
  524    None,
  525    /// Soft wrap lines that exceed the editor width.
  526    EditorWidth,
  527    /// Soft wrap lines at the preferred line length.
  528    Column(u32),
  529    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  530    Bounded(u32),
  531}
  532
  533#[derive(Clone)]
  534pub struct EditorStyle {
  535    pub background: Hsla,
  536    pub local_player: PlayerColor,
  537    pub text: TextStyle,
  538    pub scrollbar_width: Pixels,
  539    pub syntax: Arc<SyntaxTheme>,
  540    pub status: StatusColors,
  541    pub inlay_hints_style: HighlightStyle,
  542    pub inline_completion_styles: InlineCompletionStyles,
  543    pub unnecessary_code_fade: f32,
  544    pub show_underlines: bool,
  545}
  546
  547impl Default for EditorStyle {
  548    fn default() -> Self {
  549        Self {
  550            background: Hsla::default(),
  551            local_player: PlayerColor::default(),
  552            text: TextStyle::default(),
  553            scrollbar_width: Pixels::default(),
  554            syntax: Default::default(),
  555            // HACK: Status colors don't have a real default.
  556            // We should look into removing the status colors from the editor
  557            // style and retrieve them directly from the theme.
  558            status: StatusColors::dark(),
  559            inlay_hints_style: HighlightStyle::default(),
  560            inline_completion_styles: InlineCompletionStyles {
  561                insertion: HighlightStyle::default(),
  562                whitespace: HighlightStyle::default(),
  563            },
  564            unnecessary_code_fade: Default::default(),
  565            show_underlines: true,
  566        }
  567    }
  568}
  569
  570pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  571    let show_background = language_settings::language_settings(None, None, cx)
  572        .inlay_hints
  573        .show_background;
  574
  575    HighlightStyle {
  576        color: Some(cx.theme().status().hint),
  577        background_color: show_background.then(|| cx.theme().status().hint_background),
  578        ..HighlightStyle::default()
  579    }
  580}
  581
  582pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  583    InlineCompletionStyles {
  584        insertion: HighlightStyle {
  585            color: Some(cx.theme().status().predictive),
  586            ..HighlightStyle::default()
  587        },
  588        whitespace: HighlightStyle {
  589            background_color: Some(cx.theme().status().created_background),
  590            ..HighlightStyle::default()
  591        },
  592    }
  593}
  594
  595type CompletionId = usize;
  596
  597pub(crate) enum EditDisplayMode {
  598    TabAccept,
  599    DiffPopover,
  600    Inline,
  601}
  602
  603enum InlineCompletion {
  604    Edit {
  605        edits: Vec<(Range<Anchor>, String)>,
  606        edit_preview: Option<EditPreview>,
  607        display_mode: EditDisplayMode,
  608        snapshot: BufferSnapshot,
  609    },
  610    Move {
  611        target: Anchor,
  612        snapshot: BufferSnapshot,
  613    },
  614}
  615
  616struct InlineCompletionState {
  617    inlay_ids: Vec<InlayId>,
  618    completion: InlineCompletion,
  619    completion_id: Option<SharedString>,
  620    invalidation_range: Range<Anchor>,
  621}
  622
  623enum EditPredictionSettings {
  624    Disabled,
  625    Enabled {
  626        show_in_menu: bool,
  627        preview_requires_modifier: bool,
  628    },
  629}
  630
  631enum InlineCompletionHighlight {}
  632
  633#[derive(Debug, Clone)]
  634struct InlineDiagnostic {
  635    message: SharedString,
  636    group_id: usize,
  637    is_primary: bool,
  638    start: Point,
  639    severity: lsp::DiagnosticSeverity,
  640}
  641
  642pub enum MenuInlineCompletionsPolicy {
  643    Never,
  644    ByProvider,
  645}
  646
  647pub enum EditPredictionPreview {
  648    /// Modifier is not pressed
  649    Inactive { released_too_fast: bool },
  650    /// Modifier pressed
  651    Active {
  652        since: Instant,
  653        previous_scroll_position: Option<ScrollAnchor>,
  654    },
  655}
  656
  657impl EditPredictionPreview {
  658    pub fn released_too_fast(&self) -> bool {
  659        match self {
  660            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  661            EditPredictionPreview::Active { .. } => false,
  662        }
  663    }
  664
  665    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  666        if let EditPredictionPreview::Active {
  667            previous_scroll_position,
  668            ..
  669        } = self
  670        {
  671            *previous_scroll_position = scroll_position;
  672        }
  673    }
  674}
  675
  676pub struct ContextMenuOptions {
  677    pub min_entries_visible: usize,
  678    pub max_entries_visible: usize,
  679    pub placement: Option<ContextMenuPlacement>,
  680}
  681
  682#[derive(Debug, Clone, PartialEq, Eq)]
  683pub enum ContextMenuPlacement {
  684    Above,
  685    Below,
  686}
  687
  688#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  689struct EditorActionId(usize);
  690
  691impl EditorActionId {
  692    pub fn post_inc(&mut self) -> Self {
  693        let answer = self.0;
  694
  695        *self = Self(answer + 1);
  696
  697        Self(answer)
  698    }
  699}
  700
  701// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  702// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  703
  704type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  705type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  706
  707#[derive(Default)]
  708struct ScrollbarMarkerState {
  709    scrollbar_size: Size<Pixels>,
  710    dirty: bool,
  711    markers: Arc<[PaintQuad]>,
  712    pending_refresh: Option<Task<Result<()>>>,
  713}
  714
  715impl ScrollbarMarkerState {
  716    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  717        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  718    }
  719}
  720
  721#[derive(Clone, Copy, PartialEq, Eq)]
  722pub enum MinimapVisibility {
  723    Disabled,
  724    Enabled {
  725        /// The configuration currently present in the users settings.
  726        setting_configuration: bool,
  727        /// Whether to override the currently set visibility from the users setting.
  728        toggle_override: bool,
  729    },
  730}
  731
  732impl MinimapVisibility {
  733    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  734        if mode.is_full() {
  735            Self::Enabled {
  736                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  737                toggle_override: false,
  738            }
  739        } else {
  740            Self::Disabled
  741        }
  742    }
  743
  744    fn hidden(&self) -> Self {
  745        match *self {
  746            Self::Enabled {
  747                setting_configuration,
  748                ..
  749            } => Self::Enabled {
  750                setting_configuration,
  751                toggle_override: setting_configuration,
  752            },
  753            Self::Disabled => Self::Disabled,
  754        }
  755    }
  756
  757    fn disabled(&self) -> bool {
  758        match *self {
  759            Self::Disabled => true,
  760            _ => false,
  761        }
  762    }
  763
  764    fn settings_visibility(&self) -> bool {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => setting_configuration,
  770            _ => false,
  771        }
  772    }
  773
  774    fn visible(&self) -> bool {
  775        match *self {
  776            Self::Enabled {
  777                setting_configuration,
  778                toggle_override,
  779            } => setting_configuration ^ toggle_override,
  780            _ => false,
  781        }
  782    }
  783
  784    fn toggle_visibility(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                toggle_override,
  788                setting_configuration,
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: !toggle_override,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796}
  797
  798#[derive(Clone, Debug)]
  799struct RunnableTasks {
  800    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  801    offset: multi_buffer::Anchor,
  802    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  803    column: u32,
  804    // Values of all named captures, including those starting with '_'
  805    extra_variables: HashMap<String, String>,
  806    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  807    context_range: Range<BufferOffset>,
  808}
  809
  810impl RunnableTasks {
  811    fn resolve<'a>(
  812        &'a self,
  813        cx: &'a task::TaskContext,
  814    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  815        self.templates.iter().filter_map(|(kind, template)| {
  816            template
  817                .resolve_task(&kind.to_id_base(), cx)
  818                .map(|task| (kind.clone(), task))
  819        })
  820    }
  821}
  822
  823#[derive(Clone)]
  824pub struct ResolvedTasks {
  825    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  826    position: Anchor,
  827}
  828
  829#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  830struct BufferOffset(usize);
  831
  832// Addons allow storing per-editor state in other crates (e.g. Vim)
  833pub trait Addon: 'static {
  834    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  835
  836    fn render_buffer_header_controls(
  837        &self,
  838        _: &ExcerptInfo,
  839        _: &Window,
  840        _: &App,
  841    ) -> Option<AnyElement> {
  842        None
  843    }
  844
  845    fn to_any(&self) -> &dyn std::any::Any;
  846
  847    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  848        None
  849    }
  850}
  851
  852/// A set of caret positions, registered when the editor was edited.
  853pub struct ChangeList {
  854    changes: Vec<Vec<Anchor>>,
  855    /// Currently "selected" change.
  856    position: Option<usize>,
  857}
  858
  859impl ChangeList {
  860    pub fn new() -> Self {
  861        Self {
  862            changes: Vec::new(),
  863            position: None,
  864        }
  865    }
  866
  867    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  868    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  869    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  870        if self.changes.is_empty() {
  871            return None;
  872        }
  873
  874        let prev = self.position.unwrap_or(self.changes.len());
  875        let next = if direction == Direction::Prev {
  876            prev.saturating_sub(count)
  877        } else {
  878            (prev + count).min(self.changes.len() - 1)
  879        };
  880        self.position = Some(next);
  881        self.changes.get(next).map(|anchors| anchors.as_slice())
  882    }
  883
  884    /// Adds a new change to the list, resetting the change list position.
  885    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  886        self.position.take();
  887        if pop_state {
  888            self.changes.pop();
  889        }
  890        self.changes.push(new_positions.clone());
  891    }
  892
  893    pub fn last(&self) -> Option<&[Anchor]> {
  894        self.changes.last().map(|anchors| anchors.as_slice())
  895    }
  896}
  897
  898#[derive(Clone)]
  899struct InlineBlamePopoverState {
  900    scroll_handle: ScrollHandle,
  901    commit_message: Option<ParsedCommitMessage>,
  902    markdown: Entity<Markdown>,
  903}
  904
  905struct InlineBlamePopover {
  906    position: gpui::Point<Pixels>,
  907    show_task: Option<Task<()>>,
  908    hide_task: Option<Task<()>>,
  909    popover_bounds: Option<Bounds<Pixels>>,
  910    popover_state: InlineBlamePopoverState,
  911}
  912
  913/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  914/// a breakpoint on them.
  915#[derive(Clone, Copy, Debug)]
  916struct PhantomBreakpointIndicator {
  917    display_row: DisplayRow,
  918    /// There's a small debounce between hovering over the line and showing the indicator.
  919    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  920    is_active: bool,
  921    collides_with_existing_breakpoint: bool,
  922}
  923/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  924///
  925/// See the [module level documentation](self) for more information.
  926pub struct Editor {
  927    focus_handle: FocusHandle,
  928    last_focused_descendant: Option<WeakFocusHandle>,
  929    /// The text buffer being edited
  930    buffer: Entity<MultiBuffer>,
  931    /// Map of how text in the buffer should be displayed.
  932    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  933    pub display_map: Entity<DisplayMap>,
  934    pub selections: SelectionsCollection,
  935    pub scroll_manager: ScrollManager,
  936    /// When inline assist editors are linked, they all render cursors because
  937    /// typing enters text into each of them, even the ones that aren't focused.
  938    pub(crate) show_cursor_when_unfocused: bool,
  939    columnar_selection_tail: Option<Anchor>,
  940    columnar_display_point: Option<DisplayPoint>,
  941    add_selections_state: Option<AddSelectionsState>,
  942    select_next_state: Option<SelectNextState>,
  943    select_prev_state: Option<SelectNextState>,
  944    selection_history: SelectionHistory,
  945    defer_selection_effects: bool,
  946    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  947    autoclose_regions: Vec<AutocloseRegion>,
  948    snippet_stack: InvalidationStack<SnippetState>,
  949    select_syntax_node_history: SelectSyntaxNodeHistory,
  950    ime_transaction: Option<TransactionId>,
  951    pub diagnostics_max_severity: DiagnosticSeverity,
  952    active_diagnostics: ActiveDiagnostic,
  953    show_inline_diagnostics: bool,
  954    inline_diagnostics_update: Task<()>,
  955    inline_diagnostics_enabled: bool,
  956    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  957    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  958    hard_wrap: Option<usize>,
  959
  960    // TODO: make this a access method
  961    pub project: Option<Entity<Project>>,
  962    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  963    completion_provider: Option<Rc<dyn CompletionProvider>>,
  964    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  965    blink_manager: Entity<BlinkManager>,
  966    show_cursor_names: bool,
  967    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  968    pub show_local_selections: bool,
  969    mode: EditorMode,
  970    show_breadcrumbs: bool,
  971    show_gutter: bool,
  972    show_scrollbars: ScrollbarAxes,
  973    minimap_visibility: MinimapVisibility,
  974    offset_content: bool,
  975    disable_expand_excerpt_buttons: bool,
  976    show_line_numbers: Option<bool>,
  977    use_relative_line_numbers: Option<bool>,
  978    show_git_diff_gutter: Option<bool>,
  979    show_code_actions: Option<bool>,
  980    show_runnables: Option<bool>,
  981    show_breakpoints: Option<bool>,
  982    show_wrap_guides: Option<bool>,
  983    show_indent_guides: Option<bool>,
  984    placeholder_text: Option<Arc<str>>,
  985    highlight_order: usize,
  986    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  987    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  988    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  989    scrollbar_marker_state: ScrollbarMarkerState,
  990    active_indent_guides_state: ActiveIndentGuidesState,
  991    nav_history: Option<ItemNavHistory>,
  992    context_menu: RefCell<Option<CodeContextMenu>>,
  993    context_menu_options: Option<ContextMenuOptions>,
  994    mouse_context_menu: Option<MouseContextMenu>,
  995    completion_tasks: Vec<(CompletionId, Task<()>)>,
  996    inline_blame_popover: Option<InlineBlamePopover>,
  997    signature_help_state: SignatureHelpState,
  998    auto_signature_help: Option<bool>,
  999    find_all_references_task_sources: Vec<Anchor>,
 1000    next_completion_id: CompletionId,
 1001    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1002    code_actions_task: Option<Task<Result<()>>>,
 1003    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1004    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1005    document_highlights_task: Option<Task<()>>,
 1006    linked_editing_range_task: Option<Task<Option<()>>>,
 1007    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1008    pending_rename: Option<RenameState>,
 1009    searchable: bool,
 1010    cursor_shape: CursorShape,
 1011    current_line_highlight: Option<CurrentLineHighlight>,
 1012    collapse_matches: bool,
 1013    autoindent_mode: Option<AutoindentMode>,
 1014    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1015    input_enabled: bool,
 1016    use_modal_editing: bool,
 1017    read_only: bool,
 1018    leader_id: Option<CollaboratorId>,
 1019    remote_id: Option<ViewId>,
 1020    pub hover_state: HoverState,
 1021    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1022    gutter_hovered: bool,
 1023    hovered_link_state: Option<HoveredLinkState>,
 1024    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1025    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1026    active_inline_completion: Option<InlineCompletionState>,
 1027    /// Used to prevent flickering as the user types while the menu is open
 1028    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1029    edit_prediction_settings: EditPredictionSettings,
 1030    inline_completions_hidden_for_vim_mode: bool,
 1031    show_inline_completions_override: Option<bool>,
 1032    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1033    edit_prediction_preview: EditPredictionPreview,
 1034    edit_prediction_indent_conflict: bool,
 1035    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1036    inlay_hint_cache: InlayHintCache,
 1037    next_inlay_id: usize,
 1038    _subscriptions: Vec<Subscription>,
 1039    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1040    gutter_dimensions: GutterDimensions,
 1041    style: Option<EditorStyle>,
 1042    text_style_refinement: Option<TextStyleRefinement>,
 1043    next_editor_action_id: EditorActionId,
 1044    editor_actions:
 1045        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1046    use_autoclose: bool,
 1047    use_auto_surround: bool,
 1048    auto_replace_emoji_shortcode: bool,
 1049    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1050    show_git_blame_gutter: bool,
 1051    show_git_blame_inline: bool,
 1052    show_git_blame_inline_delay_task: Option<Task<()>>,
 1053    git_blame_inline_enabled: bool,
 1054    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1055    serialize_dirty_buffers: bool,
 1056    show_selection_menu: Option<bool>,
 1057    blame: Option<Entity<GitBlame>>,
 1058    blame_subscription: Option<Subscription>,
 1059    custom_context_menu: Option<
 1060        Box<
 1061            dyn 'static
 1062                + Fn(
 1063                    &mut Self,
 1064                    DisplayPoint,
 1065                    &mut Window,
 1066                    &mut Context<Self>,
 1067                ) -> Option<Entity<ui::ContextMenu>>,
 1068        >,
 1069    >,
 1070    last_bounds: Option<Bounds<Pixels>>,
 1071    last_position_map: Option<Rc<PositionMap>>,
 1072    expect_bounds_change: Option<Bounds<Pixels>>,
 1073    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1074    tasks_update_task: Option<Task<()>>,
 1075    breakpoint_store: Option<Entity<BreakpointStore>>,
 1076    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1077    pull_diagnostics_task: Task<()>,
 1078    in_project_search: bool,
 1079    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1080    breadcrumb_header: Option<String>,
 1081    focused_block: Option<FocusedBlock>,
 1082    next_scroll_position: NextScrollCursorCenterTopBottom,
 1083    addons: HashMap<TypeId, Box<dyn Addon>>,
 1084    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1085    load_diff_task: Option<Shared<Task<()>>>,
 1086    /// Whether we are temporarily displaying a diff other than git's
 1087    temporary_diff_override: bool,
 1088    selection_mark_mode: bool,
 1089    toggle_fold_multiple_buffers: Task<()>,
 1090    _scroll_cursor_center_top_bottom_task: Task<()>,
 1091    serialize_selections: Task<()>,
 1092    serialize_folds: Task<()>,
 1093    mouse_cursor_hidden: bool,
 1094    minimap: Option<Entity<Self>>,
 1095    hide_mouse_mode: HideMouseMode,
 1096    pub change_list: ChangeList,
 1097    inline_value_cache: InlineValueCache,
 1098}
 1099
 1100#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1101enum NextScrollCursorCenterTopBottom {
 1102    #[default]
 1103    Center,
 1104    Top,
 1105    Bottom,
 1106}
 1107
 1108impl NextScrollCursorCenterTopBottom {
 1109    fn next(&self) -> Self {
 1110        match self {
 1111            Self::Center => Self::Top,
 1112            Self::Top => Self::Bottom,
 1113            Self::Bottom => Self::Center,
 1114        }
 1115    }
 1116}
 1117
 1118#[derive(Clone)]
 1119pub struct EditorSnapshot {
 1120    pub mode: EditorMode,
 1121    show_gutter: bool,
 1122    show_line_numbers: Option<bool>,
 1123    show_git_diff_gutter: Option<bool>,
 1124    show_code_actions: Option<bool>,
 1125    show_runnables: Option<bool>,
 1126    show_breakpoints: Option<bool>,
 1127    git_blame_gutter_max_author_length: Option<usize>,
 1128    pub display_snapshot: DisplaySnapshot,
 1129    pub placeholder_text: Option<Arc<str>>,
 1130    is_focused: bool,
 1131    scroll_anchor: ScrollAnchor,
 1132    ongoing_scroll: OngoingScroll,
 1133    current_line_highlight: CurrentLineHighlight,
 1134    gutter_hovered: bool,
 1135}
 1136
 1137#[derive(Default, Debug, Clone, Copy)]
 1138pub struct GutterDimensions {
 1139    pub left_padding: Pixels,
 1140    pub right_padding: Pixels,
 1141    pub width: Pixels,
 1142    pub margin: Pixels,
 1143    pub git_blame_entries_width: Option<Pixels>,
 1144}
 1145
 1146impl GutterDimensions {
 1147    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1148        Self {
 1149            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1150            ..Default::default()
 1151        }
 1152    }
 1153
 1154    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1155        -cx.text_system().descent(font_id, font_size)
 1156    }
 1157    /// The full width of the space taken up by the gutter.
 1158    pub fn full_width(&self) -> Pixels {
 1159        self.margin + self.width
 1160    }
 1161
 1162    /// The width of the space reserved for the fold indicators,
 1163    /// use alongside 'justify_end' and `gutter_width` to
 1164    /// right align content with the line numbers
 1165    pub fn fold_area_width(&self) -> Pixels {
 1166        self.margin + self.right_padding
 1167    }
 1168}
 1169
 1170#[derive(Debug)]
 1171pub struct RemoteSelection {
 1172    pub replica_id: ReplicaId,
 1173    pub selection: Selection<Anchor>,
 1174    pub cursor_shape: CursorShape,
 1175    pub collaborator_id: CollaboratorId,
 1176    pub line_mode: bool,
 1177    pub user_name: Option<SharedString>,
 1178    pub color: PlayerColor,
 1179}
 1180
 1181#[derive(Clone, Debug)]
 1182struct SelectionHistoryEntry {
 1183    selections: Arc<[Selection<Anchor>]>,
 1184    select_next_state: Option<SelectNextState>,
 1185    select_prev_state: Option<SelectNextState>,
 1186    add_selections_state: Option<AddSelectionsState>,
 1187}
 1188
 1189enum SelectionHistoryMode {
 1190    Normal,
 1191    Undoing,
 1192    Redoing,
 1193}
 1194
 1195#[derive(Clone, PartialEq, Eq, Hash)]
 1196struct HoveredCursor {
 1197    replica_id: u16,
 1198    selection_id: usize,
 1199}
 1200
 1201impl Default for SelectionHistoryMode {
 1202    fn default() -> Self {
 1203        Self::Normal
 1204    }
 1205}
 1206
 1207struct DeferredSelectionEffectsState {
 1208    changed: bool,
 1209    should_update_completions: bool,
 1210    autoscroll: Option<Autoscroll>,
 1211    old_cursor_position: Anchor,
 1212    history_entry: SelectionHistoryEntry,
 1213}
 1214
 1215#[derive(Default)]
 1216struct SelectionHistory {
 1217    #[allow(clippy::type_complexity)]
 1218    selections_by_transaction:
 1219        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1220    mode: SelectionHistoryMode,
 1221    undo_stack: VecDeque<SelectionHistoryEntry>,
 1222    redo_stack: VecDeque<SelectionHistoryEntry>,
 1223}
 1224
 1225impl SelectionHistory {
 1226    fn insert_transaction(
 1227        &mut self,
 1228        transaction_id: TransactionId,
 1229        selections: Arc<[Selection<Anchor>]>,
 1230    ) {
 1231        self.selections_by_transaction
 1232            .insert(transaction_id, (selections, None));
 1233    }
 1234
 1235    #[allow(clippy::type_complexity)]
 1236    fn transaction(
 1237        &self,
 1238        transaction_id: TransactionId,
 1239    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1240        self.selections_by_transaction.get(&transaction_id)
 1241    }
 1242
 1243    #[allow(clippy::type_complexity)]
 1244    fn transaction_mut(
 1245        &mut self,
 1246        transaction_id: TransactionId,
 1247    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1248        self.selections_by_transaction.get_mut(&transaction_id)
 1249    }
 1250
 1251    fn push(&mut self, entry: SelectionHistoryEntry) {
 1252        if !entry.selections.is_empty() {
 1253            match self.mode {
 1254                SelectionHistoryMode::Normal => {
 1255                    self.push_undo(entry);
 1256                    self.redo_stack.clear();
 1257                }
 1258                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1259                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1260            }
 1261        }
 1262    }
 1263
 1264    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1265        if self
 1266            .undo_stack
 1267            .back()
 1268            .map_or(true, |e| e.selections != entry.selections)
 1269        {
 1270            self.undo_stack.push_back(entry);
 1271            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1272                self.undo_stack.pop_front();
 1273            }
 1274        }
 1275    }
 1276
 1277    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1278        if self
 1279            .redo_stack
 1280            .back()
 1281            .map_or(true, |e| e.selections != entry.selections)
 1282        {
 1283            self.redo_stack.push_back(entry);
 1284            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1285                self.redo_stack.pop_front();
 1286            }
 1287        }
 1288    }
 1289}
 1290
 1291#[derive(Clone, Copy)]
 1292pub struct RowHighlightOptions {
 1293    pub autoscroll: bool,
 1294    pub include_gutter: bool,
 1295}
 1296
 1297impl Default for RowHighlightOptions {
 1298    fn default() -> Self {
 1299        Self {
 1300            autoscroll: Default::default(),
 1301            include_gutter: true,
 1302        }
 1303    }
 1304}
 1305
 1306struct RowHighlight {
 1307    index: usize,
 1308    range: Range<Anchor>,
 1309    color: Hsla,
 1310    options: RowHighlightOptions,
 1311    type_id: TypeId,
 1312}
 1313
 1314#[derive(Clone, Debug)]
 1315struct AddSelectionsState {
 1316    groups: Vec<AddSelectionsGroup>,
 1317}
 1318
 1319#[derive(Clone, Debug)]
 1320struct AddSelectionsGroup {
 1321    above: bool,
 1322    stack: Vec<usize>,
 1323}
 1324
 1325#[derive(Clone)]
 1326struct SelectNextState {
 1327    query: AhoCorasick,
 1328    wordwise: bool,
 1329    done: bool,
 1330}
 1331
 1332impl std::fmt::Debug for SelectNextState {
 1333    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1334        f.debug_struct(std::any::type_name::<Self>())
 1335            .field("wordwise", &self.wordwise)
 1336            .field("done", &self.done)
 1337            .finish()
 1338    }
 1339}
 1340
 1341#[derive(Debug)]
 1342struct AutocloseRegion {
 1343    selection_id: usize,
 1344    range: Range<Anchor>,
 1345    pair: BracketPair,
 1346}
 1347
 1348#[derive(Debug)]
 1349struct SnippetState {
 1350    ranges: Vec<Vec<Range<Anchor>>>,
 1351    active_index: usize,
 1352    choices: Vec<Option<Vec<String>>>,
 1353}
 1354
 1355#[doc(hidden)]
 1356pub struct RenameState {
 1357    pub range: Range<Anchor>,
 1358    pub old_name: Arc<str>,
 1359    pub editor: Entity<Editor>,
 1360    block_id: CustomBlockId,
 1361}
 1362
 1363struct InvalidationStack<T>(Vec<T>);
 1364
 1365struct RegisteredInlineCompletionProvider {
 1366    provider: Arc<dyn InlineCompletionProviderHandle>,
 1367    _subscription: Subscription,
 1368}
 1369
 1370#[derive(Debug, PartialEq, Eq)]
 1371pub struct ActiveDiagnosticGroup {
 1372    pub active_range: Range<Anchor>,
 1373    pub active_message: String,
 1374    pub group_id: usize,
 1375    pub blocks: HashSet<CustomBlockId>,
 1376}
 1377
 1378#[derive(Debug, PartialEq, Eq)]
 1379
 1380pub(crate) enum ActiveDiagnostic {
 1381    None,
 1382    All,
 1383    Group(ActiveDiagnosticGroup),
 1384}
 1385
 1386#[derive(Serialize, Deserialize, Clone, Debug)]
 1387pub struct ClipboardSelection {
 1388    /// The number of bytes in this selection.
 1389    pub len: usize,
 1390    /// Whether this was a full-line selection.
 1391    pub is_entire_line: bool,
 1392    /// The indentation of the first line when this content was originally copied.
 1393    pub first_line_indent: u32,
 1394}
 1395
 1396// selections, scroll behavior, was newest selection reversed
 1397type SelectSyntaxNodeHistoryState = (
 1398    Box<[Selection<usize>]>,
 1399    SelectSyntaxNodeScrollBehavior,
 1400    bool,
 1401);
 1402
 1403#[derive(Default)]
 1404struct SelectSyntaxNodeHistory {
 1405    stack: Vec<SelectSyntaxNodeHistoryState>,
 1406    // disable temporarily to allow changing selections without losing the stack
 1407    pub disable_clearing: bool,
 1408}
 1409
 1410impl SelectSyntaxNodeHistory {
 1411    pub fn try_clear(&mut self) {
 1412        if !self.disable_clearing {
 1413            self.stack.clear();
 1414        }
 1415    }
 1416
 1417    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1418        self.stack.push(selection);
 1419    }
 1420
 1421    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1422        self.stack.pop()
 1423    }
 1424}
 1425
 1426enum SelectSyntaxNodeScrollBehavior {
 1427    CursorTop,
 1428    FitSelection,
 1429    CursorBottom,
 1430}
 1431
 1432#[derive(Debug)]
 1433pub(crate) struct NavigationData {
 1434    cursor_anchor: Anchor,
 1435    cursor_position: Point,
 1436    scroll_anchor: ScrollAnchor,
 1437    scroll_top_row: u32,
 1438}
 1439
 1440#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1441pub enum GotoDefinitionKind {
 1442    Symbol,
 1443    Declaration,
 1444    Type,
 1445    Implementation,
 1446}
 1447
 1448#[derive(Debug, Clone)]
 1449enum InlayHintRefreshReason {
 1450    ModifiersChanged(bool),
 1451    Toggle(bool),
 1452    SettingsChange(InlayHintSettings),
 1453    NewLinesShown,
 1454    BufferEdited(HashSet<Arc<Language>>),
 1455    RefreshRequested,
 1456    ExcerptsRemoved(Vec<ExcerptId>),
 1457}
 1458
 1459impl InlayHintRefreshReason {
 1460    fn description(&self) -> &'static str {
 1461        match self {
 1462            Self::ModifiersChanged(_) => "modifiers changed",
 1463            Self::Toggle(_) => "toggle",
 1464            Self::SettingsChange(_) => "settings change",
 1465            Self::NewLinesShown => "new lines shown",
 1466            Self::BufferEdited(_) => "buffer edited",
 1467            Self::RefreshRequested => "refresh requested",
 1468            Self::ExcerptsRemoved(_) => "excerpts removed",
 1469        }
 1470    }
 1471}
 1472
 1473pub enum FormatTarget {
 1474    Buffers,
 1475    Ranges(Vec<Range<MultiBufferPoint>>),
 1476}
 1477
 1478pub(crate) struct FocusedBlock {
 1479    id: BlockId,
 1480    focus_handle: WeakFocusHandle,
 1481}
 1482
 1483#[derive(Clone)]
 1484enum JumpData {
 1485    MultiBufferRow {
 1486        row: MultiBufferRow,
 1487        line_offset_from_top: u32,
 1488    },
 1489    MultiBufferPoint {
 1490        excerpt_id: ExcerptId,
 1491        position: Point,
 1492        anchor: text::Anchor,
 1493        line_offset_from_top: u32,
 1494    },
 1495}
 1496
 1497pub enum MultibufferSelectionMode {
 1498    First,
 1499    All,
 1500}
 1501
 1502#[derive(Clone, Copy, Debug, Default)]
 1503pub struct RewrapOptions {
 1504    pub override_language_settings: bool,
 1505    pub preserve_existing_whitespace: bool,
 1506}
 1507
 1508impl Editor {
 1509    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1510        let buffer = cx.new(|cx| Buffer::local("", cx));
 1511        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1512        Self::new(
 1513            EditorMode::SingleLine { auto_width: false },
 1514            buffer,
 1515            None,
 1516            window,
 1517            cx,
 1518        )
 1519    }
 1520
 1521    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1522        let buffer = cx.new(|cx| Buffer::local("", cx));
 1523        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1524        Self::new(EditorMode::full(), buffer, None, window, cx)
 1525    }
 1526
 1527    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1528        let buffer = cx.new(|cx| Buffer::local("", cx));
 1529        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1530        Self::new(
 1531            EditorMode::SingleLine { auto_width: true },
 1532            buffer,
 1533            None,
 1534            window,
 1535            cx,
 1536        )
 1537    }
 1538
 1539    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1540        let buffer = cx.new(|cx| Buffer::local("", cx));
 1541        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1542        Self::new(
 1543            EditorMode::AutoHeight { max_lines },
 1544            buffer,
 1545            None,
 1546            window,
 1547            cx,
 1548        )
 1549    }
 1550
 1551    pub fn for_buffer(
 1552        buffer: Entity<Buffer>,
 1553        project: Option<Entity<Project>>,
 1554        window: &mut Window,
 1555        cx: &mut Context<Self>,
 1556    ) -> Self {
 1557        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1558        Self::new(EditorMode::full(), buffer, project, window, cx)
 1559    }
 1560
 1561    pub fn for_multibuffer(
 1562        buffer: Entity<MultiBuffer>,
 1563        project: Option<Entity<Project>>,
 1564        window: &mut Window,
 1565        cx: &mut Context<Self>,
 1566    ) -> Self {
 1567        Self::new(EditorMode::full(), buffer, project, window, cx)
 1568    }
 1569
 1570    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1571        let mut clone = Self::new(
 1572            self.mode.clone(),
 1573            self.buffer.clone(),
 1574            self.project.clone(),
 1575            window,
 1576            cx,
 1577        );
 1578        self.display_map.update(cx, |display_map, cx| {
 1579            let snapshot = display_map.snapshot(cx);
 1580            clone.display_map.update(cx, |display_map, cx| {
 1581                display_map.set_state(&snapshot, cx);
 1582            });
 1583        });
 1584        clone.folds_did_change(cx);
 1585        clone.selections.clone_state(&self.selections);
 1586        clone.scroll_manager.clone_state(&self.scroll_manager);
 1587        clone.searchable = self.searchable;
 1588        clone.read_only = self.read_only;
 1589        clone
 1590    }
 1591
 1592    pub fn new(
 1593        mode: EditorMode,
 1594        buffer: Entity<MultiBuffer>,
 1595        project: Option<Entity<Project>>,
 1596        window: &mut Window,
 1597        cx: &mut Context<Self>,
 1598    ) -> Self {
 1599        Editor::new_internal(mode, buffer, project, None, window, cx)
 1600    }
 1601
 1602    fn new_internal(
 1603        mode: EditorMode,
 1604        buffer: Entity<MultiBuffer>,
 1605        project: Option<Entity<Project>>,
 1606        display_map: Option<Entity<DisplayMap>>,
 1607        window: &mut Window,
 1608        cx: &mut Context<Self>,
 1609    ) -> Self {
 1610        debug_assert!(
 1611            display_map.is_none() || mode.is_minimap(),
 1612            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1613        );
 1614
 1615        let full_mode = mode.is_full();
 1616        let diagnostics_max_severity = if full_mode {
 1617            EditorSettings::get_global(cx)
 1618                .diagnostics_max_severity
 1619                .unwrap_or(DiagnosticSeverity::Hint)
 1620        } else {
 1621            DiagnosticSeverity::Off
 1622        };
 1623        let style = window.text_style();
 1624        let font_size = style.font_size.to_pixels(window.rem_size());
 1625        let editor = cx.entity().downgrade();
 1626        let fold_placeholder = FoldPlaceholder {
 1627            constrain_width: true,
 1628            render: Arc::new(move |fold_id, fold_range, cx| {
 1629                let editor = editor.clone();
 1630                div()
 1631                    .id(fold_id)
 1632                    .bg(cx.theme().colors().ghost_element_background)
 1633                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1634                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1635                    .rounded_xs()
 1636                    .size_full()
 1637                    .cursor_pointer()
 1638                    .child("")
 1639                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1640                    .on_click(move |_, _window, cx| {
 1641                        editor
 1642                            .update(cx, |editor, cx| {
 1643                                editor.unfold_ranges(
 1644                                    &[fold_range.start..fold_range.end],
 1645                                    true,
 1646                                    false,
 1647                                    cx,
 1648                                );
 1649                                cx.stop_propagation();
 1650                            })
 1651                            .ok();
 1652                    })
 1653                    .into_any()
 1654            }),
 1655            merge_adjacent: true,
 1656            ..FoldPlaceholder::default()
 1657        };
 1658        let display_map = display_map.unwrap_or_else(|| {
 1659            cx.new(|cx| {
 1660                DisplayMap::new(
 1661                    buffer.clone(),
 1662                    style.font(),
 1663                    font_size,
 1664                    None,
 1665                    FILE_HEADER_HEIGHT,
 1666                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1667                    fold_placeholder,
 1668                    diagnostics_max_severity,
 1669                    cx,
 1670                )
 1671            })
 1672        });
 1673
 1674        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1675
 1676        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1677
 1678        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1679            .then(|| language_settings::SoftWrap::None);
 1680
 1681        let mut project_subscriptions = Vec::new();
 1682        if mode.is_full() {
 1683            if let Some(project) = project.as_ref() {
 1684                project_subscriptions.push(cx.subscribe_in(
 1685                    project,
 1686                    window,
 1687                    |editor, _, event, window, cx| match event {
 1688                        project::Event::RefreshCodeLens => {
 1689                            // we always query lens with actions, without storing them, always refreshing them
 1690                        }
 1691                        project::Event::RefreshInlayHints => {
 1692                            editor
 1693                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1694                        }
 1695                        project::Event::LanguageServerAdded(..)
 1696                        | project::Event::LanguageServerRemoved(..) => {
 1697                            if editor.tasks_update_task.is_none() {
 1698                                editor.tasks_update_task =
 1699                                    Some(editor.refresh_runnables(window, cx));
 1700                            }
 1701                            editor.pull_diagnostics(window, cx);
 1702                        }
 1703                        project::Event::PullWorkspaceDiagnostics => {
 1704                            editor.pull_diagnostics(window, cx);
 1705                        }
 1706                        project::Event::SnippetEdit(id, snippet_edits) => {
 1707                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1708                                let focus_handle = editor.focus_handle(cx);
 1709                                if focus_handle.is_focused(window) {
 1710                                    let snapshot = buffer.read(cx).snapshot();
 1711                                    for (range, snippet) in snippet_edits {
 1712                                        let editor_range =
 1713                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1714                                        editor
 1715                                            .insert_snippet(
 1716                                                &[editor_range],
 1717                                                snippet.clone(),
 1718                                                window,
 1719                                                cx,
 1720                                            )
 1721                                            .ok();
 1722                                    }
 1723                                }
 1724                            }
 1725                        }
 1726                        _ => {}
 1727                    },
 1728                ));
 1729                if let Some(task_inventory) = project
 1730                    .read(cx)
 1731                    .task_store()
 1732                    .read(cx)
 1733                    .task_inventory()
 1734                    .cloned()
 1735                {
 1736                    project_subscriptions.push(cx.observe_in(
 1737                        &task_inventory,
 1738                        window,
 1739                        |editor, _, window, cx| {
 1740                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1741                        },
 1742                    ));
 1743                };
 1744
 1745                project_subscriptions.push(cx.subscribe_in(
 1746                    &project.read(cx).breakpoint_store(),
 1747                    window,
 1748                    |editor, _, event, window, cx| match event {
 1749                        BreakpointStoreEvent::ClearDebugLines => {
 1750                            editor.clear_row_highlights::<ActiveDebugLine>();
 1751                            editor.refresh_inline_values(cx);
 1752                        }
 1753                        BreakpointStoreEvent::SetDebugLine => {
 1754                            if editor.go_to_active_debug_line(window, cx) {
 1755                                cx.stop_propagation();
 1756                            }
 1757
 1758                            editor.refresh_inline_values(cx);
 1759                        }
 1760                        _ => {}
 1761                    },
 1762                ));
 1763            }
 1764        }
 1765
 1766        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1767
 1768        let inlay_hint_settings =
 1769            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1770        let focus_handle = cx.focus_handle();
 1771        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1772            .detach();
 1773        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1774            .detach();
 1775        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1776            .detach();
 1777        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1778            .detach();
 1779
 1780        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1781            Some(false)
 1782        } else {
 1783            None
 1784        };
 1785
 1786        let breakpoint_store = match (&mode, project.as_ref()) {
 1787            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1788            _ => None,
 1789        };
 1790
 1791        let mut code_action_providers = Vec::new();
 1792        let mut load_uncommitted_diff = None;
 1793        if let Some(project) = project.clone() {
 1794            load_uncommitted_diff = Some(
 1795                update_uncommitted_diff_for_buffer(
 1796                    cx.entity(),
 1797                    &project,
 1798                    buffer.read(cx).all_buffers(),
 1799                    buffer.clone(),
 1800                    cx,
 1801                )
 1802                .shared(),
 1803            );
 1804            code_action_providers.push(Rc::new(project) as Rc<_>);
 1805        }
 1806
 1807        let mut editor = Self {
 1808            focus_handle,
 1809            show_cursor_when_unfocused: false,
 1810            last_focused_descendant: None,
 1811            buffer: buffer.clone(),
 1812            display_map: display_map.clone(),
 1813            selections,
 1814            scroll_manager: ScrollManager::new(cx),
 1815            columnar_selection_tail: None,
 1816            columnar_display_point: None,
 1817            add_selections_state: None,
 1818            select_next_state: None,
 1819            select_prev_state: None,
 1820            selection_history: SelectionHistory::default(),
 1821            defer_selection_effects: false,
 1822            deferred_selection_effects_state: None,
 1823            autoclose_regions: Vec::new(),
 1824            snippet_stack: InvalidationStack::default(),
 1825            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1826            ime_transaction: None,
 1827            active_diagnostics: ActiveDiagnostic::None,
 1828            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1829            inline_diagnostics_update: Task::ready(()),
 1830            inline_diagnostics: Vec::new(),
 1831            soft_wrap_mode_override,
 1832            diagnostics_max_severity,
 1833            hard_wrap: None,
 1834            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1835            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1836            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1837            project,
 1838            blink_manager: blink_manager.clone(),
 1839            show_local_selections: true,
 1840            show_scrollbars: ScrollbarAxes {
 1841                horizontal: full_mode,
 1842                vertical: full_mode,
 1843            },
 1844            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1845            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1846            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1847            show_gutter: mode.is_full(),
 1848            show_line_numbers: None,
 1849            use_relative_line_numbers: None,
 1850            disable_expand_excerpt_buttons: false,
 1851            show_git_diff_gutter: None,
 1852            show_code_actions: None,
 1853            show_runnables: None,
 1854            show_breakpoints: None,
 1855            show_wrap_guides: None,
 1856            show_indent_guides,
 1857            placeholder_text: None,
 1858            highlight_order: 0,
 1859            highlighted_rows: HashMap::default(),
 1860            background_highlights: TreeMap::default(),
 1861            gutter_highlights: TreeMap::default(),
 1862            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1863            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1864            nav_history: None,
 1865            context_menu: RefCell::new(None),
 1866            context_menu_options: None,
 1867            mouse_context_menu: None,
 1868            completion_tasks: Vec::new(),
 1869            inline_blame_popover: None,
 1870            signature_help_state: SignatureHelpState::default(),
 1871            auto_signature_help: None,
 1872            find_all_references_task_sources: Vec::new(),
 1873            next_completion_id: 0,
 1874            next_inlay_id: 0,
 1875            code_action_providers,
 1876            available_code_actions: None,
 1877            code_actions_task: None,
 1878            quick_selection_highlight_task: None,
 1879            debounced_selection_highlight_task: None,
 1880            document_highlights_task: None,
 1881            linked_editing_range_task: None,
 1882            pending_rename: None,
 1883            searchable: true,
 1884            cursor_shape: EditorSettings::get_global(cx)
 1885                .cursor_shape
 1886                .unwrap_or_default(),
 1887            current_line_highlight: None,
 1888            autoindent_mode: Some(AutoindentMode::EachLine),
 1889            collapse_matches: false,
 1890            workspace: None,
 1891            input_enabled: true,
 1892            use_modal_editing: mode.is_full(),
 1893            read_only: mode.is_minimap(),
 1894            use_autoclose: true,
 1895            use_auto_surround: true,
 1896            auto_replace_emoji_shortcode: false,
 1897            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1898            leader_id: None,
 1899            remote_id: None,
 1900            hover_state: HoverState::default(),
 1901            pending_mouse_down: None,
 1902            hovered_link_state: None,
 1903            edit_prediction_provider: None,
 1904            active_inline_completion: None,
 1905            stale_inline_completion_in_menu: None,
 1906            edit_prediction_preview: EditPredictionPreview::Inactive {
 1907                released_too_fast: false,
 1908            },
 1909            inline_diagnostics_enabled: mode.is_full(),
 1910            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1911            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1912
 1913            gutter_hovered: false,
 1914            pixel_position_of_newest_cursor: None,
 1915            last_bounds: None,
 1916            last_position_map: None,
 1917            expect_bounds_change: None,
 1918            gutter_dimensions: GutterDimensions::default(),
 1919            style: None,
 1920            show_cursor_names: false,
 1921            hovered_cursors: HashMap::default(),
 1922            next_editor_action_id: EditorActionId::default(),
 1923            editor_actions: Rc::default(),
 1924            inline_completions_hidden_for_vim_mode: false,
 1925            show_inline_completions_override: None,
 1926            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1927            edit_prediction_settings: EditPredictionSettings::Disabled,
 1928            edit_prediction_indent_conflict: false,
 1929            edit_prediction_requires_modifier_in_indent_conflict: true,
 1930            custom_context_menu: None,
 1931            show_git_blame_gutter: false,
 1932            show_git_blame_inline: false,
 1933            show_selection_menu: None,
 1934            show_git_blame_inline_delay_task: None,
 1935            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1936            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1937            serialize_dirty_buffers: !mode.is_minimap()
 1938                && ProjectSettings::get_global(cx)
 1939                    .session
 1940                    .restore_unsaved_buffers,
 1941            blame: None,
 1942            blame_subscription: None,
 1943            tasks: BTreeMap::default(),
 1944
 1945            breakpoint_store,
 1946            gutter_breakpoint_indicator: (None, None),
 1947            _subscriptions: vec![
 1948                cx.observe(&buffer, Self::on_buffer_changed),
 1949                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1950                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1951                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1952                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1953                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1954                cx.observe_window_activation(window, |editor, window, cx| {
 1955                    let active = window.is_window_active();
 1956                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1957                        if active {
 1958                            blink_manager.enable(cx);
 1959                        } else {
 1960                            blink_manager.disable(cx);
 1961                        }
 1962                    });
 1963                    if active {
 1964                        editor.show_mouse_cursor();
 1965                    }
 1966                }),
 1967            ],
 1968            tasks_update_task: None,
 1969            pull_diagnostics_task: Task::ready(()),
 1970            linked_edit_ranges: Default::default(),
 1971            in_project_search: false,
 1972            previous_search_ranges: None,
 1973            breadcrumb_header: None,
 1974            focused_block: None,
 1975            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1976            addons: HashMap::default(),
 1977            registered_buffers: HashMap::default(),
 1978            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1979            selection_mark_mode: false,
 1980            toggle_fold_multiple_buffers: Task::ready(()),
 1981            serialize_selections: Task::ready(()),
 1982            serialize_folds: Task::ready(()),
 1983            text_style_refinement: None,
 1984            load_diff_task: load_uncommitted_diff,
 1985            temporary_diff_override: false,
 1986            mouse_cursor_hidden: false,
 1987            minimap: None,
 1988            hide_mouse_mode: EditorSettings::get_global(cx)
 1989                .hide_mouse
 1990                .unwrap_or_default(),
 1991            change_list: ChangeList::new(),
 1992            mode,
 1993        };
 1994        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 1995            editor
 1996                ._subscriptions
 1997                .push(cx.observe(breakpoints, |_, _, cx| {
 1998                    cx.notify();
 1999                }));
 2000        }
 2001        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2002        editor._subscriptions.extend(project_subscriptions);
 2003
 2004        editor._subscriptions.push(cx.subscribe_in(
 2005            &cx.entity(),
 2006            window,
 2007            |editor, _, e: &EditorEvent, window, cx| match e {
 2008                EditorEvent::ScrollPositionChanged { local, .. } => {
 2009                    if *local {
 2010                        let new_anchor = editor.scroll_manager.anchor();
 2011                        let snapshot = editor.snapshot(window, cx);
 2012                        editor.update_restoration_data(cx, move |data| {
 2013                            data.scroll_position = (
 2014                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2015                                new_anchor.offset,
 2016                            );
 2017                        });
 2018                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2019                        editor.inline_blame_popover.take();
 2020                    }
 2021                }
 2022                EditorEvent::Edited { .. } => {
 2023                    if !vim_enabled(cx) {
 2024                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2025                        let pop_state = editor
 2026                            .change_list
 2027                            .last()
 2028                            .map(|previous| {
 2029                                previous.len() == selections.len()
 2030                                    && previous.iter().enumerate().all(|(ix, p)| {
 2031                                        p.to_display_point(&map).row()
 2032                                            == selections[ix].head().row()
 2033                                    })
 2034                            })
 2035                            .unwrap_or(false);
 2036                        let new_positions = selections
 2037                            .into_iter()
 2038                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2039                            .collect();
 2040                        editor
 2041                            .change_list
 2042                            .push_to_change_list(pop_state, new_positions);
 2043                    }
 2044                }
 2045                _ => (),
 2046            },
 2047        ));
 2048
 2049        if let Some(dap_store) = editor
 2050            .project
 2051            .as_ref()
 2052            .map(|project| project.read(cx).dap_store())
 2053        {
 2054            let weak_editor = cx.weak_entity();
 2055
 2056            editor
 2057                ._subscriptions
 2058                .push(
 2059                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2060                        let session_entity = cx.entity();
 2061                        weak_editor
 2062                            .update(cx, |editor, cx| {
 2063                                editor._subscriptions.push(
 2064                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2065                                );
 2066                            })
 2067                            .ok();
 2068                    }),
 2069                );
 2070
 2071            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2072                editor
 2073                    ._subscriptions
 2074                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2075            }
 2076        }
 2077
 2078        editor.end_selection(window, cx);
 2079        editor.scroll_manager.show_scrollbars(window, cx);
 2080        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2081
 2082        if full_mode {
 2083            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2084            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2085
 2086            if editor.git_blame_inline_enabled {
 2087                editor.start_git_blame_inline(false, window, cx);
 2088            }
 2089
 2090            editor.go_to_active_debug_line(window, cx);
 2091
 2092            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2093                if let Some(project) = editor.project.as_ref() {
 2094                    let handle = project.update(cx, |project, cx| {
 2095                        project.register_buffer_with_language_servers(&buffer, cx)
 2096                    });
 2097                    editor
 2098                        .registered_buffers
 2099                        .insert(buffer.read(cx).remote_id(), handle);
 2100                }
 2101            }
 2102
 2103            editor.minimap =
 2104                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2105            editor.pull_diagnostics(window, cx);
 2106        }
 2107
 2108        editor.report_editor_event("Editor Opened", None, cx);
 2109        editor
 2110    }
 2111
 2112    pub fn deploy_mouse_context_menu(
 2113        &mut self,
 2114        position: gpui::Point<Pixels>,
 2115        context_menu: Entity<ContextMenu>,
 2116        window: &mut Window,
 2117        cx: &mut Context<Self>,
 2118    ) {
 2119        self.mouse_context_menu = Some(MouseContextMenu::new(
 2120            self,
 2121            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2122            context_menu,
 2123            window,
 2124            cx,
 2125        ));
 2126    }
 2127
 2128    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2129        self.mouse_context_menu
 2130            .as_ref()
 2131            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2132    }
 2133
 2134    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2135        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2136    }
 2137
 2138    fn key_context_internal(
 2139        &self,
 2140        has_active_edit_prediction: bool,
 2141        window: &Window,
 2142        cx: &App,
 2143    ) -> KeyContext {
 2144        let mut key_context = KeyContext::new_with_defaults();
 2145        key_context.add("Editor");
 2146        let mode = match self.mode {
 2147            EditorMode::SingleLine { .. } => "single_line",
 2148            EditorMode::AutoHeight { .. } => "auto_height",
 2149            EditorMode::Minimap { .. } => "minimap",
 2150            EditorMode::Full { .. } => "full",
 2151        };
 2152
 2153        if EditorSettings::jupyter_enabled(cx) {
 2154            key_context.add("jupyter");
 2155        }
 2156
 2157        key_context.set("mode", mode);
 2158        if self.pending_rename.is_some() {
 2159            key_context.add("renaming");
 2160        }
 2161
 2162        match self.context_menu.borrow().as_ref() {
 2163            Some(CodeContextMenu::Completions(_)) => {
 2164                key_context.add("menu");
 2165                key_context.add("showing_completions");
 2166            }
 2167            Some(CodeContextMenu::CodeActions(_)) => {
 2168                key_context.add("menu");
 2169                key_context.add("showing_code_actions")
 2170            }
 2171            None => {}
 2172        }
 2173
 2174        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2175        if !self.focus_handle(cx).contains_focused(window, cx)
 2176            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2177        {
 2178            for addon in self.addons.values() {
 2179                addon.extend_key_context(&mut key_context, cx)
 2180            }
 2181        }
 2182
 2183        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2184            if let Some(extension) = singleton_buffer
 2185                .read(cx)
 2186                .file()
 2187                .and_then(|file| file.path().extension()?.to_str())
 2188            {
 2189                key_context.set("extension", extension.to_string());
 2190            }
 2191        } else {
 2192            key_context.add("multibuffer");
 2193        }
 2194
 2195        if has_active_edit_prediction {
 2196            if self.edit_prediction_in_conflict() {
 2197                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2198            } else {
 2199                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2200                key_context.add("copilot_suggestion");
 2201            }
 2202        }
 2203
 2204        if self.selection_mark_mode {
 2205            key_context.add("selection_mode");
 2206        }
 2207
 2208        key_context
 2209    }
 2210
 2211    fn show_mouse_cursor(&mut self) {
 2212        self.mouse_cursor_hidden = false;
 2213    }
 2214
 2215    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2216        self.mouse_cursor_hidden = match origin {
 2217            HideMouseCursorOrigin::TypingAction => {
 2218                matches!(
 2219                    self.hide_mouse_mode,
 2220                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2221                )
 2222            }
 2223            HideMouseCursorOrigin::MovementAction => {
 2224                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2225            }
 2226        };
 2227    }
 2228
 2229    pub fn edit_prediction_in_conflict(&self) -> bool {
 2230        if !self.show_edit_predictions_in_menu() {
 2231            return false;
 2232        }
 2233
 2234        let showing_completions = self
 2235            .context_menu
 2236            .borrow()
 2237            .as_ref()
 2238            .map_or(false, |context| {
 2239                matches!(context, CodeContextMenu::Completions(_))
 2240            });
 2241
 2242        showing_completions
 2243            || self.edit_prediction_requires_modifier()
 2244            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2245            // bindings to insert tab characters.
 2246            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2247    }
 2248
 2249    pub fn accept_edit_prediction_keybind(
 2250        &self,
 2251        accept_partial: bool,
 2252        window: &Window,
 2253        cx: &App,
 2254    ) -> AcceptEditPredictionBinding {
 2255        let key_context = self.key_context_internal(true, window, cx);
 2256        let in_conflict = self.edit_prediction_in_conflict();
 2257
 2258        let bindings = if accept_partial {
 2259            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2260        } else {
 2261            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2262        };
 2263
 2264        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2265        // just the first one.
 2266        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2267            !in_conflict
 2268                || binding
 2269                    .keystrokes()
 2270                    .first()
 2271                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2272        }))
 2273    }
 2274
 2275    pub fn new_file(
 2276        workspace: &mut Workspace,
 2277        _: &workspace::NewFile,
 2278        window: &mut Window,
 2279        cx: &mut Context<Workspace>,
 2280    ) {
 2281        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2282            "Failed to create buffer",
 2283            window,
 2284            cx,
 2285            |e, _, _| match e.error_code() {
 2286                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2287                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2288                e.error_tag("required").unwrap_or("the latest version")
 2289            )),
 2290                _ => None,
 2291            },
 2292        );
 2293    }
 2294
 2295    pub fn new_in_workspace(
 2296        workspace: &mut Workspace,
 2297        window: &mut Window,
 2298        cx: &mut Context<Workspace>,
 2299    ) -> Task<Result<Entity<Editor>>> {
 2300        let project = workspace.project().clone();
 2301        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2302
 2303        cx.spawn_in(window, async move |workspace, cx| {
 2304            let buffer = create.await?;
 2305            workspace.update_in(cx, |workspace, window, cx| {
 2306                let editor =
 2307                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2308                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2309                editor
 2310            })
 2311        })
 2312    }
 2313
 2314    fn new_file_vertical(
 2315        workspace: &mut Workspace,
 2316        _: &workspace::NewFileSplitVertical,
 2317        window: &mut Window,
 2318        cx: &mut Context<Workspace>,
 2319    ) {
 2320        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2321    }
 2322
 2323    fn new_file_horizontal(
 2324        workspace: &mut Workspace,
 2325        _: &workspace::NewFileSplitHorizontal,
 2326        window: &mut Window,
 2327        cx: &mut Context<Workspace>,
 2328    ) {
 2329        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2330    }
 2331
 2332    fn new_file_in_direction(
 2333        workspace: &mut Workspace,
 2334        direction: SplitDirection,
 2335        window: &mut Window,
 2336        cx: &mut Context<Workspace>,
 2337    ) {
 2338        let project = workspace.project().clone();
 2339        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2340
 2341        cx.spawn_in(window, async move |workspace, cx| {
 2342            let buffer = create.await?;
 2343            workspace.update_in(cx, move |workspace, window, cx| {
 2344                workspace.split_item(
 2345                    direction,
 2346                    Box::new(
 2347                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2348                    ),
 2349                    window,
 2350                    cx,
 2351                )
 2352            })?;
 2353            anyhow::Ok(())
 2354        })
 2355        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2356            match e.error_code() {
 2357                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2358                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2359                e.error_tag("required").unwrap_or("the latest version")
 2360            )),
 2361                _ => None,
 2362            }
 2363        });
 2364    }
 2365
 2366    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2367        self.leader_id
 2368    }
 2369
 2370    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2371        &self.buffer
 2372    }
 2373
 2374    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2375        self.workspace.as_ref()?.0.upgrade()
 2376    }
 2377
 2378    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2379        self.buffer().read(cx).title(cx)
 2380    }
 2381
 2382    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2383        let git_blame_gutter_max_author_length = self
 2384            .render_git_blame_gutter(cx)
 2385            .then(|| {
 2386                if let Some(blame) = self.blame.as_ref() {
 2387                    let max_author_length =
 2388                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2389                    Some(max_author_length)
 2390                } else {
 2391                    None
 2392                }
 2393            })
 2394            .flatten();
 2395
 2396        EditorSnapshot {
 2397            mode: self.mode.clone(),
 2398            show_gutter: self.show_gutter,
 2399            show_line_numbers: self.show_line_numbers,
 2400            show_git_diff_gutter: self.show_git_diff_gutter,
 2401            show_code_actions: self.show_code_actions,
 2402            show_runnables: self.show_runnables,
 2403            show_breakpoints: self.show_breakpoints,
 2404            git_blame_gutter_max_author_length,
 2405            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2406            scroll_anchor: self.scroll_manager.anchor(),
 2407            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2408            placeholder_text: self.placeholder_text.clone(),
 2409            is_focused: self.focus_handle.is_focused(window),
 2410            current_line_highlight: self
 2411                .current_line_highlight
 2412                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2413            gutter_hovered: self.gutter_hovered,
 2414        }
 2415    }
 2416
 2417    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2418        self.buffer.read(cx).language_at(point, cx)
 2419    }
 2420
 2421    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2422        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2423    }
 2424
 2425    pub fn active_excerpt(
 2426        &self,
 2427        cx: &App,
 2428    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2429        self.buffer
 2430            .read(cx)
 2431            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2432    }
 2433
 2434    pub fn mode(&self) -> &EditorMode {
 2435        &self.mode
 2436    }
 2437
 2438    pub fn set_mode(&mut self, mode: EditorMode) {
 2439        self.mode = mode;
 2440    }
 2441
 2442    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2443        self.collaboration_hub.as_deref()
 2444    }
 2445
 2446    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2447        self.collaboration_hub = Some(hub);
 2448    }
 2449
 2450    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2451        self.in_project_search = in_project_search;
 2452    }
 2453
 2454    pub fn set_custom_context_menu(
 2455        &mut self,
 2456        f: impl 'static
 2457        + Fn(
 2458            &mut Self,
 2459            DisplayPoint,
 2460            &mut Window,
 2461            &mut Context<Self>,
 2462        ) -> Option<Entity<ui::ContextMenu>>,
 2463    ) {
 2464        self.custom_context_menu = Some(Box::new(f))
 2465    }
 2466
 2467    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2468        self.completion_provider = provider;
 2469    }
 2470
 2471    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2472        self.semantics_provider.clone()
 2473    }
 2474
 2475    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2476        self.semantics_provider = provider;
 2477    }
 2478
 2479    pub fn set_edit_prediction_provider<T>(
 2480        &mut self,
 2481        provider: Option<Entity<T>>,
 2482        window: &mut Window,
 2483        cx: &mut Context<Self>,
 2484    ) where
 2485        T: EditPredictionProvider,
 2486    {
 2487        self.edit_prediction_provider =
 2488            provider.map(|provider| RegisteredInlineCompletionProvider {
 2489                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2490                    if this.focus_handle.is_focused(window) {
 2491                        this.update_visible_inline_completion(window, cx);
 2492                    }
 2493                }),
 2494                provider: Arc::new(provider),
 2495            });
 2496        self.update_edit_prediction_settings(cx);
 2497        self.refresh_inline_completion(false, false, window, cx);
 2498    }
 2499
 2500    pub fn placeholder_text(&self) -> Option<&str> {
 2501        self.placeholder_text.as_deref()
 2502    }
 2503
 2504    pub fn set_placeholder_text(
 2505        &mut self,
 2506        placeholder_text: impl Into<Arc<str>>,
 2507        cx: &mut Context<Self>,
 2508    ) {
 2509        let placeholder_text = Some(placeholder_text.into());
 2510        if self.placeholder_text != placeholder_text {
 2511            self.placeholder_text = placeholder_text;
 2512            cx.notify();
 2513        }
 2514    }
 2515
 2516    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2517        self.cursor_shape = cursor_shape;
 2518
 2519        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2520        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2521
 2522        cx.notify();
 2523    }
 2524
 2525    pub fn set_current_line_highlight(
 2526        &mut self,
 2527        current_line_highlight: Option<CurrentLineHighlight>,
 2528    ) {
 2529        self.current_line_highlight = current_line_highlight;
 2530    }
 2531
 2532    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2533        self.collapse_matches = collapse_matches;
 2534    }
 2535
 2536    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2537        let buffers = self.buffer.read(cx).all_buffers();
 2538        let Some(project) = self.project.as_ref() else {
 2539            return;
 2540        };
 2541        project.update(cx, |project, cx| {
 2542            for buffer in buffers {
 2543                self.registered_buffers
 2544                    .entry(buffer.read(cx).remote_id())
 2545                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2546            }
 2547        })
 2548    }
 2549
 2550    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2551        if self.collapse_matches {
 2552            return range.start..range.start;
 2553        }
 2554        range.clone()
 2555    }
 2556
 2557    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2558        if self.display_map.read(cx).clip_at_line_ends != clip {
 2559            self.display_map
 2560                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2561        }
 2562    }
 2563
 2564    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2565        self.input_enabled = input_enabled;
 2566    }
 2567
 2568    pub fn set_inline_completions_hidden_for_vim_mode(
 2569        &mut self,
 2570        hidden: bool,
 2571        window: &mut Window,
 2572        cx: &mut Context<Self>,
 2573    ) {
 2574        if hidden != self.inline_completions_hidden_for_vim_mode {
 2575            self.inline_completions_hidden_for_vim_mode = hidden;
 2576            if hidden {
 2577                self.update_visible_inline_completion(window, cx);
 2578            } else {
 2579                self.refresh_inline_completion(true, false, window, cx);
 2580            }
 2581        }
 2582    }
 2583
 2584    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2585        self.menu_inline_completions_policy = value;
 2586    }
 2587
 2588    pub fn set_autoindent(&mut self, autoindent: bool) {
 2589        if autoindent {
 2590            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2591        } else {
 2592            self.autoindent_mode = None;
 2593        }
 2594    }
 2595
 2596    pub fn read_only(&self, cx: &App) -> bool {
 2597        self.read_only || self.buffer.read(cx).read_only()
 2598    }
 2599
 2600    pub fn set_read_only(&mut self, read_only: bool) {
 2601        self.read_only = read_only;
 2602    }
 2603
 2604    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2605        self.use_autoclose = autoclose;
 2606    }
 2607
 2608    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2609        self.use_auto_surround = auto_surround;
 2610    }
 2611
 2612    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2613        self.auto_replace_emoji_shortcode = auto_replace;
 2614    }
 2615
 2616    pub fn toggle_edit_predictions(
 2617        &mut self,
 2618        _: &ToggleEditPrediction,
 2619        window: &mut Window,
 2620        cx: &mut Context<Self>,
 2621    ) {
 2622        if self.show_inline_completions_override.is_some() {
 2623            self.set_show_edit_predictions(None, window, cx);
 2624        } else {
 2625            let show_edit_predictions = !self.edit_predictions_enabled();
 2626            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2627        }
 2628    }
 2629
 2630    pub fn set_show_edit_predictions(
 2631        &mut self,
 2632        show_edit_predictions: Option<bool>,
 2633        window: &mut Window,
 2634        cx: &mut Context<Self>,
 2635    ) {
 2636        self.show_inline_completions_override = show_edit_predictions;
 2637        self.update_edit_prediction_settings(cx);
 2638
 2639        if let Some(false) = show_edit_predictions {
 2640            self.discard_inline_completion(false, cx);
 2641        } else {
 2642            self.refresh_inline_completion(false, true, window, cx);
 2643        }
 2644    }
 2645
 2646    fn inline_completions_disabled_in_scope(
 2647        &self,
 2648        buffer: &Entity<Buffer>,
 2649        buffer_position: language::Anchor,
 2650        cx: &App,
 2651    ) -> bool {
 2652        let snapshot = buffer.read(cx).snapshot();
 2653        let settings = snapshot.settings_at(buffer_position, cx);
 2654
 2655        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2656            return false;
 2657        };
 2658
 2659        scope.override_name().map_or(false, |scope_name| {
 2660            settings
 2661                .edit_predictions_disabled_in
 2662                .iter()
 2663                .any(|s| s == scope_name)
 2664        })
 2665    }
 2666
 2667    pub fn set_use_modal_editing(&mut self, to: bool) {
 2668        self.use_modal_editing = to;
 2669    }
 2670
 2671    pub fn use_modal_editing(&self) -> bool {
 2672        self.use_modal_editing
 2673    }
 2674
 2675    fn selections_did_change(
 2676        &mut self,
 2677        local: bool,
 2678        old_cursor_position: &Anchor,
 2679        should_update_completions: bool,
 2680        window: &mut Window,
 2681        cx: &mut Context<Self>,
 2682    ) {
 2683        window.invalidate_character_coordinates();
 2684
 2685        // Copy selections to primary selection buffer
 2686        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2687        if local {
 2688            let selections = self.selections.all::<usize>(cx);
 2689            let buffer_handle = self.buffer.read(cx).read(cx);
 2690
 2691            let mut text = String::new();
 2692            for (index, selection) in selections.iter().enumerate() {
 2693                let text_for_selection = buffer_handle
 2694                    .text_for_range(selection.start..selection.end)
 2695                    .collect::<String>();
 2696
 2697                text.push_str(&text_for_selection);
 2698                if index != selections.len() - 1 {
 2699                    text.push('\n');
 2700                }
 2701            }
 2702
 2703            if !text.is_empty() {
 2704                cx.write_to_primary(ClipboardItem::new_string(text));
 2705            }
 2706        }
 2707
 2708        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2709            self.buffer.update(cx, |buffer, cx| {
 2710                buffer.set_active_selections(
 2711                    &self.selections.disjoint_anchors(),
 2712                    self.selections.line_mode,
 2713                    self.cursor_shape,
 2714                    cx,
 2715                )
 2716            });
 2717        }
 2718        let display_map = self
 2719            .display_map
 2720            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2721        let buffer = &display_map.buffer_snapshot;
 2722        if self.selections.count() == 1 {
 2723            self.add_selections_state = None;
 2724        }
 2725        self.select_next_state = None;
 2726        self.select_prev_state = None;
 2727        self.select_syntax_node_history.try_clear();
 2728        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2729        self.snippet_stack
 2730            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2731        self.take_rename(false, window, cx);
 2732
 2733        let newest_selection = self.selections.newest_anchor();
 2734        let new_cursor_position = newest_selection.head();
 2735        let selection_start = newest_selection.start;
 2736
 2737        self.push_to_nav_history(
 2738            *old_cursor_position,
 2739            Some(new_cursor_position.to_point(buffer)),
 2740            false,
 2741            cx,
 2742        );
 2743
 2744        if local {
 2745            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2746                if !self.registered_buffers.contains_key(&buffer_id) {
 2747                    if let Some(project) = self.project.as_ref() {
 2748                        project.update(cx, |project, cx| {
 2749                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2750                                return;
 2751                            };
 2752                            self.registered_buffers.insert(
 2753                                buffer_id,
 2754                                project.register_buffer_with_language_servers(&buffer, cx),
 2755                            );
 2756                        })
 2757                    }
 2758                }
 2759            }
 2760
 2761            let mut context_menu = self.context_menu.borrow_mut();
 2762            let completion_menu = match context_menu.as_ref() {
 2763                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2764                Some(CodeContextMenu::CodeActions(_)) => {
 2765                    *context_menu = None;
 2766                    None
 2767                }
 2768                None => None,
 2769            };
 2770            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2771            drop(context_menu);
 2772
 2773            if should_update_completions {
 2774                if let Some(completion_position) = completion_position {
 2775                    let start_offset = selection_start.to_offset(buffer);
 2776                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2777                    let continue_showing = if position_matches {
 2778                        if self.snippet_stack.is_empty() {
 2779                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2780                        } else {
 2781                            // Snippet choices can be shown even when the cursor is in whitespace.
 2782                            // Dismissing the menu when actions like backspace
 2783                            true
 2784                        }
 2785                    } else {
 2786                        false
 2787                    };
 2788
 2789                    if continue_showing {
 2790                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2791                    } else {
 2792                        self.hide_context_menu(window, cx);
 2793                    }
 2794                }
 2795            }
 2796
 2797            hide_hover(self, cx);
 2798
 2799            if old_cursor_position.to_display_point(&display_map).row()
 2800                != new_cursor_position.to_display_point(&display_map).row()
 2801            {
 2802                self.available_code_actions.take();
 2803            }
 2804            self.refresh_code_actions(window, cx);
 2805            self.refresh_document_highlights(cx);
 2806            self.refresh_selected_text_highlights(false, window, cx);
 2807            refresh_matching_bracket_highlights(self, window, cx);
 2808            self.update_visible_inline_completion(window, cx);
 2809            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2810            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2811            self.inline_blame_popover.take();
 2812            if self.git_blame_inline_enabled {
 2813                self.start_inline_blame_timer(window, cx);
 2814            }
 2815        }
 2816
 2817        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2818        cx.emit(EditorEvent::SelectionsChanged { local });
 2819
 2820        let selections = &self.selections.disjoint;
 2821        if selections.len() == 1 {
 2822            cx.emit(SearchEvent::ActiveMatchChanged)
 2823        }
 2824        if local {
 2825            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2826                let inmemory_selections = selections
 2827                    .iter()
 2828                    .map(|s| {
 2829                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2830                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2831                    })
 2832                    .collect();
 2833                self.update_restoration_data(cx, |data| {
 2834                    data.selections = inmemory_selections;
 2835                });
 2836
 2837                if WorkspaceSettings::get(None, cx).restore_on_startup
 2838                    != RestoreOnStartupBehavior::None
 2839                {
 2840                    if let Some(workspace_id) =
 2841                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2842                    {
 2843                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2844                        let selections = selections.clone();
 2845                        let background_executor = cx.background_executor().clone();
 2846                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2847                        self.serialize_selections = cx.background_spawn(async move {
 2848                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2849                    let db_selections = selections
 2850                        .iter()
 2851                        .map(|selection| {
 2852                            (
 2853                                selection.start.to_offset(&snapshot),
 2854                                selection.end.to_offset(&snapshot),
 2855                            )
 2856                        })
 2857                        .collect();
 2858
 2859                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2860                        .await
 2861                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2862                        .log_err();
 2863                });
 2864                    }
 2865                }
 2866            }
 2867        }
 2868
 2869        cx.notify();
 2870    }
 2871
 2872    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2873        use text::ToOffset as _;
 2874        use text::ToPoint as _;
 2875
 2876        if self.mode.is_minimap()
 2877            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2878        {
 2879            return;
 2880        }
 2881
 2882        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2883            return;
 2884        };
 2885
 2886        let snapshot = singleton.read(cx).snapshot();
 2887        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2888            let display_snapshot = display_map.snapshot(cx);
 2889
 2890            display_snapshot
 2891                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2892                .map(|fold| {
 2893                    fold.range.start.text_anchor.to_point(&snapshot)
 2894                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2895                })
 2896                .collect()
 2897        });
 2898        self.update_restoration_data(cx, |data| {
 2899            data.folds = inmemory_folds;
 2900        });
 2901
 2902        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2903            return;
 2904        };
 2905        let background_executor = cx.background_executor().clone();
 2906        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2907        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2908            display_map
 2909                .snapshot(cx)
 2910                .folds_in_range(0..snapshot.len())
 2911                .map(|fold| {
 2912                    (
 2913                        fold.range.start.text_anchor.to_offset(&snapshot),
 2914                        fold.range.end.text_anchor.to_offset(&snapshot),
 2915                    )
 2916                })
 2917                .collect()
 2918        });
 2919        self.serialize_folds = cx.background_spawn(async move {
 2920            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2921            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2922                .await
 2923                .with_context(|| {
 2924                    format!(
 2925                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2926                    )
 2927                })
 2928                .log_err();
 2929        });
 2930    }
 2931
 2932    pub fn sync_selections(
 2933        &mut self,
 2934        other: Entity<Editor>,
 2935        cx: &mut Context<Self>,
 2936    ) -> gpui::Subscription {
 2937        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2938        self.selections.change_with(cx, |selections| {
 2939            selections.select_anchors(other_selections);
 2940        });
 2941
 2942        let other_subscription =
 2943            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2944                EditorEvent::SelectionsChanged { local: true } => {
 2945                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2946                    if other_selections.is_empty() {
 2947                        return;
 2948                    }
 2949                    this.selections.change_with(cx, |selections| {
 2950                        selections.select_anchors(other_selections);
 2951                    });
 2952                }
 2953                _ => {}
 2954            });
 2955
 2956        let this_subscription =
 2957            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2958                EditorEvent::SelectionsChanged { local: true } => {
 2959                    let these_selections = this.selections.disjoint.to_vec();
 2960                    if these_selections.is_empty() {
 2961                        return;
 2962                    }
 2963                    other.update(cx, |other_editor, cx| {
 2964                        other_editor.selections.change_with(cx, |selections| {
 2965                            selections.select_anchors(these_selections);
 2966                        })
 2967                    });
 2968                }
 2969                _ => {}
 2970            });
 2971
 2972        Subscription::join(other_subscription, this_subscription)
 2973    }
 2974
 2975    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2976    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2977    /// effects of selection change occur at the end of the transaction.
 2978    pub fn change_selections<R>(
 2979        &mut self,
 2980        autoscroll: Option<Autoscroll>,
 2981        window: &mut Window,
 2982        cx: &mut Context<Self>,
 2983        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2984    ) -> R {
 2985        self.change_selections_inner(true, autoscroll, window, cx, change)
 2986    }
 2987
 2988    pub(crate) fn change_selections_without_updating_completions<R>(
 2989        &mut self,
 2990        autoscroll: Option<Autoscroll>,
 2991        window: &mut Window,
 2992        cx: &mut Context<Self>,
 2993        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2994    ) -> R {
 2995        self.change_selections_inner(false, autoscroll, window, cx, change)
 2996    }
 2997
 2998    fn change_selections_inner<R>(
 2999        &mut self,
 3000        should_update_completions: bool,
 3001        autoscroll: Option<Autoscroll>,
 3002        window: &mut Window,
 3003        cx: &mut Context<Self>,
 3004        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3005    ) -> R {
 3006        if let Some(state) = &mut self.deferred_selection_effects_state {
 3007            state.autoscroll = autoscroll.or(state.autoscroll);
 3008            state.should_update_completions = should_update_completions;
 3009            let (changed, result) = self.selections.change_with(cx, change);
 3010            state.changed |= changed;
 3011            return result;
 3012        }
 3013        let mut state = DeferredSelectionEffectsState {
 3014            changed: false,
 3015            should_update_completions,
 3016            autoscroll,
 3017            old_cursor_position: self.selections.newest_anchor().head(),
 3018            history_entry: SelectionHistoryEntry {
 3019                selections: self.selections.disjoint_anchors(),
 3020                select_next_state: self.select_next_state.clone(),
 3021                select_prev_state: self.select_prev_state.clone(),
 3022                add_selections_state: self.add_selections_state.clone(),
 3023            },
 3024        };
 3025        let (changed, result) = self.selections.change_with(cx, change);
 3026        state.changed = state.changed || changed;
 3027        if self.defer_selection_effects {
 3028            self.deferred_selection_effects_state = Some(state);
 3029        } else {
 3030            self.apply_selection_effects(state, window, cx);
 3031        }
 3032        result
 3033    }
 3034
 3035    /// Defers the effects of selection change, so that the effects of multiple calls to
 3036    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3037    /// to selection history and the state of popovers based on selection position aren't
 3038    /// erroneously updated.
 3039    pub fn with_selection_effects_deferred<R>(
 3040        &mut self,
 3041        window: &mut Window,
 3042        cx: &mut Context<Self>,
 3043        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3044    ) -> R {
 3045        let already_deferred = self.defer_selection_effects;
 3046        self.defer_selection_effects = true;
 3047        let result = update(self, window, cx);
 3048        if !already_deferred {
 3049            self.defer_selection_effects = false;
 3050            if let Some(state) = self.deferred_selection_effects_state.take() {
 3051                self.apply_selection_effects(state, window, cx);
 3052            }
 3053        }
 3054        result
 3055    }
 3056
 3057    fn apply_selection_effects(
 3058        &mut self,
 3059        state: DeferredSelectionEffectsState,
 3060        window: &mut Window,
 3061        cx: &mut Context<Self>,
 3062    ) {
 3063        if state.changed {
 3064            self.selection_history.push(state.history_entry);
 3065
 3066            if let Some(autoscroll) = state.autoscroll {
 3067                self.request_autoscroll(autoscroll, cx);
 3068            }
 3069
 3070            let old_cursor_position = &state.old_cursor_position;
 3071
 3072            self.selections_did_change(
 3073                true,
 3074                &old_cursor_position,
 3075                state.should_update_completions,
 3076                window,
 3077                cx,
 3078            );
 3079
 3080            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3081                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3082            }
 3083        }
 3084    }
 3085
 3086    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3087    where
 3088        I: IntoIterator<Item = (Range<S>, T)>,
 3089        S: ToOffset,
 3090        T: Into<Arc<str>>,
 3091    {
 3092        if self.read_only(cx) {
 3093            return;
 3094        }
 3095
 3096        self.buffer
 3097            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3098    }
 3099
 3100    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3101    where
 3102        I: IntoIterator<Item = (Range<S>, T)>,
 3103        S: ToOffset,
 3104        T: Into<Arc<str>>,
 3105    {
 3106        if self.read_only(cx) {
 3107            return;
 3108        }
 3109
 3110        self.buffer.update(cx, |buffer, cx| {
 3111            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3112        });
 3113    }
 3114
 3115    pub fn edit_with_block_indent<I, S, T>(
 3116        &mut self,
 3117        edits: I,
 3118        original_indent_columns: Vec<Option<u32>>,
 3119        cx: &mut Context<Self>,
 3120    ) where
 3121        I: IntoIterator<Item = (Range<S>, T)>,
 3122        S: ToOffset,
 3123        T: Into<Arc<str>>,
 3124    {
 3125        if self.read_only(cx) {
 3126            return;
 3127        }
 3128
 3129        self.buffer.update(cx, |buffer, cx| {
 3130            buffer.edit(
 3131                edits,
 3132                Some(AutoindentMode::Block {
 3133                    original_indent_columns,
 3134                }),
 3135                cx,
 3136            )
 3137        });
 3138    }
 3139
 3140    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3141        self.hide_context_menu(window, cx);
 3142
 3143        match phase {
 3144            SelectPhase::Begin {
 3145                position,
 3146                add,
 3147                click_count,
 3148            } => self.begin_selection(position, add, click_count, window, cx),
 3149            SelectPhase::BeginColumnar {
 3150                position,
 3151                goal_column,
 3152                reset,
 3153            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3154            SelectPhase::Extend {
 3155                position,
 3156                click_count,
 3157            } => self.extend_selection(position, click_count, window, cx),
 3158            SelectPhase::Update {
 3159                position,
 3160                goal_column,
 3161                scroll_delta,
 3162            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3163            SelectPhase::End => self.end_selection(window, cx),
 3164        }
 3165    }
 3166
 3167    fn extend_selection(
 3168        &mut self,
 3169        position: DisplayPoint,
 3170        click_count: usize,
 3171        window: &mut Window,
 3172        cx: &mut Context<Self>,
 3173    ) {
 3174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3175        let tail = self.selections.newest::<usize>(cx).tail();
 3176        self.begin_selection(position, false, click_count, window, cx);
 3177
 3178        let position = position.to_offset(&display_map, Bias::Left);
 3179        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3180
 3181        let mut pending_selection = self
 3182            .selections
 3183            .pending_anchor()
 3184            .expect("extend_selection not called with pending selection");
 3185        if position >= tail {
 3186            pending_selection.start = tail_anchor;
 3187        } else {
 3188            pending_selection.end = tail_anchor;
 3189            pending_selection.reversed = true;
 3190        }
 3191
 3192        let mut pending_mode = self.selections.pending_mode().unwrap();
 3193        match &mut pending_mode {
 3194            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3195            _ => {}
 3196        }
 3197
 3198        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3199
 3200        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3201            s.set_pending(pending_selection, pending_mode)
 3202        });
 3203    }
 3204
 3205    fn begin_selection(
 3206        &mut self,
 3207        position: DisplayPoint,
 3208        add: bool,
 3209        click_count: usize,
 3210        window: &mut Window,
 3211        cx: &mut Context<Self>,
 3212    ) {
 3213        if !self.focus_handle.is_focused(window) {
 3214            self.last_focused_descendant = None;
 3215            window.focus(&self.focus_handle);
 3216        }
 3217
 3218        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3219        let buffer = &display_map.buffer_snapshot;
 3220        let position = display_map.clip_point(position, Bias::Left);
 3221
 3222        let start;
 3223        let end;
 3224        let mode;
 3225        let mut auto_scroll;
 3226        match click_count {
 3227            1 => {
 3228                start = buffer.anchor_before(position.to_point(&display_map));
 3229                end = start;
 3230                mode = SelectMode::Character;
 3231                auto_scroll = true;
 3232            }
 3233            2 => {
 3234                let range = movement::surrounding_word(&display_map, position);
 3235                start = buffer.anchor_before(range.start.to_point(&display_map));
 3236                end = buffer.anchor_before(range.end.to_point(&display_map));
 3237                mode = SelectMode::Word(start..end);
 3238                auto_scroll = true;
 3239            }
 3240            3 => {
 3241                let position = display_map
 3242                    .clip_point(position, Bias::Left)
 3243                    .to_point(&display_map);
 3244                let line_start = display_map.prev_line_boundary(position).0;
 3245                let next_line_start = buffer.clip_point(
 3246                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3247                    Bias::Left,
 3248                );
 3249                start = buffer.anchor_before(line_start);
 3250                end = buffer.anchor_before(next_line_start);
 3251                mode = SelectMode::Line(start..end);
 3252                auto_scroll = true;
 3253            }
 3254            _ => {
 3255                start = buffer.anchor_before(0);
 3256                end = buffer.anchor_before(buffer.len());
 3257                mode = SelectMode::All;
 3258                auto_scroll = false;
 3259            }
 3260        }
 3261        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3262
 3263        let point_to_delete: Option<usize> = {
 3264            let selected_points: Vec<Selection<Point>> =
 3265                self.selections.disjoint_in_range(start..end, cx);
 3266
 3267            if !add || click_count > 1 {
 3268                None
 3269            } else if !selected_points.is_empty() {
 3270                Some(selected_points[0].id)
 3271            } else {
 3272                let clicked_point_already_selected =
 3273                    self.selections.disjoint.iter().find(|selection| {
 3274                        selection.start.to_point(buffer) == start.to_point(buffer)
 3275                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3276                    });
 3277
 3278                clicked_point_already_selected.map(|selection| selection.id)
 3279            }
 3280        };
 3281
 3282        let selections_count = self.selections.count();
 3283
 3284        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3285            if let Some(point_to_delete) = point_to_delete {
 3286                s.delete(point_to_delete);
 3287
 3288                if selections_count == 1 {
 3289                    s.set_pending_anchor_range(start..end, mode);
 3290                }
 3291            } else {
 3292                if !add {
 3293                    s.clear_disjoint();
 3294                }
 3295
 3296                s.set_pending_anchor_range(start..end, mode);
 3297            }
 3298        });
 3299    }
 3300
 3301    fn begin_columnar_selection(
 3302        &mut self,
 3303        position: DisplayPoint,
 3304        goal_column: u32,
 3305        reset: bool,
 3306        window: &mut Window,
 3307        cx: &mut Context<Self>,
 3308    ) {
 3309        if !self.focus_handle.is_focused(window) {
 3310            self.last_focused_descendant = None;
 3311            window.focus(&self.focus_handle);
 3312        }
 3313
 3314        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3315
 3316        if reset {
 3317            let pointer_position = display_map
 3318                .buffer_snapshot
 3319                .anchor_before(position.to_point(&display_map));
 3320
 3321            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3322                s.clear_disjoint();
 3323                s.set_pending_anchor_range(
 3324                    pointer_position..pointer_position,
 3325                    SelectMode::Character,
 3326                );
 3327            });
 3328            if position.column() != goal_column {
 3329                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3330            } else {
 3331                self.columnar_display_point = None;
 3332            }
 3333        }
 3334
 3335        let tail = self.selections.newest::<Point>(cx).tail();
 3336        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3337
 3338        if !reset {
 3339            self.columnar_display_point = None;
 3340            self.select_columns(
 3341                tail.to_display_point(&display_map),
 3342                position,
 3343                goal_column,
 3344                &display_map,
 3345                window,
 3346                cx,
 3347            );
 3348        }
 3349    }
 3350
 3351    fn update_selection(
 3352        &mut self,
 3353        position: DisplayPoint,
 3354        goal_column: u32,
 3355        scroll_delta: gpui::Point<f32>,
 3356        window: &mut Window,
 3357        cx: &mut Context<Self>,
 3358    ) {
 3359        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3360
 3361        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3362            let tail = self
 3363                .columnar_display_point
 3364                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3365            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3366        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3367            let buffer = self.buffer.read(cx).snapshot(cx);
 3368            let head;
 3369            let tail;
 3370            let mode = self.selections.pending_mode().unwrap();
 3371            match &mode {
 3372                SelectMode::Character => {
 3373                    head = position.to_point(&display_map);
 3374                    tail = pending.tail().to_point(&buffer);
 3375                }
 3376                SelectMode::Word(original_range) => {
 3377                    let original_display_range = original_range.start.to_display_point(&display_map)
 3378                        ..original_range.end.to_display_point(&display_map);
 3379                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3380                        ..original_display_range.end.to_point(&display_map);
 3381                    if movement::is_inside_word(&display_map, position)
 3382                        || original_display_range.contains(&position)
 3383                    {
 3384                        let word_range = movement::surrounding_word(&display_map, position);
 3385                        if word_range.start < original_display_range.start {
 3386                            head = word_range.start.to_point(&display_map);
 3387                        } else {
 3388                            head = word_range.end.to_point(&display_map);
 3389                        }
 3390                    } else {
 3391                        head = position.to_point(&display_map);
 3392                    }
 3393
 3394                    if head <= original_buffer_range.start {
 3395                        tail = original_buffer_range.end;
 3396                    } else {
 3397                        tail = original_buffer_range.start;
 3398                    }
 3399                }
 3400                SelectMode::Line(original_range) => {
 3401                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3402
 3403                    let position = display_map
 3404                        .clip_point(position, Bias::Left)
 3405                        .to_point(&display_map);
 3406                    let line_start = display_map.prev_line_boundary(position).0;
 3407                    let next_line_start = buffer.clip_point(
 3408                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3409                        Bias::Left,
 3410                    );
 3411
 3412                    if line_start < original_range.start {
 3413                        head = line_start
 3414                    } else {
 3415                        head = next_line_start
 3416                    }
 3417
 3418                    if head <= original_range.start {
 3419                        tail = original_range.end;
 3420                    } else {
 3421                        tail = original_range.start;
 3422                    }
 3423                }
 3424                SelectMode::All => {
 3425                    return;
 3426                }
 3427            };
 3428
 3429            if head < tail {
 3430                pending.start = buffer.anchor_before(head);
 3431                pending.end = buffer.anchor_before(tail);
 3432                pending.reversed = true;
 3433            } else {
 3434                pending.start = buffer.anchor_before(tail);
 3435                pending.end = buffer.anchor_before(head);
 3436                pending.reversed = false;
 3437            }
 3438
 3439            self.change_selections(None, window, cx, |s| {
 3440                s.set_pending(pending, mode);
 3441            });
 3442        } else {
 3443            log::error!("update_selection dispatched with no pending selection");
 3444            return;
 3445        }
 3446
 3447        self.apply_scroll_delta(scroll_delta, window, cx);
 3448        cx.notify();
 3449    }
 3450
 3451    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3452        self.columnar_selection_tail.take();
 3453        if self.selections.pending_anchor().is_some() {
 3454            let selections = self.selections.all::<usize>(cx);
 3455            self.change_selections(None, window, cx, |s| {
 3456                s.select(selections);
 3457                s.clear_pending();
 3458            });
 3459        }
 3460    }
 3461
 3462    fn select_columns(
 3463        &mut self,
 3464        tail: DisplayPoint,
 3465        head: DisplayPoint,
 3466        goal_column: u32,
 3467        display_map: &DisplaySnapshot,
 3468        window: &mut Window,
 3469        cx: &mut Context<Self>,
 3470    ) {
 3471        let start_row = cmp::min(tail.row(), head.row());
 3472        let end_row = cmp::max(tail.row(), head.row());
 3473        let start_column = cmp::min(tail.column(), goal_column);
 3474        let end_column = cmp::max(tail.column(), goal_column);
 3475        let reversed = start_column < tail.column();
 3476
 3477        let selection_ranges = (start_row.0..=end_row.0)
 3478            .map(DisplayRow)
 3479            .filter_map(|row| {
 3480                if !display_map.is_block_line(row) {
 3481                    let start = display_map
 3482                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3483                        .to_point(display_map);
 3484                    let end = display_map
 3485                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3486                        .to_point(display_map);
 3487                    if reversed {
 3488                        Some(end..start)
 3489                    } else {
 3490                        Some(start..end)
 3491                    }
 3492                } else {
 3493                    None
 3494                }
 3495            })
 3496            .collect::<Vec<_>>();
 3497
 3498        let mut non_empty_ranges = selection_ranges
 3499            .iter()
 3500            .filter(|selection_range| selection_range.start != selection_range.end)
 3501            .peekable();
 3502
 3503        let ranges = if non_empty_ranges.peek().is_some() {
 3504            non_empty_ranges.cloned().collect()
 3505        } else {
 3506            selection_ranges
 3507        };
 3508
 3509        self.change_selections(None, window, cx, |s| {
 3510            s.select_ranges(ranges);
 3511        });
 3512        cx.notify();
 3513    }
 3514
 3515    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3516        self.selections
 3517            .all_adjusted(cx)
 3518            .iter()
 3519            .any(|selection| !selection.is_empty())
 3520    }
 3521
 3522    pub fn has_pending_nonempty_selection(&self) -> bool {
 3523        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3524            Some(Selection { start, end, .. }) => start != end,
 3525            None => false,
 3526        };
 3527
 3528        pending_nonempty_selection
 3529            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3530    }
 3531
 3532    pub fn has_pending_selection(&self) -> bool {
 3533        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3534    }
 3535
 3536    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3537        self.selection_mark_mode = false;
 3538
 3539        if self.clear_expanded_diff_hunks(cx) {
 3540            cx.notify();
 3541            return;
 3542        }
 3543        if self.dismiss_menus_and_popups(true, window, cx) {
 3544            return;
 3545        }
 3546
 3547        if self.mode.is_full()
 3548            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3549        {
 3550            return;
 3551        }
 3552
 3553        cx.propagate();
 3554    }
 3555
 3556    pub fn dismiss_menus_and_popups(
 3557        &mut self,
 3558        is_user_requested: bool,
 3559        window: &mut Window,
 3560        cx: &mut Context<Self>,
 3561    ) -> bool {
 3562        if self.take_rename(false, window, cx).is_some() {
 3563            return true;
 3564        }
 3565
 3566        if hide_hover(self, cx) {
 3567            return true;
 3568        }
 3569
 3570        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3571            return true;
 3572        }
 3573
 3574        if self.hide_context_menu(window, cx).is_some() {
 3575            return true;
 3576        }
 3577
 3578        if self.mouse_context_menu.take().is_some() {
 3579            return true;
 3580        }
 3581
 3582        if is_user_requested && self.discard_inline_completion(true, cx) {
 3583            return true;
 3584        }
 3585
 3586        if self.snippet_stack.pop().is_some() {
 3587            return true;
 3588        }
 3589
 3590        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3591            self.dismiss_diagnostics(cx);
 3592            return true;
 3593        }
 3594
 3595        false
 3596    }
 3597
 3598    fn linked_editing_ranges_for(
 3599        &self,
 3600        selection: Range<text::Anchor>,
 3601        cx: &App,
 3602    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3603        if self.linked_edit_ranges.is_empty() {
 3604            return None;
 3605        }
 3606        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3607            selection.end.buffer_id.and_then(|end_buffer_id| {
 3608                if selection.start.buffer_id != Some(end_buffer_id) {
 3609                    return None;
 3610                }
 3611                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3612                let snapshot = buffer.read(cx).snapshot();
 3613                self.linked_edit_ranges
 3614                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3615                    .map(|ranges| (ranges, snapshot, buffer))
 3616            })?;
 3617        use text::ToOffset as TO;
 3618        // find offset from the start of current range to current cursor position
 3619        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3620
 3621        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3622        let start_difference = start_offset - start_byte_offset;
 3623        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3624        let end_difference = end_offset - start_byte_offset;
 3625        // Current range has associated linked ranges.
 3626        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3627        for range in linked_ranges.iter() {
 3628            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3629            let end_offset = start_offset + end_difference;
 3630            let start_offset = start_offset + start_difference;
 3631            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3632                continue;
 3633            }
 3634            if self.selections.disjoint_anchor_ranges().any(|s| {
 3635                if s.start.buffer_id != selection.start.buffer_id
 3636                    || s.end.buffer_id != selection.end.buffer_id
 3637                {
 3638                    return false;
 3639                }
 3640                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3641                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3642            }) {
 3643                continue;
 3644            }
 3645            let start = buffer_snapshot.anchor_after(start_offset);
 3646            let end = buffer_snapshot.anchor_after(end_offset);
 3647            linked_edits
 3648                .entry(buffer.clone())
 3649                .or_default()
 3650                .push(start..end);
 3651        }
 3652        Some(linked_edits)
 3653    }
 3654
 3655    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3656        let text: Arc<str> = text.into();
 3657
 3658        if self.read_only(cx) {
 3659            return;
 3660        }
 3661
 3662        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3663
 3664        let selections = self.selections.all_adjusted(cx);
 3665        let mut bracket_inserted = false;
 3666        let mut edits = Vec::new();
 3667        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3668        let mut new_selections = Vec::with_capacity(selections.len());
 3669        let mut new_autoclose_regions = Vec::new();
 3670        let snapshot = self.buffer.read(cx).read(cx);
 3671        let mut clear_linked_edit_ranges = false;
 3672
 3673        for (selection, autoclose_region) in
 3674            self.selections_with_autoclose_regions(selections, &snapshot)
 3675        {
 3676            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3677                // Determine if the inserted text matches the opening or closing
 3678                // bracket of any of this language's bracket pairs.
 3679                let mut bracket_pair = None;
 3680                let mut is_bracket_pair_start = false;
 3681                let mut is_bracket_pair_end = false;
 3682                if !text.is_empty() {
 3683                    let mut bracket_pair_matching_end = None;
 3684                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3685                    //  and they are removing the character that triggered IME popup.
 3686                    for (pair, enabled) in scope.brackets() {
 3687                        if !pair.close && !pair.surround {
 3688                            continue;
 3689                        }
 3690
 3691                        if enabled && pair.start.ends_with(text.as_ref()) {
 3692                            let prefix_len = pair.start.len() - text.len();
 3693                            let preceding_text_matches_prefix = prefix_len == 0
 3694                                || (selection.start.column >= (prefix_len as u32)
 3695                                    && snapshot.contains_str_at(
 3696                                        Point::new(
 3697                                            selection.start.row,
 3698                                            selection.start.column - (prefix_len as u32),
 3699                                        ),
 3700                                        &pair.start[..prefix_len],
 3701                                    ));
 3702                            if preceding_text_matches_prefix {
 3703                                bracket_pair = Some(pair.clone());
 3704                                is_bracket_pair_start = true;
 3705                                break;
 3706                            }
 3707                        }
 3708                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3709                        {
 3710                            // take first bracket pair matching end, but don't break in case a later bracket
 3711                            // pair matches start
 3712                            bracket_pair_matching_end = Some(pair.clone());
 3713                        }
 3714                    }
 3715                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3716                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3717                        is_bracket_pair_end = true;
 3718                    }
 3719                }
 3720
 3721                if let Some(bracket_pair) = bracket_pair {
 3722                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3723                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3724                    let auto_surround =
 3725                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3726                    if selection.is_empty() {
 3727                        if is_bracket_pair_start {
 3728                            // If the inserted text is a suffix of an opening bracket and the
 3729                            // selection is preceded by the rest of the opening bracket, then
 3730                            // insert the closing bracket.
 3731                            let following_text_allows_autoclose = snapshot
 3732                                .chars_at(selection.start)
 3733                                .next()
 3734                                .map_or(true, |c| scope.should_autoclose_before(c));
 3735
 3736                            let preceding_text_allows_autoclose = selection.start.column == 0
 3737                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3738                                    true,
 3739                                    |c| {
 3740                                        bracket_pair.start != bracket_pair.end
 3741                                            || !snapshot
 3742                                                .char_classifier_at(selection.start)
 3743                                                .is_word(c)
 3744                                    },
 3745                                );
 3746
 3747                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3748                                && bracket_pair.start.len() == 1
 3749                            {
 3750                                let target = bracket_pair.start.chars().next().unwrap();
 3751                                let current_line_count = snapshot
 3752                                    .reversed_chars_at(selection.start)
 3753                                    .take_while(|&c| c != '\n')
 3754                                    .filter(|&c| c == target)
 3755                                    .count();
 3756                                current_line_count % 2 == 1
 3757                            } else {
 3758                                false
 3759                            };
 3760
 3761                            if autoclose
 3762                                && bracket_pair.close
 3763                                && following_text_allows_autoclose
 3764                                && preceding_text_allows_autoclose
 3765                                && !is_closing_quote
 3766                            {
 3767                                let anchor = snapshot.anchor_before(selection.end);
 3768                                new_selections.push((selection.map(|_| anchor), text.len()));
 3769                                new_autoclose_regions.push((
 3770                                    anchor,
 3771                                    text.len(),
 3772                                    selection.id,
 3773                                    bracket_pair.clone(),
 3774                                ));
 3775                                edits.push((
 3776                                    selection.range(),
 3777                                    format!("{}{}", text, bracket_pair.end).into(),
 3778                                ));
 3779                                bracket_inserted = true;
 3780                                continue;
 3781                            }
 3782                        }
 3783
 3784                        if let Some(region) = autoclose_region {
 3785                            // If the selection is followed by an auto-inserted closing bracket,
 3786                            // then don't insert that closing bracket again; just move the selection
 3787                            // past the closing bracket.
 3788                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3789                                && text.as_ref() == region.pair.end.as_str();
 3790                            if should_skip {
 3791                                let anchor = snapshot.anchor_after(selection.end);
 3792                                new_selections
 3793                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3794                                continue;
 3795                            }
 3796                        }
 3797
 3798                        let always_treat_brackets_as_autoclosed = snapshot
 3799                            .language_settings_at(selection.start, cx)
 3800                            .always_treat_brackets_as_autoclosed;
 3801                        if always_treat_brackets_as_autoclosed
 3802                            && is_bracket_pair_end
 3803                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3804                        {
 3805                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3806                            // and the inserted text is a closing bracket and the selection is followed
 3807                            // by the closing bracket then move the selection past the closing bracket.
 3808                            let anchor = snapshot.anchor_after(selection.end);
 3809                            new_selections.push((selection.map(|_| anchor), text.len()));
 3810                            continue;
 3811                        }
 3812                    }
 3813                    // If an opening bracket is 1 character long and is typed while
 3814                    // text is selected, then surround that text with the bracket pair.
 3815                    else if auto_surround
 3816                        && bracket_pair.surround
 3817                        && is_bracket_pair_start
 3818                        && bracket_pair.start.chars().count() == 1
 3819                    {
 3820                        edits.push((selection.start..selection.start, text.clone()));
 3821                        edits.push((
 3822                            selection.end..selection.end,
 3823                            bracket_pair.end.as_str().into(),
 3824                        ));
 3825                        bracket_inserted = true;
 3826                        new_selections.push((
 3827                            Selection {
 3828                                id: selection.id,
 3829                                start: snapshot.anchor_after(selection.start),
 3830                                end: snapshot.anchor_before(selection.end),
 3831                                reversed: selection.reversed,
 3832                                goal: selection.goal,
 3833                            },
 3834                            0,
 3835                        ));
 3836                        continue;
 3837                    }
 3838                }
 3839            }
 3840
 3841            if self.auto_replace_emoji_shortcode
 3842                && selection.is_empty()
 3843                && text.as_ref().ends_with(':')
 3844            {
 3845                if let Some(possible_emoji_short_code) =
 3846                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3847                {
 3848                    if !possible_emoji_short_code.is_empty() {
 3849                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3850                            let emoji_shortcode_start = Point::new(
 3851                                selection.start.row,
 3852                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3853                            );
 3854
 3855                            // Remove shortcode from buffer
 3856                            edits.push((
 3857                                emoji_shortcode_start..selection.start,
 3858                                "".to_string().into(),
 3859                            ));
 3860                            new_selections.push((
 3861                                Selection {
 3862                                    id: selection.id,
 3863                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3864                                    end: snapshot.anchor_before(selection.start),
 3865                                    reversed: selection.reversed,
 3866                                    goal: selection.goal,
 3867                                },
 3868                                0,
 3869                            ));
 3870
 3871                            // Insert emoji
 3872                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3873                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3874                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3875
 3876                            continue;
 3877                        }
 3878                    }
 3879                }
 3880            }
 3881
 3882            // If not handling any auto-close operation, then just replace the selected
 3883            // text with the given input and move the selection to the end of the
 3884            // newly inserted text.
 3885            let anchor = snapshot.anchor_after(selection.end);
 3886            if !self.linked_edit_ranges.is_empty() {
 3887                let start_anchor = snapshot.anchor_before(selection.start);
 3888
 3889                let is_word_char = text.chars().next().map_or(true, |char| {
 3890                    let classifier = snapshot
 3891                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3892                        .ignore_punctuation(true);
 3893                    classifier.is_word(char)
 3894                });
 3895
 3896                if is_word_char {
 3897                    if let Some(ranges) = self
 3898                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3899                    {
 3900                        for (buffer, edits) in ranges {
 3901                            linked_edits
 3902                                .entry(buffer.clone())
 3903                                .or_default()
 3904                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3905                        }
 3906                    }
 3907                } else {
 3908                    clear_linked_edit_ranges = true;
 3909                }
 3910            }
 3911
 3912            new_selections.push((selection.map(|_| anchor), 0));
 3913            edits.push((selection.start..selection.end, text.clone()));
 3914        }
 3915
 3916        drop(snapshot);
 3917
 3918        self.transact(window, cx, |this, window, cx| {
 3919            if clear_linked_edit_ranges {
 3920                this.linked_edit_ranges.clear();
 3921            }
 3922            let initial_buffer_versions =
 3923                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3924
 3925            this.buffer.update(cx, |buffer, cx| {
 3926                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3927            });
 3928            for (buffer, edits) in linked_edits {
 3929                buffer.update(cx, |buffer, cx| {
 3930                    let snapshot = buffer.snapshot();
 3931                    let edits = edits
 3932                        .into_iter()
 3933                        .map(|(range, text)| {
 3934                            use text::ToPoint as TP;
 3935                            let end_point = TP::to_point(&range.end, &snapshot);
 3936                            let start_point = TP::to_point(&range.start, &snapshot);
 3937                            (start_point..end_point, text)
 3938                        })
 3939                        .sorted_by_key(|(range, _)| range.start);
 3940                    buffer.edit(edits, None, cx);
 3941                })
 3942            }
 3943            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3944            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3945            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3946            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3947                .zip(new_selection_deltas)
 3948                .map(|(selection, delta)| Selection {
 3949                    id: selection.id,
 3950                    start: selection.start + delta,
 3951                    end: selection.end + delta,
 3952                    reversed: selection.reversed,
 3953                    goal: SelectionGoal::None,
 3954                })
 3955                .collect::<Vec<_>>();
 3956
 3957            let mut i = 0;
 3958            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3959                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3960                let start = map.buffer_snapshot.anchor_before(position);
 3961                let end = map.buffer_snapshot.anchor_after(position);
 3962                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3963                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3964                        Ordering::Less => i += 1,
 3965                        Ordering::Greater => break,
 3966                        Ordering::Equal => {
 3967                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3968                                Ordering::Less => i += 1,
 3969                                Ordering::Equal => break,
 3970                                Ordering::Greater => break,
 3971                            }
 3972                        }
 3973                    }
 3974                }
 3975                this.autoclose_regions.insert(
 3976                    i,
 3977                    AutocloseRegion {
 3978                        selection_id,
 3979                        range: start..end,
 3980                        pair,
 3981                    },
 3982                );
 3983            }
 3984
 3985            let had_active_inline_completion = this.has_active_inline_completion();
 3986            this.change_selections_without_updating_completions(
 3987                Some(Autoscroll::fit()),
 3988                window,
 3989                cx,
 3990                |s| s.select(new_selections),
 3991            );
 3992
 3993            if !bracket_inserted {
 3994                if let Some(on_type_format_task) =
 3995                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3996                {
 3997                    on_type_format_task.detach_and_log_err(cx);
 3998                }
 3999            }
 4000
 4001            let editor_settings = EditorSettings::get_global(cx);
 4002            if bracket_inserted
 4003                && (editor_settings.auto_signature_help
 4004                    || editor_settings.show_signature_help_after_edits)
 4005            {
 4006                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4007            }
 4008
 4009            let trigger_in_words =
 4010                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4011            if this.hard_wrap.is_some() {
 4012                let latest: Range<Point> = this.selections.newest(cx).range();
 4013                if latest.is_empty()
 4014                    && this
 4015                        .buffer()
 4016                        .read(cx)
 4017                        .snapshot(cx)
 4018                        .line_len(MultiBufferRow(latest.start.row))
 4019                        == latest.start.column
 4020                {
 4021                    this.rewrap_impl(
 4022                        RewrapOptions {
 4023                            override_language_settings: true,
 4024                            preserve_existing_whitespace: true,
 4025                        },
 4026                        cx,
 4027                    )
 4028                }
 4029            }
 4030            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4031            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4032            this.refresh_inline_completion(true, false, window, cx);
 4033            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4034        });
 4035    }
 4036
 4037    fn find_possible_emoji_shortcode_at_position(
 4038        snapshot: &MultiBufferSnapshot,
 4039        position: Point,
 4040    ) -> Option<String> {
 4041        let mut chars = Vec::new();
 4042        let mut found_colon = false;
 4043        for char in snapshot.reversed_chars_at(position).take(100) {
 4044            // Found a possible emoji shortcode in the middle of the buffer
 4045            if found_colon {
 4046                if char.is_whitespace() {
 4047                    chars.reverse();
 4048                    return Some(chars.iter().collect());
 4049                }
 4050                // If the previous character is not a whitespace, we are in the middle of a word
 4051                // and we only want to complete the shortcode if the word is made up of other emojis
 4052                let mut containing_word = String::new();
 4053                for ch in snapshot
 4054                    .reversed_chars_at(position)
 4055                    .skip(chars.len() + 1)
 4056                    .take(100)
 4057                {
 4058                    if ch.is_whitespace() {
 4059                        break;
 4060                    }
 4061                    containing_word.push(ch);
 4062                }
 4063                let containing_word = containing_word.chars().rev().collect::<String>();
 4064                if util::word_consists_of_emojis(containing_word.as_str()) {
 4065                    chars.reverse();
 4066                    return Some(chars.iter().collect());
 4067                }
 4068            }
 4069
 4070            if char.is_whitespace() || !char.is_ascii() {
 4071                return None;
 4072            }
 4073            if char == ':' {
 4074                found_colon = true;
 4075            } else {
 4076                chars.push(char);
 4077            }
 4078        }
 4079        // Found a possible emoji shortcode at the beginning of the buffer
 4080        chars.reverse();
 4081        Some(chars.iter().collect())
 4082    }
 4083
 4084    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4085        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4086        self.transact(window, cx, |this, window, cx| {
 4087            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4088                let selections = this.selections.all::<usize>(cx);
 4089                let multi_buffer = this.buffer.read(cx);
 4090                let buffer = multi_buffer.snapshot(cx);
 4091                selections
 4092                    .iter()
 4093                    .map(|selection| {
 4094                        let start_point = selection.start.to_point(&buffer);
 4095                        let mut existing_indent =
 4096                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4097                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4098                        let start = selection.start;
 4099                        let end = selection.end;
 4100                        let selection_is_empty = start == end;
 4101                        let language_scope = buffer.language_scope_at(start);
 4102                        let (
 4103                            comment_delimiter,
 4104                            doc_delimiter,
 4105                            insert_extra_newline,
 4106                            indent_on_newline,
 4107                            indent_on_extra_newline,
 4108                        ) = if let Some(language) = &language_scope {
 4109                            let mut insert_extra_newline =
 4110                                insert_extra_newline_brackets(&buffer, start..end, language)
 4111                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4112
 4113                            // Comment extension on newline is allowed only for cursor selections
 4114                            let comment_delimiter = maybe!({
 4115                                if !selection_is_empty {
 4116                                    return None;
 4117                                }
 4118
 4119                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4120                                    return None;
 4121                                }
 4122
 4123                                let delimiters = language.line_comment_prefixes();
 4124                                let max_len_of_delimiter =
 4125                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4126                                let (snapshot, range) =
 4127                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4128
 4129                                let num_of_whitespaces = snapshot
 4130                                    .chars_for_range(range.clone())
 4131                                    .take_while(|c| c.is_whitespace())
 4132                                    .count();
 4133                                let comment_candidate = snapshot
 4134                                    .chars_for_range(range)
 4135                                    .skip(num_of_whitespaces)
 4136                                    .take(max_len_of_delimiter)
 4137                                    .collect::<String>();
 4138                                let (delimiter, trimmed_len) = delimiters
 4139                                    .iter()
 4140                                    .filter_map(|delimiter| {
 4141                                        let prefix = delimiter.trim_end();
 4142                                        if comment_candidate.starts_with(prefix) {
 4143                                            Some((delimiter, prefix.len()))
 4144                                        } else {
 4145                                            None
 4146                                        }
 4147                                    })
 4148                                    .max_by_key(|(_, len)| *len)?;
 4149
 4150                                let cursor_is_placed_after_comment_marker =
 4151                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4152                                if cursor_is_placed_after_comment_marker {
 4153                                    Some(delimiter.clone())
 4154                                } else {
 4155                                    None
 4156                                }
 4157                            });
 4158
 4159                            let mut indent_on_newline = IndentSize::spaces(0);
 4160                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4161
 4162                            let doc_delimiter = maybe!({
 4163                                if !selection_is_empty {
 4164                                    return None;
 4165                                }
 4166
 4167                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4168                                    return None;
 4169                                }
 4170
 4171                                let DocumentationConfig {
 4172                                    start: start_tag,
 4173                                    end: end_tag,
 4174                                    prefix: delimiter,
 4175                                    tab_size: len,
 4176                                } = language.documentation()?;
 4177
 4178                                let is_within_block_comment = buffer
 4179                                    .language_scope_at(start_point)
 4180                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4181                                if !is_within_block_comment {
 4182                                    return None;
 4183                                }
 4184
 4185                                let (snapshot, range) =
 4186                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4187
 4188                                let num_of_whitespaces = snapshot
 4189                                    .chars_for_range(range.clone())
 4190                                    .take_while(|c| c.is_whitespace())
 4191                                    .count();
 4192
 4193                                // 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.
 4194                                let column = start_point.column;
 4195                                let cursor_is_after_start_tag = {
 4196                                    let start_tag_len = start_tag.len();
 4197                                    let start_tag_line = snapshot
 4198                                        .chars_for_range(range.clone())
 4199                                        .skip(num_of_whitespaces)
 4200                                        .take(start_tag_len)
 4201                                        .collect::<String>();
 4202                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4203                                        num_of_whitespaces + start_tag_len <= column as usize
 4204                                    } else {
 4205                                        false
 4206                                    }
 4207                                };
 4208
 4209                                let cursor_is_after_delimiter = {
 4210                                    let delimiter_trim = delimiter.trim_end();
 4211                                    let delimiter_line = snapshot
 4212                                        .chars_for_range(range.clone())
 4213                                        .skip(num_of_whitespaces)
 4214                                        .take(delimiter_trim.len())
 4215                                        .collect::<String>();
 4216                                    if delimiter_line.starts_with(delimiter_trim) {
 4217                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4218                                    } else {
 4219                                        false
 4220                                    }
 4221                                };
 4222
 4223                                let cursor_is_before_end_tag_if_exists = {
 4224                                    let mut char_position = 0u32;
 4225                                    let mut end_tag_offset = None;
 4226
 4227                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4228                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4229                                            let chars_before_match =
 4230                                                chunk[..byte_pos].chars().count() as u32;
 4231                                            end_tag_offset =
 4232                                                Some(char_position + chars_before_match);
 4233                                            break 'outer;
 4234                                        }
 4235                                        char_position += chunk.chars().count() as u32;
 4236                                    }
 4237
 4238                                    if let Some(end_tag_offset) = end_tag_offset {
 4239                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4240                                        if cursor_is_after_start_tag {
 4241                                            if cursor_is_before_end_tag {
 4242                                                insert_extra_newline = true;
 4243                                            }
 4244                                            let cursor_is_at_start_of_end_tag =
 4245                                                column == end_tag_offset;
 4246                                            if cursor_is_at_start_of_end_tag {
 4247                                                indent_on_extra_newline.len = (*len).into();
 4248                                            }
 4249                                        }
 4250                                        cursor_is_before_end_tag
 4251                                    } else {
 4252                                        true
 4253                                    }
 4254                                };
 4255
 4256                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4257                                    && cursor_is_before_end_tag_if_exists
 4258                                {
 4259                                    if cursor_is_after_start_tag {
 4260                                        indent_on_newline.len = (*len).into();
 4261                                    }
 4262                                    Some(delimiter.clone())
 4263                                } else {
 4264                                    None
 4265                                }
 4266                            });
 4267
 4268                            (
 4269                                comment_delimiter,
 4270                                doc_delimiter,
 4271                                insert_extra_newline,
 4272                                indent_on_newline,
 4273                                indent_on_extra_newline,
 4274                            )
 4275                        } else {
 4276                            (
 4277                                None,
 4278                                None,
 4279                                false,
 4280                                IndentSize::default(),
 4281                                IndentSize::default(),
 4282                            )
 4283                        };
 4284
 4285                        let prevent_auto_indent = doc_delimiter.is_some();
 4286                        let delimiter = comment_delimiter.or(doc_delimiter);
 4287
 4288                        let capacity_for_delimiter =
 4289                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4290                        let mut new_text = String::with_capacity(
 4291                            1 + capacity_for_delimiter
 4292                                + existing_indent.len as usize
 4293                                + indent_on_newline.len as usize
 4294                                + indent_on_extra_newline.len as usize,
 4295                        );
 4296                        new_text.push('\n');
 4297                        new_text.extend(existing_indent.chars());
 4298                        new_text.extend(indent_on_newline.chars());
 4299
 4300                        if let Some(delimiter) = &delimiter {
 4301                            new_text.push_str(delimiter);
 4302                        }
 4303
 4304                        if insert_extra_newline {
 4305                            new_text.push('\n');
 4306                            new_text.extend(existing_indent.chars());
 4307                            new_text.extend(indent_on_extra_newline.chars());
 4308                        }
 4309
 4310                        let anchor = buffer.anchor_after(end);
 4311                        let new_selection = selection.map(|_| anchor);
 4312                        (
 4313                            ((start..end, new_text), prevent_auto_indent),
 4314                            (insert_extra_newline, new_selection),
 4315                        )
 4316                    })
 4317                    .unzip()
 4318            };
 4319
 4320            let mut auto_indent_edits = Vec::new();
 4321            let mut edits = Vec::new();
 4322            for (edit, prevent_auto_indent) in edits_with_flags {
 4323                if prevent_auto_indent {
 4324                    edits.push(edit);
 4325                } else {
 4326                    auto_indent_edits.push(edit);
 4327                }
 4328            }
 4329            if !edits.is_empty() {
 4330                this.edit(edits, cx);
 4331            }
 4332            if !auto_indent_edits.is_empty() {
 4333                this.edit_with_autoindent(auto_indent_edits, cx);
 4334            }
 4335
 4336            let buffer = this.buffer.read(cx).snapshot(cx);
 4337            let new_selections = selection_info
 4338                .into_iter()
 4339                .map(|(extra_newline_inserted, new_selection)| {
 4340                    let mut cursor = new_selection.end.to_point(&buffer);
 4341                    if extra_newline_inserted {
 4342                        cursor.row -= 1;
 4343                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4344                    }
 4345                    new_selection.map(|_| cursor)
 4346                })
 4347                .collect();
 4348
 4349            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4350                s.select(new_selections)
 4351            });
 4352            this.refresh_inline_completion(true, false, window, cx);
 4353        });
 4354    }
 4355
 4356    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4357        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4358
 4359        let buffer = self.buffer.read(cx);
 4360        let snapshot = buffer.snapshot(cx);
 4361
 4362        let mut edits = Vec::new();
 4363        let mut rows = Vec::new();
 4364
 4365        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4366            let cursor = selection.head();
 4367            let row = cursor.row;
 4368
 4369            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4370
 4371            let newline = "\n".to_string();
 4372            edits.push((start_of_line..start_of_line, newline));
 4373
 4374            rows.push(row + rows_inserted as u32);
 4375        }
 4376
 4377        self.transact(window, cx, |editor, window, cx| {
 4378            editor.edit(edits, cx);
 4379
 4380            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4381                let mut index = 0;
 4382                s.move_cursors_with(|map, _, _| {
 4383                    let row = rows[index];
 4384                    index += 1;
 4385
 4386                    let point = Point::new(row, 0);
 4387                    let boundary = map.next_line_boundary(point).1;
 4388                    let clipped = map.clip_point(boundary, Bias::Left);
 4389
 4390                    (clipped, SelectionGoal::None)
 4391                });
 4392            });
 4393
 4394            let mut indent_edits = Vec::new();
 4395            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4396            for row in rows {
 4397                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4398                for (row, indent) in indents {
 4399                    if indent.len == 0 {
 4400                        continue;
 4401                    }
 4402
 4403                    let text = match indent.kind {
 4404                        IndentKind::Space => " ".repeat(indent.len as usize),
 4405                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4406                    };
 4407                    let point = Point::new(row.0, 0);
 4408                    indent_edits.push((point..point, text));
 4409                }
 4410            }
 4411            editor.edit(indent_edits, cx);
 4412        });
 4413    }
 4414
 4415    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4416        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4417
 4418        let buffer = self.buffer.read(cx);
 4419        let snapshot = buffer.snapshot(cx);
 4420
 4421        let mut edits = Vec::new();
 4422        let mut rows = Vec::new();
 4423        let mut rows_inserted = 0;
 4424
 4425        for selection in self.selections.all_adjusted(cx) {
 4426            let cursor = selection.head();
 4427            let row = cursor.row;
 4428
 4429            let point = Point::new(row + 1, 0);
 4430            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4431
 4432            let newline = "\n".to_string();
 4433            edits.push((start_of_line..start_of_line, newline));
 4434
 4435            rows_inserted += 1;
 4436            rows.push(row + rows_inserted);
 4437        }
 4438
 4439        self.transact(window, cx, |editor, window, cx| {
 4440            editor.edit(edits, cx);
 4441
 4442            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4443                let mut index = 0;
 4444                s.move_cursors_with(|map, _, _| {
 4445                    let row = rows[index];
 4446                    index += 1;
 4447
 4448                    let point = Point::new(row, 0);
 4449                    let boundary = map.next_line_boundary(point).1;
 4450                    let clipped = map.clip_point(boundary, Bias::Left);
 4451
 4452                    (clipped, SelectionGoal::None)
 4453                });
 4454            });
 4455
 4456            let mut indent_edits = Vec::new();
 4457            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4458            for row in rows {
 4459                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4460                for (row, indent) in indents {
 4461                    if indent.len == 0 {
 4462                        continue;
 4463                    }
 4464
 4465                    let text = match indent.kind {
 4466                        IndentKind::Space => " ".repeat(indent.len as usize),
 4467                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4468                    };
 4469                    let point = Point::new(row.0, 0);
 4470                    indent_edits.push((point..point, text));
 4471                }
 4472            }
 4473            editor.edit(indent_edits, cx);
 4474        });
 4475    }
 4476
 4477    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4478        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4479            original_indent_columns: Vec::new(),
 4480        });
 4481        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4482    }
 4483
 4484    fn insert_with_autoindent_mode(
 4485        &mut self,
 4486        text: &str,
 4487        autoindent_mode: Option<AutoindentMode>,
 4488        window: &mut Window,
 4489        cx: &mut Context<Self>,
 4490    ) {
 4491        if self.read_only(cx) {
 4492            return;
 4493        }
 4494
 4495        let text: Arc<str> = text.into();
 4496        self.transact(window, cx, |this, window, cx| {
 4497            let old_selections = this.selections.all_adjusted(cx);
 4498            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4499                let anchors = {
 4500                    let snapshot = buffer.read(cx);
 4501                    old_selections
 4502                        .iter()
 4503                        .map(|s| {
 4504                            let anchor = snapshot.anchor_after(s.head());
 4505                            s.map(|_| anchor)
 4506                        })
 4507                        .collect::<Vec<_>>()
 4508                };
 4509                buffer.edit(
 4510                    old_selections
 4511                        .iter()
 4512                        .map(|s| (s.start..s.end, text.clone())),
 4513                    autoindent_mode,
 4514                    cx,
 4515                );
 4516                anchors
 4517            });
 4518
 4519            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4520                s.select_anchors(selection_anchors);
 4521            });
 4522
 4523            cx.notify();
 4524        });
 4525    }
 4526
 4527    fn trigger_completion_on_input(
 4528        &mut self,
 4529        text: &str,
 4530        trigger_in_words: bool,
 4531        window: &mut Window,
 4532        cx: &mut Context<Self>,
 4533    ) {
 4534        let completions_source = self
 4535            .context_menu
 4536            .borrow()
 4537            .as_ref()
 4538            .and_then(|menu| match menu {
 4539                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4540                CodeContextMenu::CodeActions(_) => None,
 4541            });
 4542
 4543        match completions_source {
 4544            Some(CompletionsMenuSource::Words) => {
 4545                self.show_word_completions(&ShowWordCompletions, window, cx)
 4546            }
 4547            Some(CompletionsMenuSource::Normal)
 4548            | Some(CompletionsMenuSource::SnippetChoices)
 4549            | None
 4550                if self.is_completion_trigger(
 4551                    text,
 4552                    trigger_in_words,
 4553                    completions_source.is_some(),
 4554                    cx,
 4555                ) =>
 4556            {
 4557                self.show_completions(
 4558                    &ShowCompletions {
 4559                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4560                    },
 4561                    window,
 4562                    cx,
 4563                )
 4564            }
 4565            _ => {
 4566                self.hide_context_menu(window, cx);
 4567            }
 4568        }
 4569    }
 4570
 4571    fn is_completion_trigger(
 4572        &self,
 4573        text: &str,
 4574        trigger_in_words: bool,
 4575        menu_is_open: bool,
 4576        cx: &mut Context<Self>,
 4577    ) -> bool {
 4578        let position = self.selections.newest_anchor().head();
 4579        let multibuffer = self.buffer.read(cx);
 4580        let Some(buffer) = position
 4581            .buffer_id
 4582            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4583        else {
 4584            return false;
 4585        };
 4586
 4587        if let Some(completion_provider) = &self.completion_provider {
 4588            completion_provider.is_completion_trigger(
 4589                &buffer,
 4590                position.text_anchor,
 4591                text,
 4592                trigger_in_words,
 4593                menu_is_open,
 4594                cx,
 4595            )
 4596        } else {
 4597            false
 4598        }
 4599    }
 4600
 4601    /// If any empty selections is touching the start of its innermost containing autoclose
 4602    /// region, expand it to select the brackets.
 4603    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4604        let selections = self.selections.all::<usize>(cx);
 4605        let buffer = self.buffer.read(cx).read(cx);
 4606        let new_selections = self
 4607            .selections_with_autoclose_regions(selections, &buffer)
 4608            .map(|(mut selection, region)| {
 4609                if !selection.is_empty() {
 4610                    return selection;
 4611                }
 4612
 4613                if let Some(region) = region {
 4614                    let mut range = region.range.to_offset(&buffer);
 4615                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4616                        range.start -= region.pair.start.len();
 4617                        if buffer.contains_str_at(range.start, &region.pair.start)
 4618                            && buffer.contains_str_at(range.end, &region.pair.end)
 4619                        {
 4620                            range.end += region.pair.end.len();
 4621                            selection.start = range.start;
 4622                            selection.end = range.end;
 4623
 4624                            return selection;
 4625                        }
 4626                    }
 4627                }
 4628
 4629                let always_treat_brackets_as_autoclosed = buffer
 4630                    .language_settings_at(selection.start, cx)
 4631                    .always_treat_brackets_as_autoclosed;
 4632
 4633                if !always_treat_brackets_as_autoclosed {
 4634                    return selection;
 4635                }
 4636
 4637                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4638                    for (pair, enabled) in scope.brackets() {
 4639                        if !enabled || !pair.close {
 4640                            continue;
 4641                        }
 4642
 4643                        if buffer.contains_str_at(selection.start, &pair.end) {
 4644                            let pair_start_len = pair.start.len();
 4645                            if buffer.contains_str_at(
 4646                                selection.start.saturating_sub(pair_start_len),
 4647                                &pair.start,
 4648                            ) {
 4649                                selection.start -= pair_start_len;
 4650                                selection.end += pair.end.len();
 4651
 4652                                return selection;
 4653                            }
 4654                        }
 4655                    }
 4656                }
 4657
 4658                selection
 4659            })
 4660            .collect();
 4661
 4662        drop(buffer);
 4663        self.change_selections(None, window, cx, |selections| {
 4664            selections.select(new_selections)
 4665        });
 4666    }
 4667
 4668    /// Iterate the given selections, and for each one, find the smallest surrounding
 4669    /// autoclose region. This uses the ordering of the selections and the autoclose
 4670    /// regions to avoid repeated comparisons.
 4671    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4672        &'a self,
 4673        selections: impl IntoIterator<Item = Selection<D>>,
 4674        buffer: &'a MultiBufferSnapshot,
 4675    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4676        let mut i = 0;
 4677        let mut regions = self.autoclose_regions.as_slice();
 4678        selections.into_iter().map(move |selection| {
 4679            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4680
 4681            let mut enclosing = None;
 4682            while let Some(pair_state) = regions.get(i) {
 4683                if pair_state.range.end.to_offset(buffer) < range.start {
 4684                    regions = &regions[i + 1..];
 4685                    i = 0;
 4686                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4687                    break;
 4688                } else {
 4689                    if pair_state.selection_id == selection.id {
 4690                        enclosing = Some(pair_state);
 4691                    }
 4692                    i += 1;
 4693                }
 4694            }
 4695
 4696            (selection, enclosing)
 4697        })
 4698    }
 4699
 4700    /// Remove any autoclose regions that no longer contain their selection.
 4701    fn invalidate_autoclose_regions(
 4702        &mut self,
 4703        mut selections: &[Selection<Anchor>],
 4704        buffer: &MultiBufferSnapshot,
 4705    ) {
 4706        self.autoclose_regions.retain(|state| {
 4707            let mut i = 0;
 4708            while let Some(selection) = selections.get(i) {
 4709                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4710                    selections = &selections[1..];
 4711                    continue;
 4712                }
 4713                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4714                    break;
 4715                }
 4716                if selection.id == state.selection_id {
 4717                    return true;
 4718                } else {
 4719                    i += 1;
 4720                }
 4721            }
 4722            false
 4723        });
 4724    }
 4725
 4726    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4727        let offset = position.to_offset(buffer);
 4728        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4729        if offset > word_range.start && kind == Some(CharKind::Word) {
 4730            Some(
 4731                buffer
 4732                    .text_for_range(word_range.start..offset)
 4733                    .collect::<String>(),
 4734            )
 4735        } else {
 4736            None
 4737        }
 4738    }
 4739
 4740    pub fn toggle_inline_values(
 4741        &mut self,
 4742        _: &ToggleInlineValues,
 4743        _: &mut Window,
 4744        cx: &mut Context<Self>,
 4745    ) {
 4746        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4747
 4748        self.refresh_inline_values(cx);
 4749    }
 4750
 4751    pub fn toggle_inlay_hints(
 4752        &mut self,
 4753        _: &ToggleInlayHints,
 4754        _: &mut Window,
 4755        cx: &mut Context<Self>,
 4756    ) {
 4757        self.refresh_inlay_hints(
 4758            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4759            cx,
 4760        );
 4761    }
 4762
 4763    pub fn inlay_hints_enabled(&self) -> bool {
 4764        self.inlay_hint_cache.enabled
 4765    }
 4766
 4767    pub fn inline_values_enabled(&self) -> bool {
 4768        self.inline_value_cache.enabled
 4769    }
 4770
 4771    #[cfg(any(test, feature = "test-support"))]
 4772    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4773        self.display_map
 4774            .read(cx)
 4775            .current_inlays()
 4776            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4777            .cloned()
 4778            .collect()
 4779    }
 4780
 4781    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4782        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4783            return;
 4784        }
 4785
 4786        let reason_description = reason.description();
 4787        let ignore_debounce = matches!(
 4788            reason,
 4789            InlayHintRefreshReason::SettingsChange(_)
 4790                | InlayHintRefreshReason::Toggle(_)
 4791                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4792                | InlayHintRefreshReason::ModifiersChanged(_)
 4793        );
 4794        let (invalidate_cache, required_languages) = match reason {
 4795            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4796                match self.inlay_hint_cache.modifiers_override(enabled) {
 4797                    Some(enabled) => {
 4798                        if enabled {
 4799                            (InvalidationStrategy::RefreshRequested, None)
 4800                        } else {
 4801                            self.splice_inlays(
 4802                                &self
 4803                                    .visible_inlay_hints(cx)
 4804                                    .iter()
 4805                                    .map(|inlay| inlay.id)
 4806                                    .collect::<Vec<InlayId>>(),
 4807                                Vec::new(),
 4808                                cx,
 4809                            );
 4810                            return;
 4811                        }
 4812                    }
 4813                    None => return,
 4814                }
 4815            }
 4816            InlayHintRefreshReason::Toggle(enabled) => {
 4817                if self.inlay_hint_cache.toggle(enabled) {
 4818                    if enabled {
 4819                        (InvalidationStrategy::RefreshRequested, None)
 4820                    } else {
 4821                        self.splice_inlays(
 4822                            &self
 4823                                .visible_inlay_hints(cx)
 4824                                .iter()
 4825                                .map(|inlay| inlay.id)
 4826                                .collect::<Vec<InlayId>>(),
 4827                            Vec::new(),
 4828                            cx,
 4829                        );
 4830                        return;
 4831                    }
 4832                } else {
 4833                    return;
 4834                }
 4835            }
 4836            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4837                match self.inlay_hint_cache.update_settings(
 4838                    &self.buffer,
 4839                    new_settings,
 4840                    self.visible_inlay_hints(cx),
 4841                    cx,
 4842                ) {
 4843                    ControlFlow::Break(Some(InlaySplice {
 4844                        to_remove,
 4845                        to_insert,
 4846                    })) => {
 4847                        self.splice_inlays(&to_remove, to_insert, cx);
 4848                        return;
 4849                    }
 4850                    ControlFlow::Break(None) => return,
 4851                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4852                }
 4853            }
 4854            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4855                if let Some(InlaySplice {
 4856                    to_remove,
 4857                    to_insert,
 4858                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4859                {
 4860                    self.splice_inlays(&to_remove, to_insert, cx);
 4861                }
 4862                self.display_map.update(cx, |display_map, _| {
 4863                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4864                });
 4865                return;
 4866            }
 4867            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4868            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4869                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4870            }
 4871            InlayHintRefreshReason::RefreshRequested => {
 4872                (InvalidationStrategy::RefreshRequested, None)
 4873            }
 4874        };
 4875
 4876        if let Some(InlaySplice {
 4877            to_remove,
 4878            to_insert,
 4879        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4880            reason_description,
 4881            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4882            invalidate_cache,
 4883            ignore_debounce,
 4884            cx,
 4885        ) {
 4886            self.splice_inlays(&to_remove, to_insert, cx);
 4887        }
 4888    }
 4889
 4890    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4891        self.display_map
 4892            .read(cx)
 4893            .current_inlays()
 4894            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4895            .cloned()
 4896            .collect()
 4897    }
 4898
 4899    pub fn excerpts_for_inlay_hints_query(
 4900        &self,
 4901        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4902        cx: &mut Context<Editor>,
 4903    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4904        let Some(project) = self.project.as_ref() else {
 4905            return HashMap::default();
 4906        };
 4907        let project = project.read(cx);
 4908        let multi_buffer = self.buffer().read(cx);
 4909        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4910        let multi_buffer_visible_start = self
 4911            .scroll_manager
 4912            .anchor()
 4913            .anchor
 4914            .to_point(&multi_buffer_snapshot);
 4915        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4916            multi_buffer_visible_start
 4917                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4918            Bias::Left,
 4919        );
 4920        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4921        multi_buffer_snapshot
 4922            .range_to_buffer_ranges(multi_buffer_visible_range)
 4923            .into_iter()
 4924            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4925            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4926                let buffer_file = project::File::from_dyn(buffer.file())?;
 4927                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4928                let worktree_entry = buffer_worktree
 4929                    .read(cx)
 4930                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4931                if worktree_entry.is_ignored {
 4932                    return None;
 4933                }
 4934
 4935                let language = buffer.language()?;
 4936                if let Some(restrict_to_languages) = restrict_to_languages {
 4937                    if !restrict_to_languages.contains(language) {
 4938                        return None;
 4939                    }
 4940                }
 4941                Some((
 4942                    excerpt_id,
 4943                    (
 4944                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4945                        buffer.version().clone(),
 4946                        excerpt_visible_range,
 4947                    ),
 4948                ))
 4949            })
 4950            .collect()
 4951    }
 4952
 4953    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4954        TextLayoutDetails {
 4955            text_system: window.text_system().clone(),
 4956            editor_style: self.style.clone().unwrap(),
 4957            rem_size: window.rem_size(),
 4958            scroll_anchor: self.scroll_manager.anchor(),
 4959            visible_rows: self.visible_line_count(),
 4960            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4961        }
 4962    }
 4963
 4964    pub fn splice_inlays(
 4965        &self,
 4966        to_remove: &[InlayId],
 4967        to_insert: Vec<Inlay>,
 4968        cx: &mut Context<Self>,
 4969    ) {
 4970        self.display_map.update(cx, |display_map, cx| {
 4971            display_map.splice_inlays(to_remove, to_insert, cx)
 4972        });
 4973        cx.notify();
 4974    }
 4975
 4976    fn trigger_on_type_formatting(
 4977        &self,
 4978        input: String,
 4979        window: &mut Window,
 4980        cx: &mut Context<Self>,
 4981    ) -> Option<Task<Result<()>>> {
 4982        if input.len() != 1 {
 4983            return None;
 4984        }
 4985
 4986        let project = self.project.as_ref()?;
 4987        let position = self.selections.newest_anchor().head();
 4988        let (buffer, buffer_position) = self
 4989            .buffer
 4990            .read(cx)
 4991            .text_anchor_for_position(position, cx)?;
 4992
 4993        let settings = language_settings::language_settings(
 4994            buffer
 4995                .read(cx)
 4996                .language_at(buffer_position)
 4997                .map(|l| l.name()),
 4998            buffer.read(cx).file(),
 4999            cx,
 5000        );
 5001        if !settings.use_on_type_format {
 5002            return None;
 5003        }
 5004
 5005        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5006        // hence we do LSP request & edit on host side only — add formats to host's history.
 5007        let push_to_lsp_host_history = true;
 5008        // If this is not the host, append its history with new edits.
 5009        let push_to_client_history = project.read(cx).is_via_collab();
 5010
 5011        let on_type_formatting = project.update(cx, |project, cx| {
 5012            project.on_type_format(
 5013                buffer.clone(),
 5014                buffer_position,
 5015                input,
 5016                push_to_lsp_host_history,
 5017                cx,
 5018            )
 5019        });
 5020        Some(cx.spawn_in(window, async move |editor, cx| {
 5021            if let Some(transaction) = on_type_formatting.await? {
 5022                if push_to_client_history {
 5023                    buffer
 5024                        .update(cx, |buffer, _| {
 5025                            buffer.push_transaction(transaction, Instant::now());
 5026                            buffer.finalize_last_transaction();
 5027                        })
 5028                        .ok();
 5029                }
 5030                editor.update(cx, |editor, cx| {
 5031                    editor.refresh_document_highlights(cx);
 5032                })?;
 5033            }
 5034            Ok(())
 5035        }))
 5036    }
 5037
 5038    pub fn show_word_completions(
 5039        &mut self,
 5040        _: &ShowWordCompletions,
 5041        window: &mut Window,
 5042        cx: &mut Context<Self>,
 5043    ) {
 5044        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5045    }
 5046
 5047    pub fn show_completions(
 5048        &mut self,
 5049        options: &ShowCompletions,
 5050        window: &mut Window,
 5051        cx: &mut Context<Self>,
 5052    ) {
 5053        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5054    }
 5055
 5056    fn open_or_update_completions_menu(
 5057        &mut self,
 5058        requested_source: Option<CompletionsMenuSource>,
 5059        trigger: Option<&str>,
 5060        window: &mut Window,
 5061        cx: &mut Context<Self>,
 5062    ) {
 5063        if self.pending_rename.is_some() {
 5064            return;
 5065        }
 5066
 5067        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5068        // inserted and selected. To handle that case, the start of the selection is used so that
 5069        // the menu starts with all choices.
 5070        let position = self.selections.newest_anchor().start;
 5071        if position.diff_base_anchor.is_some() {
 5072            return;
 5073        }
 5074        let (buffer, buffer_position) =
 5075            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5076                output
 5077            } else {
 5078                return;
 5079            };
 5080        let buffer_snapshot = buffer.read(cx).snapshot();
 5081
 5082        let query: Option<Arc<String>> =
 5083            Self::completion_query(&self.buffer.read(cx).read(cx), position)
 5084                .map(|query| query.into());
 5085
 5086        let provider = match requested_source {
 5087            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5088            Some(CompletionsMenuSource::Words) => None,
 5089            Some(CompletionsMenuSource::SnippetChoices) => {
 5090                log::error!("bug: SnippetChoices requested_source is not handled");
 5091                None
 5092            }
 5093        };
 5094
 5095        let sort_completions = provider
 5096            .as_ref()
 5097            .map_or(false, |provider| provider.sort_completions());
 5098
 5099        let filter_completions = provider
 5100            .as_ref()
 5101            .map_or(true, |provider| provider.filter_completions());
 5102
 5103        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5104        // current query is a suffix of the initial query.
 5105        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5106            if !menu.is_incomplete && filter_completions {
 5107                // If the new query is a suffix of the old query (typing more characters) and
 5108                // the previous result was complete, the existing completions can be filtered.
 5109                //
 5110                // Note that this is always true for snippet completions.
 5111                let query_matches = match (&menu.initial_query, &query) {
 5112                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5113                    (None, _) => true,
 5114                    _ => false,
 5115                };
 5116                if query_matches {
 5117                    let position_matches = if menu.initial_position == position {
 5118                        true
 5119                    } else {
 5120                        let snapshot = self.buffer.read(cx).read(cx);
 5121                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5122                    };
 5123                    if position_matches {
 5124                        menu.filter(query.clone(), provider.clone(), window, cx);
 5125                        return;
 5126                    }
 5127                }
 5128            }
 5129        };
 5130
 5131        let trigger_kind = match trigger {
 5132            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5133                CompletionTriggerKind::TRIGGER_CHARACTER
 5134            }
 5135            _ => CompletionTriggerKind::INVOKED,
 5136        };
 5137        let completion_context = CompletionContext {
 5138            trigger_character: trigger.and_then(|trigger| {
 5139                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5140                    Some(String::from(trigger))
 5141                } else {
 5142                    None
 5143                }
 5144            }),
 5145            trigger_kind,
 5146        };
 5147
 5148        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5149            buffer_snapshot.surrounding_word(buffer_position)
 5150        {
 5151            let word_to_exclude = buffer_snapshot
 5152                .text_for_range(word_range.clone())
 5153                .collect::<String>();
 5154            (
 5155                buffer_snapshot.anchor_before(word_range.start)
 5156                    ..buffer_snapshot.anchor_after(buffer_position),
 5157                Some(word_to_exclude),
 5158            )
 5159        } else {
 5160            (buffer_position..buffer_position, None)
 5161        };
 5162
 5163        let language = buffer_snapshot
 5164            .language_at(buffer_position)
 5165            .map(|language| language.name());
 5166
 5167        let completion_settings =
 5168            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5169
 5170        let show_completion_documentation = buffer_snapshot
 5171            .settings_at(buffer_position, cx)
 5172            .show_completion_documentation;
 5173
 5174        // The document can be large, so stay in reasonable bounds when searching for words,
 5175        // otherwise completion pop-up might be slow to appear.
 5176        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5177        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5178        let min_word_search = buffer_snapshot.clip_point(
 5179            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5180            Bias::Left,
 5181        );
 5182        let max_word_search = buffer_snapshot.clip_point(
 5183            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5184            Bias::Right,
 5185        );
 5186        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5187            ..buffer_snapshot.point_to_offset(max_word_search);
 5188
 5189        let skip_digits = query
 5190            .as_ref()
 5191            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5192
 5193        let (mut words, provider_responses) = match &provider {
 5194            Some(provider) => {
 5195                let provider_responses = provider.completions(
 5196                    position.excerpt_id,
 5197                    &buffer,
 5198                    buffer_position,
 5199                    completion_context,
 5200                    window,
 5201                    cx,
 5202                );
 5203
 5204                let words = match completion_settings.words {
 5205                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5206                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5207                        .background_spawn(async move {
 5208                            buffer_snapshot.words_in_range(WordsQuery {
 5209                                fuzzy_contents: None,
 5210                                range: word_search_range,
 5211                                skip_digits,
 5212                            })
 5213                        }),
 5214                };
 5215
 5216                (words, provider_responses)
 5217            }
 5218            None => (
 5219                cx.background_spawn(async move {
 5220                    buffer_snapshot.words_in_range(WordsQuery {
 5221                        fuzzy_contents: None,
 5222                        range: word_search_range,
 5223                        skip_digits,
 5224                    })
 5225                }),
 5226                Task::ready(Ok(Vec::new())),
 5227            ),
 5228        };
 5229
 5230        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5231
 5232        let id = post_inc(&mut self.next_completion_id);
 5233        let task = cx.spawn_in(window, async move |editor, cx| {
 5234            let Ok(()) = editor.update(cx, |this, _| {
 5235                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5236            }) else {
 5237                return;
 5238            };
 5239
 5240            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5241            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5242            let mut completions = Vec::new();
 5243            let mut is_incomplete = false;
 5244            if let Some(provider_responses) = provider_responses.await.log_err() {
 5245                if !provider_responses.is_empty() {
 5246                    for response in provider_responses {
 5247                        completions.extend(response.completions);
 5248                        is_incomplete = is_incomplete || response.is_incomplete;
 5249                    }
 5250                    if completion_settings.words == WordsCompletionMode::Fallback {
 5251                        words = Task::ready(BTreeMap::default());
 5252                    }
 5253                }
 5254            }
 5255
 5256            let mut words = words.await;
 5257            if let Some(word_to_exclude) = &word_to_exclude {
 5258                words.remove(word_to_exclude);
 5259            }
 5260            for lsp_completion in &completions {
 5261                words.remove(&lsp_completion.new_text);
 5262            }
 5263            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5264                replace_range: word_replace_range.clone(),
 5265                new_text: word.clone(),
 5266                label: CodeLabel::plain(word, None),
 5267                icon_path: None,
 5268                documentation: None,
 5269                source: CompletionSource::BufferWord {
 5270                    word_range,
 5271                    resolved: false,
 5272                },
 5273                insert_text_mode: Some(InsertTextMode::AS_IS),
 5274                confirm: None,
 5275            }));
 5276
 5277            let menu = if completions.is_empty() {
 5278                None
 5279            } else {
 5280                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5281                    let languages = editor
 5282                        .workspace
 5283                        .as_ref()
 5284                        .and_then(|(workspace, _)| workspace.upgrade())
 5285                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5286                    let menu = CompletionsMenu::new(
 5287                        id,
 5288                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5289                        sort_completions,
 5290                        show_completion_documentation,
 5291                        position,
 5292                        query.clone(),
 5293                        is_incomplete,
 5294                        buffer.clone(),
 5295                        completions.into(),
 5296                        snippet_sort_order,
 5297                        languages,
 5298                        language,
 5299                        cx,
 5300                    );
 5301
 5302                    let query = if filter_completions { query } else { None };
 5303                    let matches_task = if let Some(query) = query {
 5304                        menu.do_async_filtering(query, cx)
 5305                    } else {
 5306                        Task::ready(menu.unfiltered_matches())
 5307                    };
 5308                    (menu, matches_task)
 5309                }) else {
 5310                    return;
 5311                };
 5312
 5313                let matches = matches_task.await;
 5314
 5315                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5316                    // Newer menu already set, so exit.
 5317                    match editor.context_menu.borrow().as_ref() {
 5318                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5319                            if prev_menu.id > id {
 5320                                return;
 5321                            }
 5322                        }
 5323                        _ => {}
 5324                    };
 5325
 5326                    // Only valid to take prev_menu because it the new menu is immediately set
 5327                    // below, or the menu is hidden.
 5328                    match editor.context_menu.borrow_mut().take() {
 5329                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5330                            let position_matches =
 5331                                if prev_menu.initial_position == menu.initial_position {
 5332                                    true
 5333                                } else {
 5334                                    let snapshot = editor.buffer.read(cx).read(cx);
 5335                                    prev_menu.initial_position.to_offset(&snapshot)
 5336                                        == menu.initial_position.to_offset(&snapshot)
 5337                                };
 5338                            if position_matches {
 5339                                // Preserve markdown cache before `set_filter_results` because it will
 5340                                // try to populate the documentation cache.
 5341                                menu.preserve_markdown_cache(prev_menu);
 5342                            }
 5343                        }
 5344                        _ => {}
 5345                    };
 5346
 5347                    menu.set_filter_results(matches, provider, window, cx);
 5348                }) else {
 5349                    return;
 5350                };
 5351
 5352                menu.visible().then_some(menu)
 5353            };
 5354
 5355            editor
 5356                .update_in(cx, |editor, window, cx| {
 5357                    if editor.focus_handle.is_focused(window) {
 5358                        if let Some(menu) = menu {
 5359                            *editor.context_menu.borrow_mut() =
 5360                                Some(CodeContextMenu::Completions(menu));
 5361
 5362                            crate::hover_popover::hide_hover(editor, cx);
 5363                            if editor.show_edit_predictions_in_menu() {
 5364                                editor.update_visible_inline_completion(window, cx);
 5365                            } else {
 5366                                editor.discard_inline_completion(false, cx);
 5367                            }
 5368
 5369                            cx.notify();
 5370                            return;
 5371                        }
 5372                    }
 5373
 5374                    if editor.completion_tasks.len() <= 1 {
 5375                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5376                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5377                        // If it was already hidden and we don't show inline completions in the menu, we should
 5378                        // also show the inline-completion when available.
 5379                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5380                            editor.update_visible_inline_completion(window, cx);
 5381                        }
 5382                    }
 5383                })
 5384                .ok();
 5385        });
 5386
 5387        self.completion_tasks.push((id, task));
 5388    }
 5389
 5390    #[cfg(feature = "test-support")]
 5391    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5392        let menu = self.context_menu.borrow();
 5393        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5394            let completions = menu.completions.borrow();
 5395            Some(completions.to_vec())
 5396        } else {
 5397            None
 5398        }
 5399    }
 5400
 5401    pub fn with_completions_menu_matching_id<R>(
 5402        &self,
 5403        id: CompletionId,
 5404        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5405    ) -> R {
 5406        let mut context_menu = self.context_menu.borrow_mut();
 5407        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5408            return f(None);
 5409        };
 5410        if completions_menu.id != id {
 5411            return f(None);
 5412        }
 5413        f(Some(completions_menu))
 5414    }
 5415
 5416    pub fn confirm_completion(
 5417        &mut self,
 5418        action: &ConfirmCompletion,
 5419        window: &mut Window,
 5420        cx: &mut Context<Self>,
 5421    ) -> Option<Task<Result<()>>> {
 5422        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5423        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5424    }
 5425
 5426    pub fn confirm_completion_insert(
 5427        &mut self,
 5428        _: &ConfirmCompletionInsert,
 5429        window: &mut Window,
 5430        cx: &mut Context<Self>,
 5431    ) -> Option<Task<Result<()>>> {
 5432        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5433        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5434    }
 5435
 5436    pub fn confirm_completion_replace(
 5437        &mut self,
 5438        _: &ConfirmCompletionReplace,
 5439        window: &mut Window,
 5440        cx: &mut Context<Self>,
 5441    ) -> Option<Task<Result<()>>> {
 5442        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5443        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5444    }
 5445
 5446    pub fn compose_completion(
 5447        &mut self,
 5448        action: &ComposeCompletion,
 5449        window: &mut Window,
 5450        cx: &mut Context<Self>,
 5451    ) -> Option<Task<Result<()>>> {
 5452        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5453        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5454    }
 5455
 5456    fn do_completion(
 5457        &mut self,
 5458        item_ix: Option<usize>,
 5459        intent: CompletionIntent,
 5460        window: &mut Window,
 5461        cx: &mut Context<Editor>,
 5462    ) -> Option<Task<Result<()>>> {
 5463        use language::ToOffset as _;
 5464
 5465        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5466        else {
 5467            return None;
 5468        };
 5469
 5470        let candidate_id = {
 5471            let entries = completions_menu.entries.borrow();
 5472            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5473            if self.show_edit_predictions_in_menu() {
 5474                self.discard_inline_completion(true, cx);
 5475            }
 5476            mat.candidate_id
 5477        };
 5478
 5479        let completion = completions_menu
 5480            .completions
 5481            .borrow()
 5482            .get(candidate_id)?
 5483            .clone();
 5484        cx.stop_propagation();
 5485
 5486        let buffer_handle = completions_menu.buffer.clone();
 5487
 5488        let CompletionEdit {
 5489            new_text,
 5490            snippet,
 5491            replace_range,
 5492        } = process_completion_for_edit(
 5493            &completion,
 5494            intent,
 5495            &buffer_handle,
 5496            &completions_menu.initial_position.text_anchor,
 5497            cx,
 5498        );
 5499
 5500        let buffer = buffer_handle.read(cx);
 5501        let snapshot = self.buffer.read(cx).snapshot(cx);
 5502        let newest_anchor = self.selections.newest_anchor();
 5503        let replace_range_multibuffer = {
 5504            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5505            let multibuffer_anchor = snapshot
 5506                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5507                .unwrap()
 5508                ..snapshot
 5509                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5510                    .unwrap();
 5511            multibuffer_anchor.start.to_offset(&snapshot)
 5512                ..multibuffer_anchor.end.to_offset(&snapshot)
 5513        };
 5514        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5515            return None;
 5516        }
 5517
 5518        let old_text = buffer
 5519            .text_for_range(replace_range.clone())
 5520            .collect::<String>();
 5521        let lookbehind = newest_anchor
 5522            .start
 5523            .text_anchor
 5524            .to_offset(buffer)
 5525            .saturating_sub(replace_range.start);
 5526        let lookahead = replace_range
 5527            .end
 5528            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5529        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5530        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5531
 5532        let selections = self.selections.all::<usize>(cx);
 5533        let mut ranges = Vec::new();
 5534        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5535
 5536        for selection in &selections {
 5537            let range = if selection.id == newest_anchor.id {
 5538                replace_range_multibuffer.clone()
 5539            } else {
 5540                let mut range = selection.range();
 5541
 5542                // if prefix is present, don't duplicate it
 5543                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5544                    range.start = range.start.saturating_sub(lookbehind);
 5545
 5546                    // if suffix is also present, mimic the newest cursor and replace it
 5547                    if selection.id != newest_anchor.id
 5548                        && snapshot.contains_str_at(range.end, suffix)
 5549                    {
 5550                        range.end += lookahead;
 5551                    }
 5552                }
 5553                range
 5554            };
 5555
 5556            ranges.push(range.clone());
 5557
 5558            if !self.linked_edit_ranges.is_empty() {
 5559                let start_anchor = snapshot.anchor_before(range.start);
 5560                let end_anchor = snapshot.anchor_after(range.end);
 5561                if let Some(ranges) = self
 5562                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5563                {
 5564                    for (buffer, edits) in ranges {
 5565                        linked_edits
 5566                            .entry(buffer.clone())
 5567                            .or_default()
 5568                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5569                    }
 5570                }
 5571            }
 5572        }
 5573
 5574        let common_prefix_len = old_text
 5575            .chars()
 5576            .zip(new_text.chars())
 5577            .take_while(|(a, b)| a == b)
 5578            .map(|(a, _)| a.len_utf8())
 5579            .sum::<usize>();
 5580
 5581        cx.emit(EditorEvent::InputHandled {
 5582            utf16_range_to_replace: None,
 5583            text: new_text[common_prefix_len..].into(),
 5584        });
 5585
 5586        self.transact(window, cx, |this, window, cx| {
 5587            if let Some(mut snippet) = snippet {
 5588                snippet.text = new_text.to_string();
 5589                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5590            } else {
 5591                this.buffer.update(cx, |buffer, cx| {
 5592                    let auto_indent = match completion.insert_text_mode {
 5593                        Some(InsertTextMode::AS_IS) => None,
 5594                        _ => this.autoindent_mode.clone(),
 5595                    };
 5596                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5597                    buffer.edit(edits, auto_indent, cx);
 5598                });
 5599            }
 5600            for (buffer, edits) in linked_edits {
 5601                buffer.update(cx, |buffer, cx| {
 5602                    let snapshot = buffer.snapshot();
 5603                    let edits = edits
 5604                        .into_iter()
 5605                        .map(|(range, text)| {
 5606                            use text::ToPoint as TP;
 5607                            let end_point = TP::to_point(&range.end, &snapshot);
 5608                            let start_point = TP::to_point(&range.start, &snapshot);
 5609                            (start_point..end_point, text)
 5610                        })
 5611                        .sorted_by_key(|(range, _)| range.start);
 5612                    buffer.edit(edits, None, cx);
 5613                })
 5614            }
 5615
 5616            this.refresh_inline_completion(true, false, window, cx);
 5617        });
 5618
 5619        let show_new_completions_on_confirm = completion
 5620            .confirm
 5621            .as_ref()
 5622            .map_or(false, |confirm| confirm(intent, window, cx));
 5623        if show_new_completions_on_confirm {
 5624            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5625        }
 5626
 5627        let provider = self.completion_provider.as_ref()?;
 5628        drop(completion);
 5629        let apply_edits = provider.apply_additional_edits_for_completion(
 5630            buffer_handle,
 5631            completions_menu.completions.clone(),
 5632            candidate_id,
 5633            true,
 5634            cx,
 5635        );
 5636
 5637        let editor_settings = EditorSettings::get_global(cx);
 5638        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5639            // After the code completion is finished, users often want to know what signatures are needed.
 5640            // so we should automatically call signature_help
 5641            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5642        }
 5643
 5644        Some(cx.foreground_executor().spawn(async move {
 5645            apply_edits.await?;
 5646            Ok(())
 5647        }))
 5648    }
 5649
 5650    pub fn toggle_code_actions(
 5651        &mut self,
 5652        action: &ToggleCodeActions,
 5653        window: &mut Window,
 5654        cx: &mut Context<Self>,
 5655    ) {
 5656        let quick_launch = action.quick_launch;
 5657        let mut context_menu = self.context_menu.borrow_mut();
 5658        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5659            if code_actions.deployed_from == action.deployed_from {
 5660                // Toggle if we're selecting the same one
 5661                *context_menu = None;
 5662                cx.notify();
 5663                return;
 5664            } else {
 5665                // Otherwise, clear it and start a new one
 5666                *context_menu = None;
 5667                cx.notify();
 5668            }
 5669        }
 5670        drop(context_menu);
 5671        let snapshot = self.snapshot(window, cx);
 5672        let deployed_from = action.deployed_from.clone();
 5673        let mut task = self.code_actions_task.take();
 5674        let action = action.clone();
 5675        cx.spawn_in(window, async move |editor, cx| {
 5676            while let Some(prev_task) = task {
 5677                prev_task.await.log_err();
 5678                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5679            }
 5680
 5681            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5682                if editor.focus_handle.is_focused(window) {
 5683                    let multibuffer_point = match &action.deployed_from {
 5684                        Some(CodeActionSource::Indicator(row)) => {
 5685                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5686                        }
 5687                        _ => editor.selections.newest::<Point>(cx).head(),
 5688                    };
 5689                    let (buffer, buffer_row) = snapshot
 5690                        .buffer_snapshot
 5691                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5692                        .and_then(|(buffer_snapshot, range)| {
 5693                            editor
 5694                                .buffer
 5695                                .read(cx)
 5696                                .buffer(buffer_snapshot.remote_id())
 5697                                .map(|buffer| (buffer, range.start.row))
 5698                        })?;
 5699                    let (_, code_actions) = editor
 5700                        .available_code_actions
 5701                        .clone()
 5702                        .and_then(|(location, code_actions)| {
 5703                            let snapshot = location.buffer.read(cx).snapshot();
 5704                            let point_range = location.range.to_point(&snapshot);
 5705                            let point_range = point_range.start.row..=point_range.end.row;
 5706                            if point_range.contains(&buffer_row) {
 5707                                Some((location, code_actions))
 5708                            } else {
 5709                                None
 5710                            }
 5711                        })
 5712                        .unzip();
 5713                    let buffer_id = buffer.read(cx).remote_id();
 5714                    let tasks = editor
 5715                        .tasks
 5716                        .get(&(buffer_id, buffer_row))
 5717                        .map(|t| Arc::new(t.to_owned()));
 5718                    if tasks.is_none() && code_actions.is_none() {
 5719                        return None;
 5720                    }
 5721
 5722                    editor.completion_tasks.clear();
 5723                    editor.discard_inline_completion(false, cx);
 5724                    let task_context =
 5725                        tasks
 5726                            .as_ref()
 5727                            .zip(editor.project.clone())
 5728                            .map(|(tasks, project)| {
 5729                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5730                            });
 5731
 5732                    Some(cx.spawn_in(window, async move |editor, cx| {
 5733                        let task_context = match task_context {
 5734                            Some(task_context) => task_context.await,
 5735                            None => None,
 5736                        };
 5737                        let resolved_tasks =
 5738                            tasks
 5739                                .zip(task_context.clone())
 5740                                .map(|(tasks, task_context)| ResolvedTasks {
 5741                                    templates: tasks.resolve(&task_context).collect(),
 5742                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5743                                        multibuffer_point.row,
 5744                                        tasks.column,
 5745                                    )),
 5746                                });
 5747                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5748                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5749                                maybe!({
 5750                                    let project = editor.project.as_ref()?;
 5751                                    let dap_store = project.read(cx).dap_store();
 5752                                    let mut scenarios = vec![];
 5753                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5754                                    let buffer = buffer.read(cx);
 5755                                    let language = buffer.language()?;
 5756                                    let file = buffer.file();
 5757                                    let debug_adapter =
 5758                                        language_settings(language.name().into(), file, cx)
 5759                                            .debuggers
 5760                                            .first()
 5761                                            .map(SharedString::from)
 5762                                            .or_else(|| {
 5763                                                language
 5764                                                    .config()
 5765                                                    .debuggers
 5766                                                    .first()
 5767                                                    .map(SharedString::from)
 5768                                            })?;
 5769
 5770                                    dap_store.update(cx, |dap_store, cx| {
 5771                                        for (_, task) in &resolved_tasks.templates {
 5772                                            if let Some(scenario) = dap_store
 5773                                                .debug_scenario_for_build_task(
 5774                                                    task.original_task().clone(),
 5775                                                    debug_adapter.clone().into(),
 5776                                                    task.display_label().to_owned().into(),
 5777                                                    cx,
 5778                                                )
 5779                                            {
 5780                                                scenarios.push(scenario);
 5781                                            }
 5782                                        }
 5783                                    });
 5784                                    Some(scenarios)
 5785                                })
 5786                                .unwrap_or_default()
 5787                            } else {
 5788                                vec![]
 5789                            }
 5790                        })?;
 5791                        let spawn_straight_away = quick_launch
 5792                            && resolved_tasks
 5793                                .as_ref()
 5794                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5795                            && code_actions
 5796                                .as_ref()
 5797                                .map_or(true, |actions| actions.is_empty())
 5798                            && debug_scenarios.is_empty();
 5799                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5800                            crate::hover_popover::hide_hover(editor, cx);
 5801                            *editor.context_menu.borrow_mut() =
 5802                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5803                                    buffer,
 5804                                    actions: CodeActionContents::new(
 5805                                        resolved_tasks,
 5806                                        code_actions,
 5807                                        debug_scenarios,
 5808                                        task_context.unwrap_or_default(),
 5809                                    ),
 5810                                    selected_item: Default::default(),
 5811                                    scroll_handle: UniformListScrollHandle::default(),
 5812                                    deployed_from,
 5813                                }));
 5814                            if spawn_straight_away {
 5815                                if let Some(task) = editor.confirm_code_action(
 5816                                    &ConfirmCodeAction { item_ix: Some(0) },
 5817                                    window,
 5818                                    cx,
 5819                                ) {
 5820                                    cx.notify();
 5821                                    return task;
 5822                                }
 5823                            }
 5824                            cx.notify();
 5825                            Task::ready(Ok(()))
 5826                        }) {
 5827                            task.await
 5828                        } else {
 5829                            Ok(())
 5830                        }
 5831                    }))
 5832                } else {
 5833                    Some(Task::ready(Ok(())))
 5834                }
 5835            })?;
 5836            if let Some(task) = spawned_test_task {
 5837                task.await?;
 5838            }
 5839
 5840            anyhow::Ok(())
 5841        })
 5842        .detach_and_log_err(cx);
 5843    }
 5844
 5845    pub fn confirm_code_action(
 5846        &mut self,
 5847        action: &ConfirmCodeAction,
 5848        window: &mut Window,
 5849        cx: &mut Context<Self>,
 5850    ) -> Option<Task<Result<()>>> {
 5851        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5852
 5853        let actions_menu =
 5854            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5855                menu
 5856            } else {
 5857                return None;
 5858            };
 5859
 5860        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5861        let action = actions_menu.actions.get(action_ix)?;
 5862        let title = action.label();
 5863        let buffer = actions_menu.buffer;
 5864        let workspace = self.workspace()?;
 5865
 5866        match action {
 5867            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5868                workspace.update(cx, |workspace, cx| {
 5869                    workspace.schedule_resolved_task(
 5870                        task_source_kind,
 5871                        resolved_task,
 5872                        false,
 5873                        window,
 5874                        cx,
 5875                    );
 5876
 5877                    Some(Task::ready(Ok(())))
 5878                })
 5879            }
 5880            CodeActionsItem::CodeAction {
 5881                excerpt_id,
 5882                action,
 5883                provider,
 5884            } => {
 5885                let apply_code_action =
 5886                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5887                let workspace = workspace.downgrade();
 5888                Some(cx.spawn_in(window, async move |editor, cx| {
 5889                    let project_transaction = apply_code_action.await?;
 5890                    Self::open_project_transaction(
 5891                        &editor,
 5892                        workspace,
 5893                        project_transaction,
 5894                        title,
 5895                        cx,
 5896                    )
 5897                    .await
 5898                }))
 5899            }
 5900            CodeActionsItem::DebugScenario(scenario) => {
 5901                let context = actions_menu.actions.context.clone();
 5902
 5903                workspace.update(cx, |workspace, cx| {
 5904                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5905                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5906                });
 5907                Some(Task::ready(Ok(())))
 5908            }
 5909        }
 5910    }
 5911
 5912    pub async fn open_project_transaction(
 5913        this: &WeakEntity<Editor>,
 5914        workspace: WeakEntity<Workspace>,
 5915        transaction: ProjectTransaction,
 5916        title: String,
 5917        cx: &mut AsyncWindowContext,
 5918    ) -> Result<()> {
 5919        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5920        cx.update(|_, cx| {
 5921            entries.sort_unstable_by_key(|(buffer, _)| {
 5922                buffer.read(cx).file().map(|f| f.path().clone())
 5923            });
 5924        })?;
 5925
 5926        // If the project transaction's edits are all contained within this editor, then
 5927        // avoid opening a new editor to display them.
 5928
 5929        if let Some((buffer, transaction)) = entries.first() {
 5930            if entries.len() == 1 {
 5931                let excerpt = this.update(cx, |editor, cx| {
 5932                    editor
 5933                        .buffer()
 5934                        .read(cx)
 5935                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5936                })?;
 5937                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5938                    if excerpted_buffer == *buffer {
 5939                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5940                            let excerpt_range = excerpt_range.to_offset(buffer);
 5941                            buffer
 5942                                .edited_ranges_for_transaction::<usize>(transaction)
 5943                                .all(|range| {
 5944                                    excerpt_range.start <= range.start
 5945                                        && excerpt_range.end >= range.end
 5946                                })
 5947                        })?;
 5948
 5949                        if all_edits_within_excerpt {
 5950                            return Ok(());
 5951                        }
 5952                    }
 5953                }
 5954            }
 5955        } else {
 5956            return Ok(());
 5957        }
 5958
 5959        let mut ranges_to_highlight = Vec::new();
 5960        let excerpt_buffer = cx.new(|cx| {
 5961            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5962            for (buffer_handle, transaction) in &entries {
 5963                let edited_ranges = buffer_handle
 5964                    .read(cx)
 5965                    .edited_ranges_for_transaction::<Point>(transaction)
 5966                    .collect::<Vec<_>>();
 5967                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5968                    PathKey::for_buffer(buffer_handle, cx),
 5969                    buffer_handle.clone(),
 5970                    edited_ranges,
 5971                    DEFAULT_MULTIBUFFER_CONTEXT,
 5972                    cx,
 5973                );
 5974
 5975                ranges_to_highlight.extend(ranges);
 5976            }
 5977            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5978            multibuffer
 5979        })?;
 5980
 5981        workspace.update_in(cx, |workspace, window, cx| {
 5982            let project = workspace.project().clone();
 5983            let editor =
 5984                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5985            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5986            editor.update(cx, |editor, cx| {
 5987                editor.highlight_background::<Self>(
 5988                    &ranges_to_highlight,
 5989                    |theme| theme.editor_highlighted_line_background,
 5990                    cx,
 5991                );
 5992            });
 5993        })?;
 5994
 5995        Ok(())
 5996    }
 5997
 5998    pub fn clear_code_action_providers(&mut self) {
 5999        self.code_action_providers.clear();
 6000        self.available_code_actions.take();
 6001    }
 6002
 6003    pub fn add_code_action_provider(
 6004        &mut self,
 6005        provider: Rc<dyn CodeActionProvider>,
 6006        window: &mut Window,
 6007        cx: &mut Context<Self>,
 6008    ) {
 6009        if self
 6010            .code_action_providers
 6011            .iter()
 6012            .any(|existing_provider| existing_provider.id() == provider.id())
 6013        {
 6014            return;
 6015        }
 6016
 6017        self.code_action_providers.push(provider);
 6018        self.refresh_code_actions(window, cx);
 6019    }
 6020
 6021    pub fn remove_code_action_provider(
 6022        &mut self,
 6023        id: Arc<str>,
 6024        window: &mut Window,
 6025        cx: &mut Context<Self>,
 6026    ) {
 6027        self.code_action_providers
 6028            .retain(|provider| provider.id() != id);
 6029        self.refresh_code_actions(window, cx);
 6030    }
 6031
 6032    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6033        !self.code_action_providers.is_empty()
 6034            && EditorSettings::get_global(cx).toolbar.code_actions
 6035    }
 6036
 6037    pub fn has_available_code_actions(&self) -> bool {
 6038        self.available_code_actions
 6039            .as_ref()
 6040            .is_some_and(|(_, actions)| !actions.is_empty())
 6041    }
 6042
 6043    fn render_inline_code_actions(
 6044        &self,
 6045        icon_size: ui::IconSize,
 6046        display_row: DisplayRow,
 6047        is_active: bool,
 6048        cx: &mut Context<Self>,
 6049    ) -> AnyElement {
 6050        let show_tooltip = !self.context_menu_visible();
 6051        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6052            .icon_size(icon_size)
 6053            .shape(ui::IconButtonShape::Square)
 6054            .style(ButtonStyle::Transparent)
 6055            .icon_color(ui::Color::Hidden)
 6056            .toggle_state(is_active)
 6057            .when(show_tooltip, |this| {
 6058                this.tooltip({
 6059                    let focus_handle = self.focus_handle.clone();
 6060                    move |window, cx| {
 6061                        Tooltip::for_action_in(
 6062                            "Toggle Code Actions",
 6063                            &ToggleCodeActions {
 6064                                deployed_from: None,
 6065                                quick_launch: false,
 6066                            },
 6067                            &focus_handle,
 6068                            window,
 6069                            cx,
 6070                        )
 6071                    }
 6072                })
 6073            })
 6074            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6075                window.focus(&editor.focus_handle(cx));
 6076                editor.toggle_code_actions(
 6077                    &crate::actions::ToggleCodeActions {
 6078                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6079                            display_row,
 6080                        )),
 6081                        quick_launch: false,
 6082                    },
 6083                    window,
 6084                    cx,
 6085                );
 6086            }))
 6087            .into_any_element()
 6088    }
 6089
 6090    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6091        &self.context_menu
 6092    }
 6093
 6094    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6095        let newest_selection = self.selections.newest_anchor().clone();
 6096        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6097        let buffer = self.buffer.read(cx);
 6098        if newest_selection.head().diff_base_anchor.is_some() {
 6099            return None;
 6100        }
 6101        let (start_buffer, start) =
 6102            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6103        let (end_buffer, end) =
 6104            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6105        if start_buffer != end_buffer {
 6106            return None;
 6107        }
 6108
 6109        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6110            cx.background_executor()
 6111                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6112                .await;
 6113
 6114            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6115                let providers = this.code_action_providers.clone();
 6116                let tasks = this
 6117                    .code_action_providers
 6118                    .iter()
 6119                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6120                    .collect::<Vec<_>>();
 6121                (providers, tasks)
 6122            })?;
 6123
 6124            let mut actions = Vec::new();
 6125            for (provider, provider_actions) in
 6126                providers.into_iter().zip(future::join_all(tasks).await)
 6127            {
 6128                if let Some(provider_actions) = provider_actions.log_err() {
 6129                    actions.extend(provider_actions.into_iter().map(|action| {
 6130                        AvailableCodeAction {
 6131                            excerpt_id: newest_selection.start.excerpt_id,
 6132                            action,
 6133                            provider: provider.clone(),
 6134                        }
 6135                    }));
 6136                }
 6137            }
 6138
 6139            this.update(cx, |this, cx| {
 6140                this.available_code_actions = if actions.is_empty() {
 6141                    None
 6142                } else {
 6143                    Some((
 6144                        Location {
 6145                            buffer: start_buffer,
 6146                            range: start..end,
 6147                        },
 6148                        actions.into(),
 6149                    ))
 6150                };
 6151                cx.notify();
 6152            })
 6153        }));
 6154        None
 6155    }
 6156
 6157    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6158        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6159            self.show_git_blame_inline = false;
 6160
 6161            self.show_git_blame_inline_delay_task =
 6162                Some(cx.spawn_in(window, async move |this, cx| {
 6163                    cx.background_executor().timer(delay).await;
 6164
 6165                    this.update(cx, |this, cx| {
 6166                        this.show_git_blame_inline = true;
 6167                        cx.notify();
 6168                    })
 6169                    .log_err();
 6170                }));
 6171        }
 6172    }
 6173
 6174    fn show_blame_popover(
 6175        &mut self,
 6176        blame_entry: &BlameEntry,
 6177        position: gpui::Point<Pixels>,
 6178        cx: &mut Context<Self>,
 6179    ) {
 6180        if let Some(state) = &mut self.inline_blame_popover {
 6181            state.hide_task.take();
 6182            cx.notify();
 6183        } else {
 6184            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6185            let show_task = cx.spawn(async move |editor, cx| {
 6186                cx.background_executor()
 6187                    .timer(std::time::Duration::from_millis(delay))
 6188                    .await;
 6189                editor
 6190                    .update(cx, |editor, cx| {
 6191                        if let Some(state) = &mut editor.inline_blame_popover {
 6192                            state.show_task = None;
 6193                            cx.notify();
 6194                        }
 6195                    })
 6196                    .ok();
 6197            });
 6198            let Some(blame) = self.blame.as_ref() else {
 6199                return;
 6200            };
 6201            let blame = blame.read(cx);
 6202            let details = blame.details_for_entry(&blame_entry);
 6203            let markdown = cx.new(|cx| {
 6204                Markdown::new(
 6205                    details
 6206                        .as_ref()
 6207                        .map(|message| message.message.clone())
 6208                        .unwrap_or_default(),
 6209                    None,
 6210                    None,
 6211                    cx,
 6212                )
 6213            });
 6214            self.inline_blame_popover = Some(InlineBlamePopover {
 6215                position,
 6216                show_task: Some(show_task),
 6217                hide_task: None,
 6218                popover_bounds: None,
 6219                popover_state: InlineBlamePopoverState {
 6220                    scroll_handle: ScrollHandle::new(),
 6221                    commit_message: details,
 6222                    markdown,
 6223                },
 6224            });
 6225        }
 6226    }
 6227
 6228    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6229        if let Some(state) = &mut self.inline_blame_popover {
 6230            if state.show_task.is_some() {
 6231                self.inline_blame_popover.take();
 6232                cx.notify();
 6233            } else {
 6234                let hide_task = cx.spawn(async move |editor, cx| {
 6235                    cx.background_executor()
 6236                        .timer(std::time::Duration::from_millis(100))
 6237                        .await;
 6238                    editor
 6239                        .update(cx, |editor, cx| {
 6240                            editor.inline_blame_popover.take();
 6241                            cx.notify();
 6242                        })
 6243                        .ok();
 6244                });
 6245                state.hide_task = Some(hide_task);
 6246            }
 6247        }
 6248    }
 6249
 6250    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6251        if self.pending_rename.is_some() {
 6252            return None;
 6253        }
 6254
 6255        let provider = self.semantics_provider.clone()?;
 6256        let buffer = self.buffer.read(cx);
 6257        let newest_selection = self.selections.newest_anchor().clone();
 6258        let cursor_position = newest_selection.head();
 6259        let (cursor_buffer, cursor_buffer_position) =
 6260            buffer.text_anchor_for_position(cursor_position, cx)?;
 6261        let (tail_buffer, tail_buffer_position) =
 6262            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6263        if cursor_buffer != tail_buffer {
 6264            return None;
 6265        }
 6266
 6267        let snapshot = cursor_buffer.read(cx).snapshot();
 6268        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6269        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6270        if start_word_range != end_word_range {
 6271            self.document_highlights_task.take();
 6272            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6273            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6274            return None;
 6275        }
 6276
 6277        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6278        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6279            cx.background_executor()
 6280                .timer(Duration::from_millis(debounce))
 6281                .await;
 6282
 6283            let highlights = if let Some(highlights) = cx
 6284                .update(|cx| {
 6285                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6286                })
 6287                .ok()
 6288                .flatten()
 6289            {
 6290                highlights.await.log_err()
 6291            } else {
 6292                None
 6293            };
 6294
 6295            if let Some(highlights) = highlights {
 6296                this.update(cx, |this, cx| {
 6297                    if this.pending_rename.is_some() {
 6298                        return;
 6299                    }
 6300
 6301                    let buffer_id = cursor_position.buffer_id;
 6302                    let buffer = this.buffer.read(cx);
 6303                    if !buffer
 6304                        .text_anchor_for_position(cursor_position, cx)
 6305                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6306                    {
 6307                        return;
 6308                    }
 6309
 6310                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6311                    let mut write_ranges = Vec::new();
 6312                    let mut read_ranges = Vec::new();
 6313                    for highlight in highlights {
 6314                        for (excerpt_id, excerpt_range) in
 6315                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6316                        {
 6317                            let start = highlight
 6318                                .range
 6319                                .start
 6320                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6321                            let end = highlight
 6322                                .range
 6323                                .end
 6324                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6325                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6326                                continue;
 6327                            }
 6328
 6329                            let range = Anchor {
 6330                                buffer_id,
 6331                                excerpt_id,
 6332                                text_anchor: start,
 6333                                diff_base_anchor: None,
 6334                            }..Anchor {
 6335                                buffer_id,
 6336                                excerpt_id,
 6337                                text_anchor: end,
 6338                                diff_base_anchor: None,
 6339                            };
 6340                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6341                                write_ranges.push(range);
 6342                            } else {
 6343                                read_ranges.push(range);
 6344                            }
 6345                        }
 6346                    }
 6347
 6348                    this.highlight_background::<DocumentHighlightRead>(
 6349                        &read_ranges,
 6350                        |theme| theme.editor_document_highlight_read_background,
 6351                        cx,
 6352                    );
 6353                    this.highlight_background::<DocumentHighlightWrite>(
 6354                        &write_ranges,
 6355                        |theme| theme.editor_document_highlight_write_background,
 6356                        cx,
 6357                    );
 6358                    cx.notify();
 6359                })
 6360                .log_err();
 6361            }
 6362        }));
 6363        None
 6364    }
 6365
 6366    fn prepare_highlight_query_from_selection(
 6367        &mut self,
 6368        cx: &mut Context<Editor>,
 6369    ) -> Option<(String, Range<Anchor>)> {
 6370        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6371            return None;
 6372        }
 6373        if !EditorSettings::get_global(cx).selection_highlight {
 6374            return None;
 6375        }
 6376        if self.selections.count() != 1 || self.selections.line_mode {
 6377            return None;
 6378        }
 6379        let selection = self.selections.newest::<Point>(cx);
 6380        if selection.is_empty() || selection.start.row != selection.end.row {
 6381            return None;
 6382        }
 6383        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6384        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6385        let query = multi_buffer_snapshot
 6386            .text_for_range(selection_anchor_range.clone())
 6387            .collect::<String>();
 6388        if query.trim().is_empty() {
 6389            return None;
 6390        }
 6391        Some((query, selection_anchor_range))
 6392    }
 6393
 6394    fn update_selection_occurrence_highlights(
 6395        &mut self,
 6396        query_text: String,
 6397        query_range: Range<Anchor>,
 6398        multi_buffer_range_to_query: Range<Point>,
 6399        use_debounce: bool,
 6400        window: &mut Window,
 6401        cx: &mut Context<Editor>,
 6402    ) -> Task<()> {
 6403        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6404        cx.spawn_in(window, async move |editor, cx| {
 6405            if use_debounce {
 6406                cx.background_executor()
 6407                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6408                    .await;
 6409            }
 6410            let match_task = cx.background_spawn(async move {
 6411                let buffer_ranges = multi_buffer_snapshot
 6412                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6413                    .into_iter()
 6414                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6415                let mut match_ranges = Vec::new();
 6416                let Ok(regex) = project::search::SearchQuery::text(
 6417                    query_text.clone(),
 6418                    false,
 6419                    false,
 6420                    false,
 6421                    Default::default(),
 6422                    Default::default(),
 6423                    false,
 6424                    None,
 6425                ) else {
 6426                    return Vec::default();
 6427                };
 6428                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6429                    match_ranges.extend(
 6430                        regex
 6431                            .search(&buffer_snapshot, Some(search_range.clone()))
 6432                            .await
 6433                            .into_iter()
 6434                            .filter_map(|match_range| {
 6435                                let match_start = buffer_snapshot
 6436                                    .anchor_after(search_range.start + match_range.start);
 6437                                let match_end = buffer_snapshot
 6438                                    .anchor_before(search_range.start + match_range.end);
 6439                                let match_anchor_range = Anchor::range_in_buffer(
 6440                                    excerpt_id,
 6441                                    buffer_snapshot.remote_id(),
 6442                                    match_start..match_end,
 6443                                );
 6444                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6445                            }),
 6446                    );
 6447                }
 6448                match_ranges
 6449            });
 6450            let match_ranges = match_task.await;
 6451            editor
 6452                .update_in(cx, |editor, _, cx| {
 6453                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6454                    if !match_ranges.is_empty() {
 6455                        editor.highlight_background::<SelectedTextHighlight>(
 6456                            &match_ranges,
 6457                            |theme| theme.editor_document_highlight_bracket_background,
 6458                            cx,
 6459                        )
 6460                    }
 6461                })
 6462                .log_err();
 6463        })
 6464    }
 6465
 6466    fn refresh_selected_text_highlights(
 6467        &mut self,
 6468        on_buffer_edit: bool,
 6469        window: &mut Window,
 6470        cx: &mut Context<Editor>,
 6471    ) {
 6472        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6473        else {
 6474            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6475            self.quick_selection_highlight_task.take();
 6476            self.debounced_selection_highlight_task.take();
 6477            return;
 6478        };
 6479        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6480        if on_buffer_edit
 6481            || self
 6482                .quick_selection_highlight_task
 6483                .as_ref()
 6484                .map_or(true, |(prev_anchor_range, _)| {
 6485                    prev_anchor_range != &query_range
 6486                })
 6487        {
 6488            let multi_buffer_visible_start = self
 6489                .scroll_manager
 6490                .anchor()
 6491                .anchor
 6492                .to_point(&multi_buffer_snapshot);
 6493            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6494                multi_buffer_visible_start
 6495                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6496                Bias::Left,
 6497            );
 6498            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6499            self.quick_selection_highlight_task = Some((
 6500                query_range.clone(),
 6501                self.update_selection_occurrence_highlights(
 6502                    query_text.clone(),
 6503                    query_range.clone(),
 6504                    multi_buffer_visible_range,
 6505                    false,
 6506                    window,
 6507                    cx,
 6508                ),
 6509            ));
 6510        }
 6511        if on_buffer_edit
 6512            || self
 6513                .debounced_selection_highlight_task
 6514                .as_ref()
 6515                .map_or(true, |(prev_anchor_range, _)| {
 6516                    prev_anchor_range != &query_range
 6517                })
 6518        {
 6519            let multi_buffer_start = multi_buffer_snapshot
 6520                .anchor_before(0)
 6521                .to_point(&multi_buffer_snapshot);
 6522            let multi_buffer_end = multi_buffer_snapshot
 6523                .anchor_after(multi_buffer_snapshot.len())
 6524                .to_point(&multi_buffer_snapshot);
 6525            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6526            self.debounced_selection_highlight_task = Some((
 6527                query_range.clone(),
 6528                self.update_selection_occurrence_highlights(
 6529                    query_text,
 6530                    query_range,
 6531                    multi_buffer_full_range,
 6532                    true,
 6533                    window,
 6534                    cx,
 6535                ),
 6536            ));
 6537        }
 6538    }
 6539
 6540    pub fn refresh_inline_completion(
 6541        &mut self,
 6542        debounce: bool,
 6543        user_requested: bool,
 6544        window: &mut Window,
 6545        cx: &mut Context<Self>,
 6546    ) -> Option<()> {
 6547        let provider = self.edit_prediction_provider()?;
 6548        let cursor = self.selections.newest_anchor().head();
 6549        let (buffer, cursor_buffer_position) =
 6550            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6551
 6552        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6553            self.discard_inline_completion(false, cx);
 6554            return None;
 6555        }
 6556
 6557        if !user_requested
 6558            && (!self.should_show_edit_predictions()
 6559                || !self.is_focused(window)
 6560                || buffer.read(cx).is_empty())
 6561        {
 6562            self.discard_inline_completion(false, cx);
 6563            return None;
 6564        }
 6565
 6566        self.update_visible_inline_completion(window, cx);
 6567        provider.refresh(
 6568            self.project.clone(),
 6569            buffer,
 6570            cursor_buffer_position,
 6571            debounce,
 6572            cx,
 6573        );
 6574        Some(())
 6575    }
 6576
 6577    fn show_edit_predictions_in_menu(&self) -> bool {
 6578        match self.edit_prediction_settings {
 6579            EditPredictionSettings::Disabled => false,
 6580            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6581        }
 6582    }
 6583
 6584    pub fn edit_predictions_enabled(&self) -> bool {
 6585        match self.edit_prediction_settings {
 6586            EditPredictionSettings::Disabled => false,
 6587            EditPredictionSettings::Enabled { .. } => true,
 6588        }
 6589    }
 6590
 6591    fn edit_prediction_requires_modifier(&self) -> bool {
 6592        match self.edit_prediction_settings {
 6593            EditPredictionSettings::Disabled => false,
 6594            EditPredictionSettings::Enabled {
 6595                preview_requires_modifier,
 6596                ..
 6597            } => preview_requires_modifier,
 6598        }
 6599    }
 6600
 6601    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6602        if self.edit_prediction_provider.is_none() {
 6603            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6604        } else {
 6605            let selection = self.selections.newest_anchor();
 6606            let cursor = selection.head();
 6607
 6608            if let Some((buffer, cursor_buffer_position)) =
 6609                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6610            {
 6611                self.edit_prediction_settings =
 6612                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6613            }
 6614        }
 6615    }
 6616
 6617    fn edit_prediction_settings_at_position(
 6618        &self,
 6619        buffer: &Entity<Buffer>,
 6620        buffer_position: language::Anchor,
 6621        cx: &App,
 6622    ) -> EditPredictionSettings {
 6623        if !self.mode.is_full()
 6624            || !self.show_inline_completions_override.unwrap_or(true)
 6625            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6626        {
 6627            return EditPredictionSettings::Disabled;
 6628        }
 6629
 6630        let buffer = buffer.read(cx);
 6631
 6632        let file = buffer.file();
 6633
 6634        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6635            return EditPredictionSettings::Disabled;
 6636        };
 6637
 6638        let by_provider = matches!(
 6639            self.menu_inline_completions_policy,
 6640            MenuInlineCompletionsPolicy::ByProvider
 6641        );
 6642
 6643        let show_in_menu = by_provider
 6644            && self
 6645                .edit_prediction_provider
 6646                .as_ref()
 6647                .map_or(false, |provider| {
 6648                    provider.provider.show_completions_in_menu()
 6649                });
 6650
 6651        let preview_requires_modifier =
 6652            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6653
 6654        EditPredictionSettings::Enabled {
 6655            show_in_menu,
 6656            preview_requires_modifier,
 6657        }
 6658    }
 6659
 6660    fn should_show_edit_predictions(&self) -> bool {
 6661        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6662    }
 6663
 6664    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6665        matches!(
 6666            self.edit_prediction_preview,
 6667            EditPredictionPreview::Active { .. }
 6668        )
 6669    }
 6670
 6671    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6672        let cursor = self.selections.newest_anchor().head();
 6673        if let Some((buffer, cursor_position)) =
 6674            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6675        {
 6676            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6677        } else {
 6678            false
 6679        }
 6680    }
 6681
 6682    pub fn supports_minimap(&self, cx: &App) -> bool {
 6683        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6684    }
 6685
 6686    fn edit_predictions_enabled_in_buffer(
 6687        &self,
 6688        buffer: &Entity<Buffer>,
 6689        buffer_position: language::Anchor,
 6690        cx: &App,
 6691    ) -> bool {
 6692        maybe!({
 6693            if self.read_only(cx) {
 6694                return Some(false);
 6695            }
 6696            let provider = self.edit_prediction_provider()?;
 6697            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6698                return Some(false);
 6699            }
 6700            let buffer = buffer.read(cx);
 6701            let Some(file) = buffer.file() else {
 6702                return Some(true);
 6703            };
 6704            let settings = all_language_settings(Some(file), cx);
 6705            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6706        })
 6707        .unwrap_or(false)
 6708    }
 6709
 6710    fn cycle_inline_completion(
 6711        &mut self,
 6712        direction: Direction,
 6713        window: &mut Window,
 6714        cx: &mut Context<Self>,
 6715    ) -> Option<()> {
 6716        let provider = self.edit_prediction_provider()?;
 6717        let cursor = self.selections.newest_anchor().head();
 6718        let (buffer, cursor_buffer_position) =
 6719            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6720        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6721            return None;
 6722        }
 6723
 6724        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6725        self.update_visible_inline_completion(window, cx);
 6726
 6727        Some(())
 6728    }
 6729
 6730    pub fn show_inline_completion(
 6731        &mut self,
 6732        _: &ShowEditPrediction,
 6733        window: &mut Window,
 6734        cx: &mut Context<Self>,
 6735    ) {
 6736        if !self.has_active_inline_completion() {
 6737            self.refresh_inline_completion(false, true, window, cx);
 6738            return;
 6739        }
 6740
 6741        self.update_visible_inline_completion(window, cx);
 6742    }
 6743
 6744    pub fn display_cursor_names(
 6745        &mut self,
 6746        _: &DisplayCursorNames,
 6747        window: &mut Window,
 6748        cx: &mut Context<Self>,
 6749    ) {
 6750        self.show_cursor_names(window, cx);
 6751    }
 6752
 6753    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6754        self.show_cursor_names = true;
 6755        cx.notify();
 6756        cx.spawn_in(window, async move |this, cx| {
 6757            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6758            this.update(cx, |this, cx| {
 6759                this.show_cursor_names = false;
 6760                cx.notify()
 6761            })
 6762            .ok()
 6763        })
 6764        .detach();
 6765    }
 6766
 6767    pub fn next_edit_prediction(
 6768        &mut self,
 6769        _: &NextEditPrediction,
 6770        window: &mut Window,
 6771        cx: &mut Context<Self>,
 6772    ) {
 6773        if self.has_active_inline_completion() {
 6774            self.cycle_inline_completion(Direction::Next, window, cx);
 6775        } else {
 6776            let is_copilot_disabled = self
 6777                .refresh_inline_completion(false, true, window, cx)
 6778                .is_none();
 6779            if is_copilot_disabled {
 6780                cx.propagate();
 6781            }
 6782        }
 6783    }
 6784
 6785    pub fn previous_edit_prediction(
 6786        &mut self,
 6787        _: &PreviousEditPrediction,
 6788        window: &mut Window,
 6789        cx: &mut Context<Self>,
 6790    ) {
 6791        if self.has_active_inline_completion() {
 6792            self.cycle_inline_completion(Direction::Prev, window, cx);
 6793        } else {
 6794            let is_copilot_disabled = self
 6795                .refresh_inline_completion(false, true, window, cx)
 6796                .is_none();
 6797            if is_copilot_disabled {
 6798                cx.propagate();
 6799            }
 6800        }
 6801    }
 6802
 6803    pub fn accept_edit_prediction(
 6804        &mut self,
 6805        _: &AcceptEditPrediction,
 6806        window: &mut Window,
 6807        cx: &mut Context<Self>,
 6808    ) {
 6809        if self.show_edit_predictions_in_menu() {
 6810            self.hide_context_menu(window, cx);
 6811        }
 6812
 6813        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6814            return;
 6815        };
 6816
 6817        self.report_inline_completion_event(
 6818            active_inline_completion.completion_id.clone(),
 6819            true,
 6820            cx,
 6821        );
 6822
 6823        match &active_inline_completion.completion {
 6824            InlineCompletion::Move { target, .. } => {
 6825                let target = *target;
 6826
 6827                if let Some(position_map) = &self.last_position_map {
 6828                    if position_map
 6829                        .visible_row_range
 6830                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6831                        || !self.edit_prediction_requires_modifier()
 6832                    {
 6833                        self.unfold_ranges(&[target..target], true, false, cx);
 6834                        // Note that this is also done in vim's handler of the Tab action.
 6835                        self.change_selections(
 6836                            Some(Autoscroll::newest()),
 6837                            window,
 6838                            cx,
 6839                            |selections| {
 6840                                selections.select_anchor_ranges([target..target]);
 6841                            },
 6842                        );
 6843                        self.clear_row_highlights::<EditPredictionPreview>();
 6844
 6845                        self.edit_prediction_preview
 6846                            .set_previous_scroll_position(None);
 6847                    } else {
 6848                        self.edit_prediction_preview
 6849                            .set_previous_scroll_position(Some(
 6850                                position_map.snapshot.scroll_anchor,
 6851                            ));
 6852
 6853                        self.highlight_rows::<EditPredictionPreview>(
 6854                            target..target,
 6855                            cx.theme().colors().editor_highlighted_line_background,
 6856                            RowHighlightOptions {
 6857                                autoscroll: true,
 6858                                ..Default::default()
 6859                            },
 6860                            cx,
 6861                        );
 6862                        self.request_autoscroll(Autoscroll::fit(), cx);
 6863                    }
 6864                }
 6865            }
 6866            InlineCompletion::Edit { edits, .. } => {
 6867                if let Some(provider) = self.edit_prediction_provider() {
 6868                    provider.accept(cx);
 6869                }
 6870
 6871                // Store the transaction ID and selections before applying the edit
 6872                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6873
 6874                let snapshot = self.buffer.read(cx).snapshot(cx);
 6875                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6876
 6877                self.buffer.update(cx, |buffer, cx| {
 6878                    buffer.edit(edits.iter().cloned(), None, cx)
 6879                });
 6880
 6881                self.change_selections(None, window, cx, |s| {
 6882                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6883                });
 6884
 6885                let selections = self.selections.disjoint_anchors();
 6886                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6887                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6888                    if has_new_transaction {
 6889                        self.selection_history
 6890                            .insert_transaction(transaction_id_now, selections);
 6891                    }
 6892                }
 6893
 6894                self.update_visible_inline_completion(window, cx);
 6895                if self.active_inline_completion.is_none() {
 6896                    self.refresh_inline_completion(true, true, window, cx);
 6897                }
 6898
 6899                cx.notify();
 6900            }
 6901        }
 6902
 6903        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6904    }
 6905
 6906    pub fn accept_partial_inline_completion(
 6907        &mut self,
 6908        _: &AcceptPartialEditPrediction,
 6909        window: &mut Window,
 6910        cx: &mut Context<Self>,
 6911    ) {
 6912        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6913            return;
 6914        };
 6915        if self.selections.count() != 1 {
 6916            return;
 6917        }
 6918
 6919        self.report_inline_completion_event(
 6920            active_inline_completion.completion_id.clone(),
 6921            true,
 6922            cx,
 6923        );
 6924
 6925        match &active_inline_completion.completion {
 6926            InlineCompletion::Move { target, .. } => {
 6927                let target = *target;
 6928                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6929                    selections.select_anchor_ranges([target..target]);
 6930                });
 6931            }
 6932            InlineCompletion::Edit { edits, .. } => {
 6933                // Find an insertion that starts at the cursor position.
 6934                let snapshot = self.buffer.read(cx).snapshot(cx);
 6935                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6936                let insertion = edits.iter().find_map(|(range, text)| {
 6937                    let range = range.to_offset(&snapshot);
 6938                    if range.is_empty() && range.start == cursor_offset {
 6939                        Some(text)
 6940                    } else {
 6941                        None
 6942                    }
 6943                });
 6944
 6945                if let Some(text) = insertion {
 6946                    let mut partial_completion = text
 6947                        .chars()
 6948                        .by_ref()
 6949                        .take_while(|c| c.is_alphabetic())
 6950                        .collect::<String>();
 6951                    if partial_completion.is_empty() {
 6952                        partial_completion = text
 6953                            .chars()
 6954                            .by_ref()
 6955                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6956                            .collect::<String>();
 6957                    }
 6958
 6959                    cx.emit(EditorEvent::InputHandled {
 6960                        utf16_range_to_replace: None,
 6961                        text: partial_completion.clone().into(),
 6962                    });
 6963
 6964                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6965
 6966                    self.refresh_inline_completion(true, true, window, cx);
 6967                    cx.notify();
 6968                } else {
 6969                    self.accept_edit_prediction(&Default::default(), window, cx);
 6970                }
 6971            }
 6972        }
 6973    }
 6974
 6975    fn discard_inline_completion(
 6976        &mut self,
 6977        should_report_inline_completion_event: bool,
 6978        cx: &mut Context<Self>,
 6979    ) -> bool {
 6980        if should_report_inline_completion_event {
 6981            let completion_id = self
 6982                .active_inline_completion
 6983                .as_ref()
 6984                .and_then(|active_completion| active_completion.completion_id.clone());
 6985
 6986            self.report_inline_completion_event(completion_id, false, cx);
 6987        }
 6988
 6989        if let Some(provider) = self.edit_prediction_provider() {
 6990            provider.discard(cx);
 6991        }
 6992
 6993        self.take_active_inline_completion(cx)
 6994    }
 6995
 6996    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6997        let Some(provider) = self.edit_prediction_provider() else {
 6998            return;
 6999        };
 7000
 7001        let Some((_, buffer, _)) = self
 7002            .buffer
 7003            .read(cx)
 7004            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7005        else {
 7006            return;
 7007        };
 7008
 7009        let extension = buffer
 7010            .read(cx)
 7011            .file()
 7012            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7013
 7014        let event_type = match accepted {
 7015            true => "Edit Prediction Accepted",
 7016            false => "Edit Prediction Discarded",
 7017        };
 7018        telemetry::event!(
 7019            event_type,
 7020            provider = provider.name(),
 7021            prediction_id = id,
 7022            suggestion_accepted = accepted,
 7023            file_extension = extension,
 7024        );
 7025    }
 7026
 7027    pub fn has_active_inline_completion(&self) -> bool {
 7028        self.active_inline_completion.is_some()
 7029    }
 7030
 7031    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7032        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7033            return false;
 7034        };
 7035
 7036        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7037        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7038        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7039        true
 7040    }
 7041
 7042    /// Returns true when we're displaying the edit prediction popover below the cursor
 7043    /// like we are not previewing and the LSP autocomplete menu is visible
 7044    /// or we are in `when_holding_modifier` mode.
 7045    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7046        if self.edit_prediction_preview_is_active()
 7047            || !self.show_edit_predictions_in_menu()
 7048            || !self.edit_predictions_enabled()
 7049        {
 7050            return false;
 7051        }
 7052
 7053        if self.has_visible_completions_menu() {
 7054            return true;
 7055        }
 7056
 7057        has_completion && self.edit_prediction_requires_modifier()
 7058    }
 7059
 7060    fn handle_modifiers_changed(
 7061        &mut self,
 7062        modifiers: Modifiers,
 7063        position_map: &PositionMap,
 7064        window: &mut Window,
 7065        cx: &mut Context<Self>,
 7066    ) {
 7067        if self.show_edit_predictions_in_menu() {
 7068            self.update_edit_prediction_preview(&modifiers, window, cx);
 7069        }
 7070
 7071        self.update_selection_mode(&modifiers, position_map, window, cx);
 7072
 7073        let mouse_position = window.mouse_position();
 7074        if !position_map.text_hitbox.is_hovered(window) {
 7075            return;
 7076        }
 7077
 7078        self.update_hovered_link(
 7079            position_map.point_for_position(mouse_position),
 7080            &position_map.snapshot,
 7081            modifiers,
 7082            window,
 7083            cx,
 7084        )
 7085    }
 7086
 7087    fn update_selection_mode(
 7088        &mut self,
 7089        modifiers: &Modifiers,
 7090        position_map: &PositionMap,
 7091        window: &mut Window,
 7092        cx: &mut Context<Self>,
 7093    ) {
 7094        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 7095            return;
 7096        }
 7097
 7098        let mouse_position = window.mouse_position();
 7099        let point_for_position = position_map.point_for_position(mouse_position);
 7100        let position = point_for_position.previous_valid;
 7101
 7102        self.select(
 7103            SelectPhase::BeginColumnar {
 7104                position,
 7105                reset: false,
 7106                goal_column: point_for_position.exact_unclipped.column(),
 7107            },
 7108            window,
 7109            cx,
 7110        );
 7111    }
 7112
 7113    fn update_edit_prediction_preview(
 7114        &mut self,
 7115        modifiers: &Modifiers,
 7116        window: &mut Window,
 7117        cx: &mut Context<Self>,
 7118    ) {
 7119        let mut modifiers_held = false;
 7120        if let Some(accept_keystroke) = self
 7121            .accept_edit_prediction_keybind(false, window, cx)
 7122            .keystroke()
 7123        {
 7124            modifiers_held = modifiers_held
 7125                || (&accept_keystroke.modifiers == modifiers
 7126                    && accept_keystroke.modifiers.modified());
 7127        };
 7128        if let Some(accept_partial_keystroke) = self
 7129            .accept_edit_prediction_keybind(true, window, cx)
 7130            .keystroke()
 7131        {
 7132            modifiers_held = modifiers_held
 7133                || (&accept_partial_keystroke.modifiers == modifiers
 7134                    && accept_partial_keystroke.modifiers.modified());
 7135        }
 7136
 7137        if modifiers_held {
 7138            if matches!(
 7139                self.edit_prediction_preview,
 7140                EditPredictionPreview::Inactive { .. }
 7141            ) {
 7142                self.edit_prediction_preview = EditPredictionPreview::Active {
 7143                    previous_scroll_position: None,
 7144                    since: Instant::now(),
 7145                };
 7146
 7147                self.update_visible_inline_completion(window, cx);
 7148                cx.notify();
 7149            }
 7150        } else if let EditPredictionPreview::Active {
 7151            previous_scroll_position,
 7152            since,
 7153        } = self.edit_prediction_preview
 7154        {
 7155            if let (Some(previous_scroll_position), Some(position_map)) =
 7156                (previous_scroll_position, self.last_position_map.as_ref())
 7157            {
 7158                self.set_scroll_position(
 7159                    previous_scroll_position
 7160                        .scroll_position(&position_map.snapshot.display_snapshot),
 7161                    window,
 7162                    cx,
 7163                );
 7164            }
 7165
 7166            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7167                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7168            };
 7169            self.clear_row_highlights::<EditPredictionPreview>();
 7170            self.update_visible_inline_completion(window, cx);
 7171            cx.notify();
 7172        }
 7173    }
 7174
 7175    fn update_visible_inline_completion(
 7176        &mut self,
 7177        _window: &mut Window,
 7178        cx: &mut Context<Self>,
 7179    ) -> Option<()> {
 7180        let selection = self.selections.newest_anchor();
 7181        let cursor = selection.head();
 7182        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7183        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7184        let excerpt_id = cursor.excerpt_id;
 7185
 7186        let show_in_menu = self.show_edit_predictions_in_menu();
 7187        let completions_menu_has_precedence = !show_in_menu
 7188            && (self.context_menu.borrow().is_some()
 7189                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7190
 7191        if completions_menu_has_precedence
 7192            || !offset_selection.is_empty()
 7193            || self
 7194                .active_inline_completion
 7195                .as_ref()
 7196                .map_or(false, |completion| {
 7197                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7198                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7199                    !invalidation_range.contains(&offset_selection.head())
 7200                })
 7201        {
 7202            self.discard_inline_completion(false, cx);
 7203            return None;
 7204        }
 7205
 7206        self.take_active_inline_completion(cx);
 7207        let Some(provider) = self.edit_prediction_provider() else {
 7208            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7209            return None;
 7210        };
 7211
 7212        let (buffer, cursor_buffer_position) =
 7213            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7214
 7215        self.edit_prediction_settings =
 7216            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7217
 7218        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7219
 7220        if self.edit_prediction_indent_conflict {
 7221            let cursor_point = cursor.to_point(&multibuffer);
 7222
 7223            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7224
 7225            if let Some((_, indent)) = indents.iter().next() {
 7226                if indent.len == cursor_point.column {
 7227                    self.edit_prediction_indent_conflict = false;
 7228                }
 7229            }
 7230        }
 7231
 7232        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7233        let edits = inline_completion
 7234            .edits
 7235            .into_iter()
 7236            .flat_map(|(range, new_text)| {
 7237                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7238                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7239                Some((start..end, new_text))
 7240            })
 7241            .collect::<Vec<_>>();
 7242        if edits.is_empty() {
 7243            return None;
 7244        }
 7245
 7246        let first_edit_start = edits.first().unwrap().0.start;
 7247        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7248        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7249
 7250        let last_edit_end = edits.last().unwrap().0.end;
 7251        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7252        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7253
 7254        let cursor_row = cursor.to_point(&multibuffer).row;
 7255
 7256        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7257
 7258        let mut inlay_ids = Vec::new();
 7259        let invalidation_row_range;
 7260        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7261            Some(cursor_row..edit_end_row)
 7262        } else if cursor_row > edit_end_row {
 7263            Some(edit_start_row..cursor_row)
 7264        } else {
 7265            None
 7266        };
 7267        let is_move =
 7268            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7269        let completion = if is_move {
 7270            invalidation_row_range =
 7271                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7272            let target = first_edit_start;
 7273            InlineCompletion::Move { target, snapshot }
 7274        } else {
 7275            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7276                && !self.inline_completions_hidden_for_vim_mode;
 7277
 7278            if show_completions_in_buffer {
 7279                if edits
 7280                    .iter()
 7281                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7282                {
 7283                    let mut inlays = Vec::new();
 7284                    for (range, new_text) in &edits {
 7285                        let inlay = Inlay::inline_completion(
 7286                            post_inc(&mut self.next_inlay_id),
 7287                            range.start,
 7288                            new_text.as_str(),
 7289                        );
 7290                        inlay_ids.push(inlay.id);
 7291                        inlays.push(inlay);
 7292                    }
 7293
 7294                    self.splice_inlays(&[], inlays, cx);
 7295                } else {
 7296                    let background_color = cx.theme().status().deleted_background;
 7297                    self.highlight_text::<InlineCompletionHighlight>(
 7298                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7299                        HighlightStyle {
 7300                            background_color: Some(background_color),
 7301                            ..Default::default()
 7302                        },
 7303                        cx,
 7304                    );
 7305                }
 7306            }
 7307
 7308            invalidation_row_range = edit_start_row..edit_end_row;
 7309
 7310            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7311                if provider.show_tab_accept_marker() {
 7312                    EditDisplayMode::TabAccept
 7313                } else {
 7314                    EditDisplayMode::Inline
 7315                }
 7316            } else {
 7317                EditDisplayMode::DiffPopover
 7318            };
 7319
 7320            InlineCompletion::Edit {
 7321                edits,
 7322                edit_preview: inline_completion.edit_preview,
 7323                display_mode,
 7324                snapshot,
 7325            }
 7326        };
 7327
 7328        let invalidation_range = multibuffer
 7329            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7330            ..multibuffer.anchor_after(Point::new(
 7331                invalidation_row_range.end,
 7332                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7333            ));
 7334
 7335        self.stale_inline_completion_in_menu = None;
 7336        self.active_inline_completion = Some(InlineCompletionState {
 7337            inlay_ids,
 7338            completion,
 7339            completion_id: inline_completion.id,
 7340            invalidation_range,
 7341        });
 7342
 7343        cx.notify();
 7344
 7345        Some(())
 7346    }
 7347
 7348    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7349        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7350    }
 7351
 7352    fn clear_tasks(&mut self) {
 7353        self.tasks.clear()
 7354    }
 7355
 7356    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7357        if self.tasks.insert(key, value).is_some() {
 7358            // This case should hopefully be rare, but just in case...
 7359            log::error!(
 7360                "multiple different run targets found on a single line, only the last target will be rendered"
 7361            )
 7362        }
 7363    }
 7364
 7365    /// Get all display points of breakpoints that will be rendered within editor
 7366    ///
 7367    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7368    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7369    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7370    fn active_breakpoints(
 7371        &self,
 7372        range: Range<DisplayRow>,
 7373        window: &mut Window,
 7374        cx: &mut Context<Self>,
 7375    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7376        let mut breakpoint_display_points = HashMap::default();
 7377
 7378        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7379            return breakpoint_display_points;
 7380        };
 7381
 7382        let snapshot = self.snapshot(window, cx);
 7383
 7384        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7385        let Some(project) = self.project.as_ref() else {
 7386            return breakpoint_display_points;
 7387        };
 7388
 7389        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7390            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7391
 7392        for (buffer_snapshot, range, excerpt_id) in
 7393            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7394        {
 7395            let Some(buffer) = project
 7396                .read(cx)
 7397                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7398            else {
 7399                continue;
 7400            };
 7401            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7402                &buffer,
 7403                Some(
 7404                    buffer_snapshot.anchor_before(range.start)
 7405                        ..buffer_snapshot.anchor_after(range.end),
 7406                ),
 7407                buffer_snapshot,
 7408                cx,
 7409            );
 7410            for (breakpoint, state) in breakpoints {
 7411                let multi_buffer_anchor =
 7412                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7413                let position = multi_buffer_anchor
 7414                    .to_point(&multi_buffer_snapshot)
 7415                    .to_display_point(&snapshot);
 7416
 7417                breakpoint_display_points.insert(
 7418                    position.row(),
 7419                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7420                );
 7421            }
 7422        }
 7423
 7424        breakpoint_display_points
 7425    }
 7426
 7427    fn breakpoint_context_menu(
 7428        &self,
 7429        anchor: Anchor,
 7430        window: &mut Window,
 7431        cx: &mut Context<Self>,
 7432    ) -> Entity<ui::ContextMenu> {
 7433        let weak_editor = cx.weak_entity();
 7434        let focus_handle = self.focus_handle(cx);
 7435
 7436        let row = self
 7437            .buffer
 7438            .read(cx)
 7439            .snapshot(cx)
 7440            .summary_for_anchor::<Point>(&anchor)
 7441            .row;
 7442
 7443        let breakpoint = self
 7444            .breakpoint_at_row(row, window, cx)
 7445            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7446
 7447        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7448            "Edit Log Breakpoint"
 7449        } else {
 7450            "Set Log Breakpoint"
 7451        };
 7452
 7453        let condition_breakpoint_msg = if breakpoint
 7454            .as_ref()
 7455            .is_some_and(|bp| bp.1.condition.is_some())
 7456        {
 7457            "Edit Condition Breakpoint"
 7458        } else {
 7459            "Set Condition Breakpoint"
 7460        };
 7461
 7462        let hit_condition_breakpoint_msg = if breakpoint
 7463            .as_ref()
 7464            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7465        {
 7466            "Edit Hit Condition Breakpoint"
 7467        } else {
 7468            "Set Hit Condition Breakpoint"
 7469        };
 7470
 7471        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7472            "Unset Breakpoint"
 7473        } else {
 7474            "Set Breakpoint"
 7475        };
 7476
 7477        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7478            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7479
 7480        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7481            BreakpointState::Enabled => Some("Disable"),
 7482            BreakpointState::Disabled => Some("Enable"),
 7483        });
 7484
 7485        let (anchor, breakpoint) =
 7486            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7487
 7488        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7489            menu.on_blur_subscription(Subscription::new(|| {}))
 7490                .context(focus_handle)
 7491                .when(run_to_cursor, |this| {
 7492                    let weak_editor = weak_editor.clone();
 7493                    this.entry("Run to cursor", None, move |window, cx| {
 7494                        weak_editor
 7495                            .update(cx, |editor, cx| {
 7496                                editor.change_selections(None, window, cx, |s| {
 7497                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7498                                });
 7499                            })
 7500                            .ok();
 7501
 7502                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7503                    })
 7504                    .separator()
 7505                })
 7506                .when_some(toggle_state_msg, |this, msg| {
 7507                    this.entry(msg, None, {
 7508                        let weak_editor = weak_editor.clone();
 7509                        let breakpoint = breakpoint.clone();
 7510                        move |_window, cx| {
 7511                            weak_editor
 7512                                .update(cx, |this, cx| {
 7513                                    this.edit_breakpoint_at_anchor(
 7514                                        anchor,
 7515                                        breakpoint.as_ref().clone(),
 7516                                        BreakpointEditAction::InvertState,
 7517                                        cx,
 7518                                    );
 7519                                })
 7520                                .log_err();
 7521                        }
 7522                    })
 7523                })
 7524                .entry(set_breakpoint_msg, None, {
 7525                    let weak_editor = weak_editor.clone();
 7526                    let breakpoint = breakpoint.clone();
 7527                    move |_window, cx| {
 7528                        weak_editor
 7529                            .update(cx, |this, cx| {
 7530                                this.edit_breakpoint_at_anchor(
 7531                                    anchor,
 7532                                    breakpoint.as_ref().clone(),
 7533                                    BreakpointEditAction::Toggle,
 7534                                    cx,
 7535                                );
 7536                            })
 7537                            .log_err();
 7538                    }
 7539                })
 7540                .entry(log_breakpoint_msg, None, {
 7541                    let breakpoint = breakpoint.clone();
 7542                    let weak_editor = weak_editor.clone();
 7543                    move |window, cx| {
 7544                        weak_editor
 7545                            .update(cx, |this, cx| {
 7546                                this.add_edit_breakpoint_block(
 7547                                    anchor,
 7548                                    breakpoint.as_ref(),
 7549                                    BreakpointPromptEditAction::Log,
 7550                                    window,
 7551                                    cx,
 7552                                );
 7553                            })
 7554                            .log_err();
 7555                    }
 7556                })
 7557                .entry(condition_breakpoint_msg, None, {
 7558                    let breakpoint = breakpoint.clone();
 7559                    let weak_editor = weak_editor.clone();
 7560                    move |window, cx| {
 7561                        weak_editor
 7562                            .update(cx, |this, cx| {
 7563                                this.add_edit_breakpoint_block(
 7564                                    anchor,
 7565                                    breakpoint.as_ref(),
 7566                                    BreakpointPromptEditAction::Condition,
 7567                                    window,
 7568                                    cx,
 7569                                );
 7570                            })
 7571                            .log_err();
 7572                    }
 7573                })
 7574                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7575                    weak_editor
 7576                        .update(cx, |this, cx| {
 7577                            this.add_edit_breakpoint_block(
 7578                                anchor,
 7579                                breakpoint.as_ref(),
 7580                                BreakpointPromptEditAction::HitCondition,
 7581                                window,
 7582                                cx,
 7583                            );
 7584                        })
 7585                        .log_err();
 7586                })
 7587        })
 7588    }
 7589
 7590    fn render_breakpoint(
 7591        &self,
 7592        position: Anchor,
 7593        row: DisplayRow,
 7594        breakpoint: &Breakpoint,
 7595        state: Option<BreakpointSessionState>,
 7596        cx: &mut Context<Self>,
 7597    ) -> IconButton {
 7598        let is_rejected = state.is_some_and(|s| !s.verified);
 7599        // Is it a breakpoint that shows up when hovering over gutter?
 7600        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7601            (false, false),
 7602            |PhantomBreakpointIndicator {
 7603                 is_active,
 7604                 display_row,
 7605                 collides_with_existing_breakpoint,
 7606             }| {
 7607                (
 7608                    is_active && display_row == row,
 7609                    collides_with_existing_breakpoint,
 7610                )
 7611            },
 7612        );
 7613
 7614        let (color, icon) = {
 7615            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7616                (false, false) => ui::IconName::DebugBreakpoint,
 7617                (true, false) => ui::IconName::DebugLogBreakpoint,
 7618                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7619                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7620            };
 7621
 7622            let color = if is_phantom {
 7623                Color::Hint
 7624            } else if is_rejected {
 7625                Color::Disabled
 7626            } else {
 7627                Color::Debugger
 7628            };
 7629
 7630            (color, icon)
 7631        };
 7632
 7633        let breakpoint = Arc::from(breakpoint.clone());
 7634
 7635        let alt_as_text = gpui::Keystroke {
 7636            modifiers: Modifiers::secondary_key(),
 7637            ..Default::default()
 7638        };
 7639        let primary_action_text = if breakpoint.is_disabled() {
 7640            "Enable breakpoint"
 7641        } else if is_phantom && !collides_with_existing {
 7642            "Set breakpoint"
 7643        } else {
 7644            "Unset breakpoint"
 7645        };
 7646        let focus_handle = self.focus_handle.clone();
 7647
 7648        let meta = if is_rejected {
 7649            SharedString::from("No executable code is associated with this line.")
 7650        } else if collides_with_existing && !breakpoint.is_disabled() {
 7651            SharedString::from(format!(
 7652                "{alt_as_text}-click to disable,\nright-click for more options."
 7653            ))
 7654        } else {
 7655            SharedString::from("Right-click for more options.")
 7656        };
 7657        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7658            .icon_size(IconSize::XSmall)
 7659            .size(ui::ButtonSize::None)
 7660            .when(is_rejected, |this| {
 7661                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7662            })
 7663            .icon_color(color)
 7664            .style(ButtonStyle::Transparent)
 7665            .on_click(cx.listener({
 7666                let breakpoint = breakpoint.clone();
 7667
 7668                move |editor, event: &ClickEvent, window, cx| {
 7669                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7670                        BreakpointEditAction::InvertState
 7671                    } else {
 7672                        BreakpointEditAction::Toggle
 7673                    };
 7674
 7675                    window.focus(&editor.focus_handle(cx));
 7676                    editor.edit_breakpoint_at_anchor(
 7677                        position,
 7678                        breakpoint.as_ref().clone(),
 7679                        edit_action,
 7680                        cx,
 7681                    );
 7682                }
 7683            }))
 7684            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7685                editor.set_breakpoint_context_menu(
 7686                    row,
 7687                    Some(position),
 7688                    event.down.position,
 7689                    window,
 7690                    cx,
 7691                );
 7692            }))
 7693            .tooltip(move |window, cx| {
 7694                Tooltip::with_meta_in(
 7695                    primary_action_text,
 7696                    Some(&ToggleBreakpoint),
 7697                    meta.clone(),
 7698                    &focus_handle,
 7699                    window,
 7700                    cx,
 7701                )
 7702            })
 7703    }
 7704
 7705    fn build_tasks_context(
 7706        project: &Entity<Project>,
 7707        buffer: &Entity<Buffer>,
 7708        buffer_row: u32,
 7709        tasks: &Arc<RunnableTasks>,
 7710        cx: &mut Context<Self>,
 7711    ) -> Task<Option<task::TaskContext>> {
 7712        let position = Point::new(buffer_row, tasks.column);
 7713        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7714        let location = Location {
 7715            buffer: buffer.clone(),
 7716            range: range_start..range_start,
 7717        };
 7718        // Fill in the environmental variables from the tree-sitter captures
 7719        let mut captured_task_variables = TaskVariables::default();
 7720        for (capture_name, value) in tasks.extra_variables.clone() {
 7721            captured_task_variables.insert(
 7722                task::VariableName::Custom(capture_name.into()),
 7723                value.clone(),
 7724            );
 7725        }
 7726        project.update(cx, |project, cx| {
 7727            project.task_store().update(cx, |task_store, cx| {
 7728                task_store.task_context_for_location(captured_task_variables, location, cx)
 7729            })
 7730        })
 7731    }
 7732
 7733    pub fn spawn_nearest_task(
 7734        &mut self,
 7735        action: &SpawnNearestTask,
 7736        window: &mut Window,
 7737        cx: &mut Context<Self>,
 7738    ) {
 7739        let Some((workspace, _)) = self.workspace.clone() else {
 7740            return;
 7741        };
 7742        let Some(project) = self.project.clone() else {
 7743            return;
 7744        };
 7745
 7746        // Try to find a closest, enclosing node using tree-sitter that has a
 7747        // task
 7748        let Some((buffer, buffer_row, tasks)) = self
 7749            .find_enclosing_node_task(cx)
 7750            // Or find the task that's closest in row-distance.
 7751            .or_else(|| self.find_closest_task(cx))
 7752        else {
 7753            return;
 7754        };
 7755
 7756        let reveal_strategy = action.reveal;
 7757        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7758        cx.spawn_in(window, async move |_, cx| {
 7759            let context = task_context.await?;
 7760            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7761
 7762            let resolved = &mut resolved_task.resolved;
 7763            resolved.reveal = reveal_strategy;
 7764
 7765            workspace
 7766                .update_in(cx, |workspace, window, cx| {
 7767                    workspace.schedule_resolved_task(
 7768                        task_source_kind,
 7769                        resolved_task,
 7770                        false,
 7771                        window,
 7772                        cx,
 7773                    );
 7774                })
 7775                .ok()
 7776        })
 7777        .detach();
 7778    }
 7779
 7780    fn find_closest_task(
 7781        &mut self,
 7782        cx: &mut Context<Self>,
 7783    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7784        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7785
 7786        let ((buffer_id, row), tasks) = self
 7787            .tasks
 7788            .iter()
 7789            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7790
 7791        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7792        let tasks = Arc::new(tasks.to_owned());
 7793        Some((buffer, *row, tasks))
 7794    }
 7795
 7796    fn find_enclosing_node_task(
 7797        &mut self,
 7798        cx: &mut Context<Self>,
 7799    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7800        let snapshot = self.buffer.read(cx).snapshot(cx);
 7801        let offset = self.selections.newest::<usize>(cx).head();
 7802        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7803        let buffer_id = excerpt.buffer().remote_id();
 7804
 7805        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7806        let mut cursor = layer.node().walk();
 7807
 7808        while cursor.goto_first_child_for_byte(offset).is_some() {
 7809            if cursor.node().end_byte() == offset {
 7810                cursor.goto_next_sibling();
 7811            }
 7812        }
 7813
 7814        // Ascend to the smallest ancestor that contains the range and has a task.
 7815        loop {
 7816            let node = cursor.node();
 7817            let node_range = node.byte_range();
 7818            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7819
 7820            // Check if this node contains our offset
 7821            if node_range.start <= offset && node_range.end >= offset {
 7822                // If it contains offset, check for task
 7823                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7824                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7825                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7826                }
 7827            }
 7828
 7829            if !cursor.goto_parent() {
 7830                break;
 7831            }
 7832        }
 7833        None
 7834    }
 7835
 7836    fn render_run_indicator(
 7837        &self,
 7838        _style: &EditorStyle,
 7839        is_active: bool,
 7840        row: DisplayRow,
 7841        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7842        cx: &mut Context<Self>,
 7843    ) -> IconButton {
 7844        let color = Color::Muted;
 7845        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7846
 7847        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7848            .shape(ui::IconButtonShape::Square)
 7849            .icon_size(IconSize::XSmall)
 7850            .icon_color(color)
 7851            .toggle_state(is_active)
 7852            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7853                let quick_launch = e.down.button == MouseButton::Left;
 7854                window.focus(&editor.focus_handle(cx));
 7855                editor.toggle_code_actions(
 7856                    &ToggleCodeActions {
 7857                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7858                        quick_launch,
 7859                    },
 7860                    window,
 7861                    cx,
 7862                );
 7863            }))
 7864            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7865                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7866            }))
 7867    }
 7868
 7869    pub fn context_menu_visible(&self) -> bool {
 7870        !self.edit_prediction_preview_is_active()
 7871            && self
 7872                .context_menu
 7873                .borrow()
 7874                .as_ref()
 7875                .map_or(false, |menu| menu.visible())
 7876    }
 7877
 7878    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7879        self.context_menu
 7880            .borrow()
 7881            .as_ref()
 7882            .map(|menu| menu.origin())
 7883    }
 7884
 7885    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7886        self.context_menu_options = Some(options);
 7887    }
 7888
 7889    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7890    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7891
 7892    fn render_edit_prediction_popover(
 7893        &mut self,
 7894        text_bounds: &Bounds<Pixels>,
 7895        content_origin: gpui::Point<Pixels>,
 7896        right_margin: Pixels,
 7897        editor_snapshot: &EditorSnapshot,
 7898        visible_row_range: Range<DisplayRow>,
 7899        scroll_top: f32,
 7900        scroll_bottom: f32,
 7901        line_layouts: &[LineWithInvisibles],
 7902        line_height: Pixels,
 7903        scroll_pixel_position: gpui::Point<Pixels>,
 7904        newest_selection_head: Option<DisplayPoint>,
 7905        editor_width: Pixels,
 7906        style: &EditorStyle,
 7907        window: &mut Window,
 7908        cx: &mut App,
 7909    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7910        if self.mode().is_minimap() {
 7911            return None;
 7912        }
 7913        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7914
 7915        if self.edit_prediction_visible_in_cursor_popover(true) {
 7916            return None;
 7917        }
 7918
 7919        match &active_inline_completion.completion {
 7920            InlineCompletion::Move { target, .. } => {
 7921                let target_display_point = target.to_display_point(editor_snapshot);
 7922
 7923                if self.edit_prediction_requires_modifier() {
 7924                    if !self.edit_prediction_preview_is_active() {
 7925                        return None;
 7926                    }
 7927
 7928                    self.render_edit_prediction_modifier_jump_popover(
 7929                        text_bounds,
 7930                        content_origin,
 7931                        visible_row_range,
 7932                        line_layouts,
 7933                        line_height,
 7934                        scroll_pixel_position,
 7935                        newest_selection_head,
 7936                        target_display_point,
 7937                        window,
 7938                        cx,
 7939                    )
 7940                } else {
 7941                    self.render_edit_prediction_eager_jump_popover(
 7942                        text_bounds,
 7943                        content_origin,
 7944                        editor_snapshot,
 7945                        visible_row_range,
 7946                        scroll_top,
 7947                        scroll_bottom,
 7948                        line_height,
 7949                        scroll_pixel_position,
 7950                        target_display_point,
 7951                        editor_width,
 7952                        window,
 7953                        cx,
 7954                    )
 7955                }
 7956            }
 7957            InlineCompletion::Edit {
 7958                display_mode: EditDisplayMode::Inline,
 7959                ..
 7960            } => None,
 7961            InlineCompletion::Edit {
 7962                display_mode: EditDisplayMode::TabAccept,
 7963                edits,
 7964                ..
 7965            } => {
 7966                let range = &edits.first()?.0;
 7967                let target_display_point = range.end.to_display_point(editor_snapshot);
 7968
 7969                self.render_edit_prediction_end_of_line_popover(
 7970                    "Accept",
 7971                    editor_snapshot,
 7972                    visible_row_range,
 7973                    target_display_point,
 7974                    line_height,
 7975                    scroll_pixel_position,
 7976                    content_origin,
 7977                    editor_width,
 7978                    window,
 7979                    cx,
 7980                )
 7981            }
 7982            InlineCompletion::Edit {
 7983                edits,
 7984                edit_preview,
 7985                display_mode: EditDisplayMode::DiffPopover,
 7986                snapshot,
 7987            } => self.render_edit_prediction_diff_popover(
 7988                text_bounds,
 7989                content_origin,
 7990                right_margin,
 7991                editor_snapshot,
 7992                visible_row_range,
 7993                line_layouts,
 7994                line_height,
 7995                scroll_pixel_position,
 7996                newest_selection_head,
 7997                editor_width,
 7998                style,
 7999                edits,
 8000                edit_preview,
 8001                snapshot,
 8002                window,
 8003                cx,
 8004            ),
 8005        }
 8006    }
 8007
 8008    fn render_edit_prediction_modifier_jump_popover(
 8009        &mut self,
 8010        text_bounds: &Bounds<Pixels>,
 8011        content_origin: gpui::Point<Pixels>,
 8012        visible_row_range: Range<DisplayRow>,
 8013        line_layouts: &[LineWithInvisibles],
 8014        line_height: Pixels,
 8015        scroll_pixel_position: gpui::Point<Pixels>,
 8016        newest_selection_head: Option<DisplayPoint>,
 8017        target_display_point: DisplayPoint,
 8018        window: &mut Window,
 8019        cx: &mut App,
 8020    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8021        let scrolled_content_origin =
 8022            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8023
 8024        const SCROLL_PADDING_Y: Pixels = px(12.);
 8025
 8026        if target_display_point.row() < visible_row_range.start {
 8027            return self.render_edit_prediction_scroll_popover(
 8028                |_| SCROLL_PADDING_Y,
 8029                IconName::ArrowUp,
 8030                visible_row_range,
 8031                line_layouts,
 8032                newest_selection_head,
 8033                scrolled_content_origin,
 8034                window,
 8035                cx,
 8036            );
 8037        } else if target_display_point.row() >= visible_row_range.end {
 8038            return self.render_edit_prediction_scroll_popover(
 8039                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8040                IconName::ArrowDown,
 8041                visible_row_range,
 8042                line_layouts,
 8043                newest_selection_head,
 8044                scrolled_content_origin,
 8045                window,
 8046                cx,
 8047            );
 8048        }
 8049
 8050        const POLE_WIDTH: Pixels = px(2.);
 8051
 8052        let line_layout =
 8053            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8054        let target_column = target_display_point.column() as usize;
 8055
 8056        let target_x = line_layout.x_for_index(target_column);
 8057        let target_y =
 8058            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8059
 8060        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8061
 8062        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8063        border_color.l += 0.001;
 8064
 8065        let mut element = v_flex()
 8066            .items_end()
 8067            .when(flag_on_right, |el| el.items_start())
 8068            .child(if flag_on_right {
 8069                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8070                    .rounded_bl(px(0.))
 8071                    .rounded_tl(px(0.))
 8072                    .border_l_2()
 8073                    .border_color(border_color)
 8074            } else {
 8075                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8076                    .rounded_br(px(0.))
 8077                    .rounded_tr(px(0.))
 8078                    .border_r_2()
 8079                    .border_color(border_color)
 8080            })
 8081            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8082            .into_any();
 8083
 8084        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8085
 8086        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8087            - point(
 8088                if flag_on_right {
 8089                    POLE_WIDTH
 8090                } else {
 8091                    size.width - POLE_WIDTH
 8092                },
 8093                size.height - line_height,
 8094            );
 8095
 8096        origin.x = origin.x.max(content_origin.x);
 8097
 8098        element.prepaint_at(origin, window, cx);
 8099
 8100        Some((element, origin))
 8101    }
 8102
 8103    fn render_edit_prediction_scroll_popover(
 8104        &mut self,
 8105        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8106        scroll_icon: IconName,
 8107        visible_row_range: Range<DisplayRow>,
 8108        line_layouts: &[LineWithInvisibles],
 8109        newest_selection_head: Option<DisplayPoint>,
 8110        scrolled_content_origin: gpui::Point<Pixels>,
 8111        window: &mut Window,
 8112        cx: &mut App,
 8113    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8114        let mut element = self
 8115            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8116            .into_any();
 8117
 8118        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8119
 8120        let cursor = newest_selection_head?;
 8121        let cursor_row_layout =
 8122            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8123        let cursor_column = cursor.column() as usize;
 8124
 8125        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8126
 8127        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8128
 8129        element.prepaint_at(origin, window, cx);
 8130        Some((element, origin))
 8131    }
 8132
 8133    fn render_edit_prediction_eager_jump_popover(
 8134        &mut self,
 8135        text_bounds: &Bounds<Pixels>,
 8136        content_origin: gpui::Point<Pixels>,
 8137        editor_snapshot: &EditorSnapshot,
 8138        visible_row_range: Range<DisplayRow>,
 8139        scroll_top: f32,
 8140        scroll_bottom: f32,
 8141        line_height: Pixels,
 8142        scroll_pixel_position: gpui::Point<Pixels>,
 8143        target_display_point: DisplayPoint,
 8144        editor_width: Pixels,
 8145        window: &mut Window,
 8146        cx: &mut App,
 8147    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8148        if target_display_point.row().as_f32() < scroll_top {
 8149            let mut element = self
 8150                .render_edit_prediction_line_popover(
 8151                    "Jump to Edit",
 8152                    Some(IconName::ArrowUp),
 8153                    window,
 8154                    cx,
 8155                )?
 8156                .into_any();
 8157
 8158            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8159            let offset = point(
 8160                (text_bounds.size.width - size.width) / 2.,
 8161                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8162            );
 8163
 8164            let origin = text_bounds.origin + offset;
 8165            element.prepaint_at(origin, window, cx);
 8166            Some((element, origin))
 8167        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8168            let mut element = self
 8169                .render_edit_prediction_line_popover(
 8170                    "Jump to Edit",
 8171                    Some(IconName::ArrowDown),
 8172                    window,
 8173                    cx,
 8174                )?
 8175                .into_any();
 8176
 8177            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8178            let offset = point(
 8179                (text_bounds.size.width - size.width) / 2.,
 8180                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8181            );
 8182
 8183            let origin = text_bounds.origin + offset;
 8184            element.prepaint_at(origin, window, cx);
 8185            Some((element, origin))
 8186        } else {
 8187            self.render_edit_prediction_end_of_line_popover(
 8188                "Jump to Edit",
 8189                editor_snapshot,
 8190                visible_row_range,
 8191                target_display_point,
 8192                line_height,
 8193                scroll_pixel_position,
 8194                content_origin,
 8195                editor_width,
 8196                window,
 8197                cx,
 8198            )
 8199        }
 8200    }
 8201
 8202    fn render_edit_prediction_end_of_line_popover(
 8203        self: &mut Editor,
 8204        label: &'static str,
 8205        editor_snapshot: &EditorSnapshot,
 8206        visible_row_range: Range<DisplayRow>,
 8207        target_display_point: DisplayPoint,
 8208        line_height: Pixels,
 8209        scroll_pixel_position: gpui::Point<Pixels>,
 8210        content_origin: gpui::Point<Pixels>,
 8211        editor_width: Pixels,
 8212        window: &mut Window,
 8213        cx: &mut App,
 8214    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8215        let target_line_end = DisplayPoint::new(
 8216            target_display_point.row(),
 8217            editor_snapshot.line_len(target_display_point.row()),
 8218        );
 8219
 8220        let mut element = self
 8221            .render_edit_prediction_line_popover(label, None, window, cx)?
 8222            .into_any();
 8223
 8224        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8225
 8226        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8227
 8228        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8229        let mut origin = start_point
 8230            + line_origin
 8231            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8232        origin.x = origin.x.max(content_origin.x);
 8233
 8234        let max_x = content_origin.x + editor_width - size.width;
 8235
 8236        if origin.x > max_x {
 8237            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8238
 8239            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8240                origin.y += offset;
 8241                IconName::ArrowUp
 8242            } else {
 8243                origin.y -= offset;
 8244                IconName::ArrowDown
 8245            };
 8246
 8247            element = self
 8248                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8249                .into_any();
 8250
 8251            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8252
 8253            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8254        }
 8255
 8256        element.prepaint_at(origin, window, cx);
 8257        Some((element, origin))
 8258    }
 8259
 8260    fn render_edit_prediction_diff_popover(
 8261        self: &Editor,
 8262        text_bounds: &Bounds<Pixels>,
 8263        content_origin: gpui::Point<Pixels>,
 8264        right_margin: Pixels,
 8265        editor_snapshot: &EditorSnapshot,
 8266        visible_row_range: Range<DisplayRow>,
 8267        line_layouts: &[LineWithInvisibles],
 8268        line_height: Pixels,
 8269        scroll_pixel_position: gpui::Point<Pixels>,
 8270        newest_selection_head: Option<DisplayPoint>,
 8271        editor_width: Pixels,
 8272        style: &EditorStyle,
 8273        edits: &Vec<(Range<Anchor>, String)>,
 8274        edit_preview: &Option<language::EditPreview>,
 8275        snapshot: &language::BufferSnapshot,
 8276        window: &mut Window,
 8277        cx: &mut App,
 8278    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8279        let edit_start = edits
 8280            .first()
 8281            .unwrap()
 8282            .0
 8283            .start
 8284            .to_display_point(editor_snapshot);
 8285        let edit_end = edits
 8286            .last()
 8287            .unwrap()
 8288            .0
 8289            .end
 8290            .to_display_point(editor_snapshot);
 8291
 8292        let is_visible = visible_row_range.contains(&edit_start.row())
 8293            || visible_row_range.contains(&edit_end.row());
 8294        if !is_visible {
 8295            return None;
 8296        }
 8297
 8298        let highlighted_edits =
 8299            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8300
 8301        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8302        let line_count = highlighted_edits.text.lines().count();
 8303
 8304        const BORDER_WIDTH: Pixels = px(1.);
 8305
 8306        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8307        let has_keybind = keybind.is_some();
 8308
 8309        let mut element = h_flex()
 8310            .items_start()
 8311            .child(
 8312                h_flex()
 8313                    .bg(cx.theme().colors().editor_background)
 8314                    .border(BORDER_WIDTH)
 8315                    .shadow_sm()
 8316                    .border_color(cx.theme().colors().border)
 8317                    .rounded_l_lg()
 8318                    .when(line_count > 1, |el| el.rounded_br_lg())
 8319                    .pr_1()
 8320                    .child(styled_text),
 8321            )
 8322            .child(
 8323                h_flex()
 8324                    .h(line_height + BORDER_WIDTH * 2.)
 8325                    .px_1p5()
 8326                    .gap_1()
 8327                    // Workaround: For some reason, there's a gap if we don't do this
 8328                    .ml(-BORDER_WIDTH)
 8329                    .shadow(vec![gpui::BoxShadow {
 8330                        color: gpui::black().opacity(0.05),
 8331                        offset: point(px(1.), px(1.)),
 8332                        blur_radius: px(2.),
 8333                        spread_radius: px(0.),
 8334                    }])
 8335                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8336                    .border(BORDER_WIDTH)
 8337                    .border_color(cx.theme().colors().border)
 8338                    .rounded_r_lg()
 8339                    .id("edit_prediction_diff_popover_keybind")
 8340                    .when(!has_keybind, |el| {
 8341                        let status_colors = cx.theme().status();
 8342
 8343                        el.bg(status_colors.error_background)
 8344                            .border_color(status_colors.error.opacity(0.6))
 8345                            .child(Icon::new(IconName::Info).color(Color::Error))
 8346                            .cursor_default()
 8347                            .hoverable_tooltip(move |_window, cx| {
 8348                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8349                            })
 8350                    })
 8351                    .children(keybind),
 8352            )
 8353            .into_any();
 8354
 8355        let longest_row =
 8356            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8357        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8358            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8359        } else {
 8360            layout_line(
 8361                longest_row,
 8362                editor_snapshot,
 8363                style,
 8364                editor_width,
 8365                |_| false,
 8366                window,
 8367                cx,
 8368            )
 8369            .width
 8370        };
 8371
 8372        let viewport_bounds =
 8373            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8374                right: -right_margin,
 8375                ..Default::default()
 8376            });
 8377
 8378        let x_after_longest =
 8379            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8380                - scroll_pixel_position.x;
 8381
 8382        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8383
 8384        // Fully visible if it can be displayed within the window (allow overlapping other
 8385        // panes). However, this is only allowed if the popover starts within text_bounds.
 8386        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8387            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8388
 8389        let mut origin = if can_position_to_the_right {
 8390            point(
 8391                x_after_longest,
 8392                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8393                    - scroll_pixel_position.y,
 8394            )
 8395        } else {
 8396            let cursor_row = newest_selection_head.map(|head| head.row());
 8397            let above_edit = edit_start
 8398                .row()
 8399                .0
 8400                .checked_sub(line_count as u32)
 8401                .map(DisplayRow);
 8402            let below_edit = Some(edit_end.row() + 1);
 8403            let above_cursor =
 8404                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8405            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8406
 8407            // Place the edit popover adjacent to the edit if there is a location
 8408            // available that is onscreen and does not obscure the cursor. Otherwise,
 8409            // place it adjacent to the cursor.
 8410            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8411                .into_iter()
 8412                .flatten()
 8413                .find(|&start_row| {
 8414                    let end_row = start_row + line_count as u32;
 8415                    visible_row_range.contains(&start_row)
 8416                        && visible_row_range.contains(&end_row)
 8417                        && cursor_row.map_or(true, |cursor_row| {
 8418                            !((start_row..end_row).contains(&cursor_row))
 8419                        })
 8420                })?;
 8421
 8422            content_origin
 8423                + point(
 8424                    -scroll_pixel_position.x,
 8425                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8426                )
 8427        };
 8428
 8429        origin.x -= BORDER_WIDTH;
 8430
 8431        window.defer_draw(element, origin, 1);
 8432
 8433        // Do not return an element, since it will already be drawn due to defer_draw.
 8434        None
 8435    }
 8436
 8437    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8438        px(30.)
 8439    }
 8440
 8441    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8442        if self.read_only(cx) {
 8443            cx.theme().players().read_only()
 8444        } else {
 8445            self.style.as_ref().unwrap().local_player
 8446        }
 8447    }
 8448
 8449    fn render_edit_prediction_accept_keybind(
 8450        &self,
 8451        window: &mut Window,
 8452        cx: &App,
 8453    ) -> Option<AnyElement> {
 8454        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8455        let accept_keystroke = accept_binding.keystroke()?;
 8456
 8457        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8458
 8459        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8460            Color::Accent
 8461        } else {
 8462            Color::Muted
 8463        };
 8464
 8465        h_flex()
 8466            .px_0p5()
 8467            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8468            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8469            .text_size(TextSize::XSmall.rems(cx))
 8470            .child(h_flex().children(ui::render_modifiers(
 8471                &accept_keystroke.modifiers,
 8472                PlatformStyle::platform(),
 8473                Some(modifiers_color),
 8474                Some(IconSize::XSmall.rems().into()),
 8475                true,
 8476            )))
 8477            .when(is_platform_style_mac, |parent| {
 8478                parent.child(accept_keystroke.key.clone())
 8479            })
 8480            .when(!is_platform_style_mac, |parent| {
 8481                parent.child(
 8482                    Key::new(
 8483                        util::capitalize(&accept_keystroke.key),
 8484                        Some(Color::Default),
 8485                    )
 8486                    .size(Some(IconSize::XSmall.rems().into())),
 8487                )
 8488            })
 8489            .into_any()
 8490            .into()
 8491    }
 8492
 8493    fn render_edit_prediction_line_popover(
 8494        &self,
 8495        label: impl Into<SharedString>,
 8496        icon: Option<IconName>,
 8497        window: &mut Window,
 8498        cx: &App,
 8499    ) -> Option<Stateful<Div>> {
 8500        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8501
 8502        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8503        let has_keybind = keybind.is_some();
 8504
 8505        let result = h_flex()
 8506            .id("ep-line-popover")
 8507            .py_0p5()
 8508            .pl_1()
 8509            .pr(padding_right)
 8510            .gap_1()
 8511            .rounded_md()
 8512            .border_1()
 8513            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8514            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8515            .shadow_sm()
 8516            .when(!has_keybind, |el| {
 8517                let status_colors = cx.theme().status();
 8518
 8519                el.bg(status_colors.error_background)
 8520                    .border_color(status_colors.error.opacity(0.6))
 8521                    .pl_2()
 8522                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8523                    .cursor_default()
 8524                    .hoverable_tooltip(move |_window, cx| {
 8525                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8526                    })
 8527            })
 8528            .children(keybind)
 8529            .child(
 8530                Label::new(label)
 8531                    .size(LabelSize::Small)
 8532                    .when(!has_keybind, |el| {
 8533                        el.color(cx.theme().status().error.into()).strikethrough()
 8534                    }),
 8535            )
 8536            .when(!has_keybind, |el| {
 8537                el.child(
 8538                    h_flex().ml_1().child(
 8539                        Icon::new(IconName::Info)
 8540                            .size(IconSize::Small)
 8541                            .color(cx.theme().status().error.into()),
 8542                    ),
 8543                )
 8544            })
 8545            .when_some(icon, |element, icon| {
 8546                element.child(
 8547                    div()
 8548                        .mt(px(1.5))
 8549                        .child(Icon::new(icon).size(IconSize::Small)),
 8550                )
 8551            });
 8552
 8553        Some(result)
 8554    }
 8555
 8556    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8557        let accent_color = cx.theme().colors().text_accent;
 8558        let editor_bg_color = cx.theme().colors().editor_background;
 8559        editor_bg_color.blend(accent_color.opacity(0.1))
 8560    }
 8561
 8562    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8563        let accent_color = cx.theme().colors().text_accent;
 8564        let editor_bg_color = cx.theme().colors().editor_background;
 8565        editor_bg_color.blend(accent_color.opacity(0.6))
 8566    }
 8567
 8568    fn render_edit_prediction_cursor_popover(
 8569        &self,
 8570        min_width: Pixels,
 8571        max_width: Pixels,
 8572        cursor_point: Point,
 8573        style: &EditorStyle,
 8574        accept_keystroke: Option<&gpui::Keystroke>,
 8575        _window: &Window,
 8576        cx: &mut Context<Editor>,
 8577    ) -> Option<AnyElement> {
 8578        let provider = self.edit_prediction_provider.as_ref()?;
 8579
 8580        if provider.provider.needs_terms_acceptance(cx) {
 8581            return Some(
 8582                h_flex()
 8583                    .min_w(min_width)
 8584                    .flex_1()
 8585                    .px_2()
 8586                    .py_1()
 8587                    .gap_3()
 8588                    .elevation_2(cx)
 8589                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8590                    .id("accept-terms")
 8591                    .cursor_pointer()
 8592                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8593                    .on_click(cx.listener(|this, _event, window, cx| {
 8594                        cx.stop_propagation();
 8595                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8596                        window.dispatch_action(
 8597                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8598                            cx,
 8599                        );
 8600                    }))
 8601                    .child(
 8602                        h_flex()
 8603                            .flex_1()
 8604                            .gap_2()
 8605                            .child(Icon::new(IconName::ZedPredict))
 8606                            .child(Label::new("Accept Terms of Service"))
 8607                            .child(div().w_full())
 8608                            .child(
 8609                                Icon::new(IconName::ArrowUpRight)
 8610                                    .color(Color::Muted)
 8611                                    .size(IconSize::Small),
 8612                            )
 8613                            .into_any_element(),
 8614                    )
 8615                    .into_any(),
 8616            );
 8617        }
 8618
 8619        let is_refreshing = provider.provider.is_refreshing(cx);
 8620
 8621        fn pending_completion_container() -> Div {
 8622            h_flex()
 8623                .h_full()
 8624                .flex_1()
 8625                .gap_2()
 8626                .child(Icon::new(IconName::ZedPredict))
 8627        }
 8628
 8629        let completion = match &self.active_inline_completion {
 8630            Some(prediction) => {
 8631                if !self.has_visible_completions_menu() {
 8632                    const RADIUS: Pixels = px(6.);
 8633                    const BORDER_WIDTH: Pixels = px(1.);
 8634
 8635                    return Some(
 8636                        h_flex()
 8637                            .elevation_2(cx)
 8638                            .border(BORDER_WIDTH)
 8639                            .border_color(cx.theme().colors().border)
 8640                            .when(accept_keystroke.is_none(), |el| {
 8641                                el.border_color(cx.theme().status().error)
 8642                            })
 8643                            .rounded(RADIUS)
 8644                            .rounded_tl(px(0.))
 8645                            .overflow_hidden()
 8646                            .child(div().px_1p5().child(match &prediction.completion {
 8647                                InlineCompletion::Move { target, snapshot } => {
 8648                                    use text::ToPoint as _;
 8649                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8650                                    {
 8651                                        Icon::new(IconName::ZedPredictDown)
 8652                                    } else {
 8653                                        Icon::new(IconName::ZedPredictUp)
 8654                                    }
 8655                                }
 8656                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8657                            }))
 8658                            .child(
 8659                                h_flex()
 8660                                    .gap_1()
 8661                                    .py_1()
 8662                                    .px_2()
 8663                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8664                                    .border_l_1()
 8665                                    .border_color(cx.theme().colors().border)
 8666                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8667                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8668                                        el.child(
 8669                                            Label::new("Hold")
 8670                                                .size(LabelSize::Small)
 8671                                                .when(accept_keystroke.is_none(), |el| {
 8672                                                    el.strikethrough()
 8673                                                })
 8674                                                .line_height_style(LineHeightStyle::UiLabel),
 8675                                        )
 8676                                    })
 8677                                    .id("edit_prediction_cursor_popover_keybind")
 8678                                    .when(accept_keystroke.is_none(), |el| {
 8679                                        let status_colors = cx.theme().status();
 8680
 8681                                        el.bg(status_colors.error_background)
 8682                                            .border_color(status_colors.error.opacity(0.6))
 8683                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8684                                            .cursor_default()
 8685                                            .hoverable_tooltip(move |_window, cx| {
 8686                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8687                                                    .into()
 8688                                            })
 8689                                    })
 8690                                    .when_some(
 8691                                        accept_keystroke.as_ref(),
 8692                                        |el, accept_keystroke| {
 8693                                            el.child(h_flex().children(ui::render_modifiers(
 8694                                                &accept_keystroke.modifiers,
 8695                                                PlatformStyle::platform(),
 8696                                                Some(Color::Default),
 8697                                                Some(IconSize::XSmall.rems().into()),
 8698                                                false,
 8699                                            )))
 8700                                        },
 8701                                    ),
 8702                            )
 8703                            .into_any(),
 8704                    );
 8705                }
 8706
 8707                self.render_edit_prediction_cursor_popover_preview(
 8708                    prediction,
 8709                    cursor_point,
 8710                    style,
 8711                    cx,
 8712                )?
 8713            }
 8714
 8715            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8716                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8717                    stale_completion,
 8718                    cursor_point,
 8719                    style,
 8720                    cx,
 8721                )?,
 8722
 8723                None => {
 8724                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8725                }
 8726            },
 8727
 8728            None => pending_completion_container().child(Label::new("No Prediction")),
 8729        };
 8730
 8731        let completion = if is_refreshing {
 8732            completion
 8733                .with_animation(
 8734                    "loading-completion",
 8735                    Animation::new(Duration::from_secs(2))
 8736                        .repeat()
 8737                        .with_easing(pulsating_between(0.4, 0.8)),
 8738                    |label, delta| label.opacity(delta),
 8739                )
 8740                .into_any_element()
 8741        } else {
 8742            completion.into_any_element()
 8743        };
 8744
 8745        let has_completion = self.active_inline_completion.is_some();
 8746
 8747        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8748        Some(
 8749            h_flex()
 8750                .min_w(min_width)
 8751                .max_w(max_width)
 8752                .flex_1()
 8753                .elevation_2(cx)
 8754                .border_color(cx.theme().colors().border)
 8755                .child(
 8756                    div()
 8757                        .flex_1()
 8758                        .py_1()
 8759                        .px_2()
 8760                        .overflow_hidden()
 8761                        .child(completion),
 8762                )
 8763                .when_some(accept_keystroke, |el, accept_keystroke| {
 8764                    if !accept_keystroke.modifiers.modified() {
 8765                        return el;
 8766                    }
 8767
 8768                    el.child(
 8769                        h_flex()
 8770                            .h_full()
 8771                            .border_l_1()
 8772                            .rounded_r_lg()
 8773                            .border_color(cx.theme().colors().border)
 8774                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8775                            .gap_1()
 8776                            .py_1()
 8777                            .px_2()
 8778                            .child(
 8779                                h_flex()
 8780                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8781                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8782                                    .child(h_flex().children(ui::render_modifiers(
 8783                                        &accept_keystroke.modifiers,
 8784                                        PlatformStyle::platform(),
 8785                                        Some(if !has_completion {
 8786                                            Color::Muted
 8787                                        } else {
 8788                                            Color::Default
 8789                                        }),
 8790                                        None,
 8791                                        false,
 8792                                    ))),
 8793                            )
 8794                            .child(Label::new("Preview").into_any_element())
 8795                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8796                    )
 8797                })
 8798                .into_any(),
 8799        )
 8800    }
 8801
 8802    fn render_edit_prediction_cursor_popover_preview(
 8803        &self,
 8804        completion: &InlineCompletionState,
 8805        cursor_point: Point,
 8806        style: &EditorStyle,
 8807        cx: &mut Context<Editor>,
 8808    ) -> Option<Div> {
 8809        use text::ToPoint as _;
 8810
 8811        fn render_relative_row_jump(
 8812            prefix: impl Into<String>,
 8813            current_row: u32,
 8814            target_row: u32,
 8815        ) -> Div {
 8816            let (row_diff, arrow) = if target_row < current_row {
 8817                (current_row - target_row, IconName::ArrowUp)
 8818            } else {
 8819                (target_row - current_row, IconName::ArrowDown)
 8820            };
 8821
 8822            h_flex()
 8823                .child(
 8824                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8825                        .color(Color::Muted)
 8826                        .size(LabelSize::Small),
 8827                )
 8828                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8829        }
 8830
 8831        match &completion.completion {
 8832            InlineCompletion::Move {
 8833                target, snapshot, ..
 8834            } => Some(
 8835                h_flex()
 8836                    .px_2()
 8837                    .gap_2()
 8838                    .flex_1()
 8839                    .child(
 8840                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8841                            Icon::new(IconName::ZedPredictDown)
 8842                        } else {
 8843                            Icon::new(IconName::ZedPredictUp)
 8844                        },
 8845                    )
 8846                    .child(Label::new("Jump to Edit")),
 8847            ),
 8848
 8849            InlineCompletion::Edit {
 8850                edits,
 8851                edit_preview,
 8852                snapshot,
 8853                display_mode: _,
 8854            } => {
 8855                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8856
 8857                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8858                    &snapshot,
 8859                    &edits,
 8860                    edit_preview.as_ref()?,
 8861                    true,
 8862                    cx,
 8863                )
 8864                .first_line_preview();
 8865
 8866                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8867                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8868
 8869                let preview = h_flex()
 8870                    .gap_1()
 8871                    .min_w_16()
 8872                    .child(styled_text)
 8873                    .when(has_more_lines, |parent| parent.child(""));
 8874
 8875                let left = if first_edit_row != cursor_point.row {
 8876                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8877                        .into_any_element()
 8878                } else {
 8879                    Icon::new(IconName::ZedPredict).into_any_element()
 8880                };
 8881
 8882                Some(
 8883                    h_flex()
 8884                        .h_full()
 8885                        .flex_1()
 8886                        .gap_2()
 8887                        .pr_1()
 8888                        .overflow_x_hidden()
 8889                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8890                        .child(left)
 8891                        .child(preview),
 8892                )
 8893            }
 8894        }
 8895    }
 8896
 8897    pub fn render_context_menu(
 8898        &self,
 8899        style: &EditorStyle,
 8900        max_height_in_lines: u32,
 8901        window: &mut Window,
 8902        cx: &mut Context<Editor>,
 8903    ) -> Option<AnyElement> {
 8904        let menu = self.context_menu.borrow();
 8905        let menu = menu.as_ref()?;
 8906        if !menu.visible() {
 8907            return None;
 8908        };
 8909        Some(menu.render(style, max_height_in_lines, window, cx))
 8910    }
 8911
 8912    fn render_context_menu_aside(
 8913        &mut self,
 8914        max_size: Size<Pixels>,
 8915        window: &mut Window,
 8916        cx: &mut Context<Editor>,
 8917    ) -> Option<AnyElement> {
 8918        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8919            if menu.visible() {
 8920                menu.render_aside(max_size, window, cx)
 8921            } else {
 8922                None
 8923            }
 8924        })
 8925    }
 8926
 8927    fn hide_context_menu(
 8928        &mut self,
 8929        window: &mut Window,
 8930        cx: &mut Context<Self>,
 8931    ) -> Option<CodeContextMenu> {
 8932        cx.notify();
 8933        self.completion_tasks.clear();
 8934        let context_menu = self.context_menu.borrow_mut().take();
 8935        self.stale_inline_completion_in_menu.take();
 8936        self.update_visible_inline_completion(window, cx);
 8937        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8938            if let Some(completion_provider) = &self.completion_provider {
 8939                completion_provider.selection_changed(None, window, cx);
 8940            }
 8941        }
 8942        context_menu
 8943    }
 8944
 8945    fn show_snippet_choices(
 8946        &mut self,
 8947        choices: &Vec<String>,
 8948        selection: Range<Anchor>,
 8949        cx: &mut Context<Self>,
 8950    ) {
 8951        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 8952            (Some(a), Some(b)) if a == b => a,
 8953            _ => {
 8954                log::error!("expected anchor range to have matching buffer IDs");
 8955                return;
 8956            }
 8957        };
 8958        let multi_buffer = self.buffer().read(cx);
 8959        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 8960            return;
 8961        };
 8962
 8963        let id = post_inc(&mut self.next_completion_id);
 8964        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8965        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8966            CompletionsMenu::new_snippet_choices(
 8967                id,
 8968                true,
 8969                choices,
 8970                selection,
 8971                buffer,
 8972                snippet_sort_order,
 8973            ),
 8974        ));
 8975    }
 8976
 8977    pub fn insert_snippet(
 8978        &mut self,
 8979        insertion_ranges: &[Range<usize>],
 8980        snippet: Snippet,
 8981        window: &mut Window,
 8982        cx: &mut Context<Self>,
 8983    ) -> Result<()> {
 8984        struct Tabstop<T> {
 8985            is_end_tabstop: bool,
 8986            ranges: Vec<Range<T>>,
 8987            choices: Option<Vec<String>>,
 8988        }
 8989
 8990        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8991            let snippet_text: Arc<str> = snippet.text.clone().into();
 8992            let edits = insertion_ranges
 8993                .iter()
 8994                .cloned()
 8995                .map(|range| (range, snippet_text.clone()));
 8996            let autoindent_mode = AutoindentMode::Block {
 8997                original_indent_columns: Vec::new(),
 8998            };
 8999            buffer.edit(edits, Some(autoindent_mode), cx);
 9000
 9001            let snapshot = &*buffer.read(cx);
 9002            let snippet = &snippet;
 9003            snippet
 9004                .tabstops
 9005                .iter()
 9006                .map(|tabstop| {
 9007                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9008                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9009                    });
 9010                    let mut tabstop_ranges = tabstop
 9011                        .ranges
 9012                        .iter()
 9013                        .flat_map(|tabstop_range| {
 9014                            let mut delta = 0_isize;
 9015                            insertion_ranges.iter().map(move |insertion_range| {
 9016                                let insertion_start = insertion_range.start as isize + delta;
 9017                                delta +=
 9018                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9019
 9020                                let start = ((insertion_start + tabstop_range.start) as usize)
 9021                                    .min(snapshot.len());
 9022                                let end = ((insertion_start + tabstop_range.end) as usize)
 9023                                    .min(snapshot.len());
 9024                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9025                            })
 9026                        })
 9027                        .collect::<Vec<_>>();
 9028                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9029
 9030                    Tabstop {
 9031                        is_end_tabstop,
 9032                        ranges: tabstop_ranges,
 9033                        choices: tabstop.choices.clone(),
 9034                    }
 9035                })
 9036                .collect::<Vec<_>>()
 9037        });
 9038        if let Some(tabstop) = tabstops.first() {
 9039            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9040                // Reverse order so that the first range is the newest created selection.
 9041                // Completions will use it and autoscroll will prioritize it.
 9042                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9043            });
 9044
 9045            if let Some(choices) = &tabstop.choices {
 9046                if let Some(selection) = tabstop.ranges.first() {
 9047                    self.show_snippet_choices(choices, selection.clone(), cx)
 9048                }
 9049            }
 9050
 9051            // If we're already at the last tabstop and it's at the end of the snippet,
 9052            // we're done, we don't need to keep the state around.
 9053            if !tabstop.is_end_tabstop {
 9054                let choices = tabstops
 9055                    .iter()
 9056                    .map(|tabstop| tabstop.choices.clone())
 9057                    .collect();
 9058
 9059                let ranges = tabstops
 9060                    .into_iter()
 9061                    .map(|tabstop| tabstop.ranges)
 9062                    .collect::<Vec<_>>();
 9063
 9064                self.snippet_stack.push(SnippetState {
 9065                    active_index: 0,
 9066                    ranges,
 9067                    choices,
 9068                });
 9069            }
 9070
 9071            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9072            if self.autoclose_regions.is_empty() {
 9073                let snapshot = self.buffer.read(cx).snapshot(cx);
 9074                for selection in &mut self.selections.all::<Point>(cx) {
 9075                    let selection_head = selection.head();
 9076                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9077                        continue;
 9078                    };
 9079
 9080                    let mut bracket_pair = None;
 9081                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9082                    let prev_chars = snapshot
 9083                        .reversed_chars_at(selection_head)
 9084                        .collect::<String>();
 9085                    for (pair, enabled) in scope.brackets() {
 9086                        if enabled
 9087                            && pair.close
 9088                            && prev_chars.starts_with(pair.start.as_str())
 9089                            && next_chars.starts_with(pair.end.as_str())
 9090                        {
 9091                            bracket_pair = Some(pair.clone());
 9092                            break;
 9093                        }
 9094                    }
 9095                    if let Some(pair) = bracket_pair {
 9096                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9097                        let autoclose_enabled =
 9098                            self.use_autoclose && snapshot_settings.use_autoclose;
 9099                        if autoclose_enabled {
 9100                            let start = snapshot.anchor_after(selection_head);
 9101                            let end = snapshot.anchor_after(selection_head);
 9102                            self.autoclose_regions.push(AutocloseRegion {
 9103                                selection_id: selection.id,
 9104                                range: start..end,
 9105                                pair,
 9106                            });
 9107                        }
 9108                    }
 9109                }
 9110            }
 9111        }
 9112        Ok(())
 9113    }
 9114
 9115    pub fn move_to_next_snippet_tabstop(
 9116        &mut self,
 9117        window: &mut Window,
 9118        cx: &mut Context<Self>,
 9119    ) -> bool {
 9120        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9121    }
 9122
 9123    pub fn move_to_prev_snippet_tabstop(
 9124        &mut self,
 9125        window: &mut Window,
 9126        cx: &mut Context<Self>,
 9127    ) -> bool {
 9128        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9129    }
 9130
 9131    pub fn move_to_snippet_tabstop(
 9132        &mut self,
 9133        bias: Bias,
 9134        window: &mut Window,
 9135        cx: &mut Context<Self>,
 9136    ) -> bool {
 9137        if let Some(mut snippet) = self.snippet_stack.pop() {
 9138            match bias {
 9139                Bias::Left => {
 9140                    if snippet.active_index > 0 {
 9141                        snippet.active_index -= 1;
 9142                    } else {
 9143                        self.snippet_stack.push(snippet);
 9144                        return false;
 9145                    }
 9146                }
 9147                Bias::Right => {
 9148                    if snippet.active_index + 1 < snippet.ranges.len() {
 9149                        snippet.active_index += 1;
 9150                    } else {
 9151                        self.snippet_stack.push(snippet);
 9152                        return false;
 9153                    }
 9154                }
 9155            }
 9156            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9157                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9158                    // Reverse order so that the first range is the newest created selection.
 9159                    // Completions will use it and autoscroll will prioritize it.
 9160                    s.select_ranges(current_ranges.iter().rev().cloned())
 9161                });
 9162
 9163                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9164                    if let Some(selection) = current_ranges.first() {
 9165                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9166                    }
 9167                }
 9168
 9169                // If snippet state is not at the last tabstop, push it back on the stack
 9170                if snippet.active_index + 1 < snippet.ranges.len() {
 9171                    self.snippet_stack.push(snippet);
 9172                }
 9173                return true;
 9174            }
 9175        }
 9176
 9177        false
 9178    }
 9179
 9180    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9181        self.transact(window, cx, |this, window, cx| {
 9182            this.select_all(&SelectAll, window, cx);
 9183            this.insert("", window, cx);
 9184        });
 9185    }
 9186
 9187    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9188        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9189        self.transact(window, cx, |this, window, cx| {
 9190            this.select_autoclose_pair(window, cx);
 9191            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9192            if !this.linked_edit_ranges.is_empty() {
 9193                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9194                let snapshot = this.buffer.read(cx).snapshot(cx);
 9195
 9196                for selection in selections.iter() {
 9197                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9198                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9199                    if selection_start.buffer_id != selection_end.buffer_id {
 9200                        continue;
 9201                    }
 9202                    if let Some(ranges) =
 9203                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9204                    {
 9205                        for (buffer, entries) in ranges {
 9206                            linked_ranges.entry(buffer).or_default().extend(entries);
 9207                        }
 9208                    }
 9209                }
 9210            }
 9211
 9212            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9213            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9214            for selection in &mut selections {
 9215                if selection.is_empty() {
 9216                    let old_head = selection.head();
 9217                    let mut new_head =
 9218                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9219                            .to_point(&display_map);
 9220                    if let Some((buffer, line_buffer_range)) = display_map
 9221                        .buffer_snapshot
 9222                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9223                    {
 9224                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9225                        let indent_len = match indent_size.kind {
 9226                            IndentKind::Space => {
 9227                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9228                            }
 9229                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9230                        };
 9231                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9232                            let indent_len = indent_len.get();
 9233                            new_head = cmp::min(
 9234                                new_head,
 9235                                MultiBufferPoint::new(
 9236                                    old_head.row,
 9237                                    ((old_head.column - 1) / indent_len) * indent_len,
 9238                                ),
 9239                            );
 9240                        }
 9241                    }
 9242
 9243                    selection.set_head(new_head, SelectionGoal::None);
 9244                }
 9245            }
 9246
 9247            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9248                s.select(selections)
 9249            });
 9250            this.insert("", window, cx);
 9251            let empty_str: Arc<str> = Arc::from("");
 9252            for (buffer, edits) in linked_ranges {
 9253                let snapshot = buffer.read(cx).snapshot();
 9254                use text::ToPoint as TP;
 9255
 9256                let edits = edits
 9257                    .into_iter()
 9258                    .map(|range| {
 9259                        let end_point = TP::to_point(&range.end, &snapshot);
 9260                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9261
 9262                        if end_point == start_point {
 9263                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9264                                .saturating_sub(1);
 9265                            start_point =
 9266                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9267                        };
 9268
 9269                        (start_point..end_point, empty_str.clone())
 9270                    })
 9271                    .sorted_by_key(|(range, _)| range.start)
 9272                    .collect::<Vec<_>>();
 9273                buffer.update(cx, |this, cx| {
 9274                    this.edit(edits, None, cx);
 9275                })
 9276            }
 9277            this.refresh_inline_completion(true, false, window, cx);
 9278            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9279        });
 9280    }
 9281
 9282    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9283        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9284        self.transact(window, cx, |this, window, cx| {
 9285            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9286                s.move_with(|map, selection| {
 9287                    if selection.is_empty() {
 9288                        let cursor = movement::right(map, selection.head());
 9289                        selection.end = cursor;
 9290                        selection.reversed = true;
 9291                        selection.goal = SelectionGoal::None;
 9292                    }
 9293                })
 9294            });
 9295            this.insert("", window, cx);
 9296            this.refresh_inline_completion(true, false, window, cx);
 9297        });
 9298    }
 9299
 9300    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9301        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9302        if self.move_to_prev_snippet_tabstop(window, cx) {
 9303            return;
 9304        }
 9305        self.outdent(&Outdent, window, cx);
 9306    }
 9307
 9308    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9309        if self.move_to_next_snippet_tabstop(window, cx) {
 9310            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9311            return;
 9312        }
 9313        if self.read_only(cx) {
 9314            return;
 9315        }
 9316        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9317        let mut selections = self.selections.all_adjusted(cx);
 9318        let buffer = self.buffer.read(cx);
 9319        let snapshot = buffer.snapshot(cx);
 9320        let rows_iter = selections.iter().map(|s| s.head().row);
 9321        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9322
 9323        let has_some_cursor_in_whitespace = selections
 9324            .iter()
 9325            .filter(|selection| selection.is_empty())
 9326            .any(|selection| {
 9327                let cursor = selection.head();
 9328                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9329                cursor.column < current_indent.len
 9330            });
 9331
 9332        let mut edits = Vec::new();
 9333        let mut prev_edited_row = 0;
 9334        let mut row_delta = 0;
 9335        for selection in &mut selections {
 9336            if selection.start.row != prev_edited_row {
 9337                row_delta = 0;
 9338            }
 9339            prev_edited_row = selection.end.row;
 9340
 9341            // If the selection is non-empty, then increase the indentation of the selected lines.
 9342            if !selection.is_empty() {
 9343                row_delta =
 9344                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9345                continue;
 9346            }
 9347
 9348            let cursor = selection.head();
 9349            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9350            if let Some(suggested_indent) =
 9351                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9352            {
 9353                // Don't do anything if already at suggested indent
 9354                // and there is any other cursor which is not
 9355                if has_some_cursor_in_whitespace
 9356                    && cursor.column == current_indent.len
 9357                    && current_indent.len == suggested_indent.len
 9358                {
 9359                    continue;
 9360                }
 9361
 9362                // Adjust line and move cursor to suggested indent
 9363                // if cursor is not at suggested indent
 9364                if cursor.column < suggested_indent.len
 9365                    && cursor.column <= current_indent.len
 9366                    && current_indent.len <= suggested_indent.len
 9367                {
 9368                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9369                    selection.end = selection.start;
 9370                    if row_delta == 0 {
 9371                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9372                            cursor.row,
 9373                            current_indent,
 9374                            suggested_indent,
 9375                        ));
 9376                        row_delta = suggested_indent.len - current_indent.len;
 9377                    }
 9378                    continue;
 9379                }
 9380
 9381                // If current indent is more than suggested indent
 9382                // only move cursor to current indent and skip indent
 9383                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9384                    selection.start = Point::new(cursor.row, current_indent.len);
 9385                    selection.end = selection.start;
 9386                    continue;
 9387                }
 9388            }
 9389
 9390            // Otherwise, insert a hard or soft tab.
 9391            let settings = buffer.language_settings_at(cursor, cx);
 9392            let tab_size = if settings.hard_tabs {
 9393                IndentSize::tab()
 9394            } else {
 9395                let tab_size = settings.tab_size.get();
 9396                let indent_remainder = snapshot
 9397                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9398                    .flat_map(str::chars)
 9399                    .fold(row_delta % tab_size, |counter: u32, c| {
 9400                        if c == '\t' {
 9401                            0
 9402                        } else {
 9403                            (counter + 1) % tab_size
 9404                        }
 9405                    });
 9406
 9407                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9408                IndentSize::spaces(chars_to_next_tab_stop)
 9409            };
 9410            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9411            selection.end = selection.start;
 9412            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9413            row_delta += tab_size.len;
 9414        }
 9415
 9416        self.transact(window, cx, |this, window, cx| {
 9417            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9418            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9419                s.select(selections)
 9420            });
 9421            this.refresh_inline_completion(true, false, window, cx);
 9422        });
 9423    }
 9424
 9425    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9426        if self.read_only(cx) {
 9427            return;
 9428        }
 9429        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9430        let mut selections = self.selections.all::<Point>(cx);
 9431        let mut prev_edited_row = 0;
 9432        let mut row_delta = 0;
 9433        let mut edits = Vec::new();
 9434        let buffer = self.buffer.read(cx);
 9435        let snapshot = buffer.snapshot(cx);
 9436        for selection in &mut selections {
 9437            if selection.start.row != prev_edited_row {
 9438                row_delta = 0;
 9439            }
 9440            prev_edited_row = selection.end.row;
 9441
 9442            row_delta =
 9443                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9444        }
 9445
 9446        self.transact(window, cx, |this, window, cx| {
 9447            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9448            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9449                s.select(selections)
 9450            });
 9451        });
 9452    }
 9453
 9454    fn indent_selection(
 9455        buffer: &MultiBuffer,
 9456        snapshot: &MultiBufferSnapshot,
 9457        selection: &mut Selection<Point>,
 9458        edits: &mut Vec<(Range<Point>, String)>,
 9459        delta_for_start_row: u32,
 9460        cx: &App,
 9461    ) -> u32 {
 9462        let settings = buffer.language_settings_at(selection.start, cx);
 9463        let tab_size = settings.tab_size.get();
 9464        let indent_kind = if settings.hard_tabs {
 9465            IndentKind::Tab
 9466        } else {
 9467            IndentKind::Space
 9468        };
 9469        let mut start_row = selection.start.row;
 9470        let mut end_row = selection.end.row + 1;
 9471
 9472        // If a selection ends at the beginning of a line, don't indent
 9473        // that last line.
 9474        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9475            end_row -= 1;
 9476        }
 9477
 9478        // Avoid re-indenting a row that has already been indented by a
 9479        // previous selection, but still update this selection's column
 9480        // to reflect that indentation.
 9481        if delta_for_start_row > 0 {
 9482            start_row += 1;
 9483            selection.start.column += delta_for_start_row;
 9484            if selection.end.row == selection.start.row {
 9485                selection.end.column += delta_for_start_row;
 9486            }
 9487        }
 9488
 9489        let mut delta_for_end_row = 0;
 9490        let has_multiple_rows = start_row + 1 != end_row;
 9491        for row in start_row..end_row {
 9492            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9493            let indent_delta = match (current_indent.kind, indent_kind) {
 9494                (IndentKind::Space, IndentKind::Space) => {
 9495                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9496                    IndentSize::spaces(columns_to_next_tab_stop)
 9497                }
 9498                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9499                (_, IndentKind::Tab) => IndentSize::tab(),
 9500            };
 9501
 9502            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9503                0
 9504            } else {
 9505                selection.start.column
 9506            };
 9507            let row_start = Point::new(row, start);
 9508            edits.push((
 9509                row_start..row_start,
 9510                indent_delta.chars().collect::<String>(),
 9511            ));
 9512
 9513            // Update this selection's endpoints to reflect the indentation.
 9514            if row == selection.start.row {
 9515                selection.start.column += indent_delta.len;
 9516            }
 9517            if row == selection.end.row {
 9518                selection.end.column += indent_delta.len;
 9519                delta_for_end_row = indent_delta.len;
 9520            }
 9521        }
 9522
 9523        if selection.start.row == selection.end.row {
 9524            delta_for_start_row + delta_for_end_row
 9525        } else {
 9526            delta_for_end_row
 9527        }
 9528    }
 9529
 9530    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9531        if self.read_only(cx) {
 9532            return;
 9533        }
 9534        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9536        let selections = self.selections.all::<Point>(cx);
 9537        let mut deletion_ranges = Vec::new();
 9538        let mut last_outdent = None;
 9539        {
 9540            let buffer = self.buffer.read(cx);
 9541            let snapshot = buffer.snapshot(cx);
 9542            for selection in &selections {
 9543                let settings = buffer.language_settings_at(selection.start, cx);
 9544                let tab_size = settings.tab_size.get();
 9545                let mut rows = selection.spanned_rows(false, &display_map);
 9546
 9547                // Avoid re-outdenting a row that has already been outdented by a
 9548                // previous selection.
 9549                if let Some(last_row) = last_outdent {
 9550                    if last_row == rows.start {
 9551                        rows.start = rows.start.next_row();
 9552                    }
 9553                }
 9554                let has_multiple_rows = rows.len() > 1;
 9555                for row in rows.iter_rows() {
 9556                    let indent_size = snapshot.indent_size_for_line(row);
 9557                    if indent_size.len > 0 {
 9558                        let deletion_len = match indent_size.kind {
 9559                            IndentKind::Space => {
 9560                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9561                                if columns_to_prev_tab_stop == 0 {
 9562                                    tab_size
 9563                                } else {
 9564                                    columns_to_prev_tab_stop
 9565                                }
 9566                            }
 9567                            IndentKind::Tab => 1,
 9568                        };
 9569                        let start = if has_multiple_rows
 9570                            || deletion_len > selection.start.column
 9571                            || indent_size.len < selection.start.column
 9572                        {
 9573                            0
 9574                        } else {
 9575                            selection.start.column - deletion_len
 9576                        };
 9577                        deletion_ranges.push(
 9578                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9579                        );
 9580                        last_outdent = Some(row);
 9581                    }
 9582                }
 9583            }
 9584        }
 9585
 9586        self.transact(window, cx, |this, window, cx| {
 9587            this.buffer.update(cx, |buffer, cx| {
 9588                let empty_str: Arc<str> = Arc::default();
 9589                buffer.edit(
 9590                    deletion_ranges
 9591                        .into_iter()
 9592                        .map(|range| (range, empty_str.clone())),
 9593                    None,
 9594                    cx,
 9595                );
 9596            });
 9597            let selections = this.selections.all::<usize>(cx);
 9598            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9599                s.select(selections)
 9600            });
 9601        });
 9602    }
 9603
 9604    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9605        if self.read_only(cx) {
 9606            return;
 9607        }
 9608        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9609        let selections = self
 9610            .selections
 9611            .all::<usize>(cx)
 9612            .into_iter()
 9613            .map(|s| s.range());
 9614
 9615        self.transact(window, cx, |this, window, cx| {
 9616            this.buffer.update(cx, |buffer, cx| {
 9617                buffer.autoindent_ranges(selections, cx);
 9618            });
 9619            let selections = this.selections.all::<usize>(cx);
 9620            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9621                s.select(selections)
 9622            });
 9623        });
 9624    }
 9625
 9626    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9627        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9628        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9629        let selections = self.selections.all::<Point>(cx);
 9630
 9631        let mut new_cursors = Vec::new();
 9632        let mut edit_ranges = Vec::new();
 9633        let mut selections = selections.iter().peekable();
 9634        while let Some(selection) = selections.next() {
 9635            let mut rows = selection.spanned_rows(false, &display_map);
 9636            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9637
 9638            // Accumulate contiguous regions of rows that we want to delete.
 9639            while let Some(next_selection) = selections.peek() {
 9640                let next_rows = next_selection.spanned_rows(false, &display_map);
 9641                if next_rows.start <= rows.end {
 9642                    rows.end = next_rows.end;
 9643                    selections.next().unwrap();
 9644                } else {
 9645                    break;
 9646                }
 9647            }
 9648
 9649            let buffer = &display_map.buffer_snapshot;
 9650            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9651            let edit_end;
 9652            let cursor_buffer_row;
 9653            if buffer.max_point().row >= rows.end.0 {
 9654                // If there's a line after the range, delete the \n from the end of the row range
 9655                // and position the cursor on the next line.
 9656                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9657                cursor_buffer_row = rows.end;
 9658            } else {
 9659                // If there isn't a line after the range, delete the \n from the line before the
 9660                // start of the row range and position the cursor there.
 9661                edit_start = edit_start.saturating_sub(1);
 9662                edit_end = buffer.len();
 9663                cursor_buffer_row = rows.start.previous_row();
 9664            }
 9665
 9666            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9667            *cursor.column_mut() =
 9668                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9669
 9670            new_cursors.push((
 9671                selection.id,
 9672                buffer.anchor_after(cursor.to_point(&display_map)),
 9673            ));
 9674            edit_ranges.push(edit_start..edit_end);
 9675        }
 9676
 9677        self.transact(window, cx, |this, window, cx| {
 9678            let buffer = this.buffer.update(cx, |buffer, cx| {
 9679                let empty_str: Arc<str> = Arc::default();
 9680                buffer.edit(
 9681                    edit_ranges
 9682                        .into_iter()
 9683                        .map(|range| (range, empty_str.clone())),
 9684                    None,
 9685                    cx,
 9686                );
 9687                buffer.snapshot(cx)
 9688            });
 9689            let new_selections = new_cursors
 9690                .into_iter()
 9691                .map(|(id, cursor)| {
 9692                    let cursor = cursor.to_point(&buffer);
 9693                    Selection {
 9694                        id,
 9695                        start: cursor,
 9696                        end: cursor,
 9697                        reversed: false,
 9698                        goal: SelectionGoal::None,
 9699                    }
 9700                })
 9701                .collect();
 9702
 9703            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9704                s.select(new_selections);
 9705            });
 9706        });
 9707    }
 9708
 9709    pub fn join_lines_impl(
 9710        &mut self,
 9711        insert_whitespace: bool,
 9712        window: &mut Window,
 9713        cx: &mut Context<Self>,
 9714    ) {
 9715        if self.read_only(cx) {
 9716            return;
 9717        }
 9718        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9719        for selection in self.selections.all::<Point>(cx) {
 9720            let start = MultiBufferRow(selection.start.row);
 9721            // Treat single line selections as if they include the next line. Otherwise this action
 9722            // would do nothing for single line selections individual cursors.
 9723            let end = if selection.start.row == selection.end.row {
 9724                MultiBufferRow(selection.start.row + 1)
 9725            } else {
 9726                MultiBufferRow(selection.end.row)
 9727            };
 9728
 9729            if let Some(last_row_range) = row_ranges.last_mut() {
 9730                if start <= last_row_range.end {
 9731                    last_row_range.end = end;
 9732                    continue;
 9733                }
 9734            }
 9735            row_ranges.push(start..end);
 9736        }
 9737
 9738        let snapshot = self.buffer.read(cx).snapshot(cx);
 9739        let mut cursor_positions = Vec::new();
 9740        for row_range in &row_ranges {
 9741            let anchor = snapshot.anchor_before(Point::new(
 9742                row_range.end.previous_row().0,
 9743                snapshot.line_len(row_range.end.previous_row()),
 9744            ));
 9745            cursor_positions.push(anchor..anchor);
 9746        }
 9747
 9748        self.transact(window, cx, |this, window, cx| {
 9749            for row_range in row_ranges.into_iter().rev() {
 9750                for row in row_range.iter_rows().rev() {
 9751                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9752                    let next_line_row = row.next_row();
 9753                    let indent = snapshot.indent_size_for_line(next_line_row);
 9754                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9755
 9756                    let replace =
 9757                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9758                            " "
 9759                        } else {
 9760                            ""
 9761                        };
 9762
 9763                    this.buffer.update(cx, |buffer, cx| {
 9764                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9765                    });
 9766                }
 9767            }
 9768
 9769            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9770                s.select_anchor_ranges(cursor_positions)
 9771            });
 9772        });
 9773    }
 9774
 9775    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9776        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9777        self.join_lines_impl(true, window, cx);
 9778    }
 9779
 9780    pub fn sort_lines_case_sensitive(
 9781        &mut self,
 9782        _: &SortLinesCaseSensitive,
 9783        window: &mut Window,
 9784        cx: &mut Context<Self>,
 9785    ) {
 9786        self.manipulate_lines(window, cx, |lines| lines.sort())
 9787    }
 9788
 9789    pub fn sort_lines_case_insensitive(
 9790        &mut self,
 9791        _: &SortLinesCaseInsensitive,
 9792        window: &mut Window,
 9793        cx: &mut Context<Self>,
 9794    ) {
 9795        self.manipulate_lines(window, cx, |lines| {
 9796            lines.sort_by_key(|line| line.to_lowercase())
 9797        })
 9798    }
 9799
 9800    pub fn unique_lines_case_insensitive(
 9801        &mut self,
 9802        _: &UniqueLinesCaseInsensitive,
 9803        window: &mut Window,
 9804        cx: &mut Context<Self>,
 9805    ) {
 9806        self.manipulate_lines(window, cx, |lines| {
 9807            let mut seen = HashSet::default();
 9808            lines.retain(|line| seen.insert(line.to_lowercase()));
 9809        })
 9810    }
 9811
 9812    pub fn unique_lines_case_sensitive(
 9813        &mut self,
 9814        _: &UniqueLinesCaseSensitive,
 9815        window: &mut Window,
 9816        cx: &mut Context<Self>,
 9817    ) {
 9818        self.manipulate_lines(window, cx, |lines| {
 9819            let mut seen = HashSet::default();
 9820            lines.retain(|line| seen.insert(*line));
 9821        })
 9822    }
 9823
 9824    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9825        let Some(project) = self.project.clone() else {
 9826            return;
 9827        };
 9828        self.reload(project, window, cx)
 9829            .detach_and_notify_err(window, cx);
 9830    }
 9831
 9832    pub fn restore_file(
 9833        &mut self,
 9834        _: &::git::RestoreFile,
 9835        window: &mut Window,
 9836        cx: &mut Context<Self>,
 9837    ) {
 9838        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9839        let mut buffer_ids = HashSet::default();
 9840        let snapshot = self.buffer().read(cx).snapshot(cx);
 9841        for selection in self.selections.all::<usize>(cx) {
 9842            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9843        }
 9844
 9845        let buffer = self.buffer().read(cx);
 9846        let ranges = buffer_ids
 9847            .into_iter()
 9848            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9849            .collect::<Vec<_>>();
 9850
 9851        self.restore_hunks_in_ranges(ranges, window, cx);
 9852    }
 9853
 9854    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9855        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9856        let selections = self
 9857            .selections
 9858            .all(cx)
 9859            .into_iter()
 9860            .map(|s| s.range())
 9861            .collect();
 9862        self.restore_hunks_in_ranges(selections, window, cx);
 9863    }
 9864
 9865    pub fn restore_hunks_in_ranges(
 9866        &mut self,
 9867        ranges: Vec<Range<Point>>,
 9868        window: &mut Window,
 9869        cx: &mut Context<Editor>,
 9870    ) {
 9871        let mut revert_changes = HashMap::default();
 9872        let chunk_by = self
 9873            .snapshot(window, cx)
 9874            .hunks_for_ranges(ranges)
 9875            .into_iter()
 9876            .chunk_by(|hunk| hunk.buffer_id);
 9877        for (buffer_id, hunks) in &chunk_by {
 9878            let hunks = hunks.collect::<Vec<_>>();
 9879            for hunk in &hunks {
 9880                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9881            }
 9882            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9883        }
 9884        drop(chunk_by);
 9885        if !revert_changes.is_empty() {
 9886            self.transact(window, cx, |editor, window, cx| {
 9887                editor.restore(revert_changes, window, cx);
 9888            });
 9889        }
 9890    }
 9891
 9892    pub fn open_active_item_in_terminal(
 9893        &mut self,
 9894        _: &OpenInTerminal,
 9895        window: &mut Window,
 9896        cx: &mut Context<Self>,
 9897    ) {
 9898        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9899            let project_path = buffer.read(cx).project_path(cx)?;
 9900            let project = self.project.as_ref()?.read(cx);
 9901            let entry = project.entry_for_path(&project_path, cx)?;
 9902            let parent = match &entry.canonical_path {
 9903                Some(canonical_path) => canonical_path.to_path_buf(),
 9904                None => project.absolute_path(&project_path, cx)?,
 9905            }
 9906            .parent()?
 9907            .to_path_buf();
 9908            Some(parent)
 9909        }) {
 9910            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9911        }
 9912    }
 9913
 9914    fn set_breakpoint_context_menu(
 9915        &mut self,
 9916        display_row: DisplayRow,
 9917        position: Option<Anchor>,
 9918        clicked_point: gpui::Point<Pixels>,
 9919        window: &mut Window,
 9920        cx: &mut Context<Self>,
 9921    ) {
 9922        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9923            return;
 9924        }
 9925        let source = self
 9926            .buffer
 9927            .read(cx)
 9928            .snapshot(cx)
 9929            .anchor_before(Point::new(display_row.0, 0u32));
 9930
 9931        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9932
 9933        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9934            self,
 9935            source,
 9936            clicked_point,
 9937            context_menu,
 9938            window,
 9939            cx,
 9940        );
 9941    }
 9942
 9943    fn add_edit_breakpoint_block(
 9944        &mut self,
 9945        anchor: Anchor,
 9946        breakpoint: &Breakpoint,
 9947        edit_action: BreakpointPromptEditAction,
 9948        window: &mut Window,
 9949        cx: &mut Context<Self>,
 9950    ) {
 9951        let weak_editor = cx.weak_entity();
 9952        let bp_prompt = cx.new(|cx| {
 9953            BreakpointPromptEditor::new(
 9954                weak_editor,
 9955                anchor,
 9956                breakpoint.clone(),
 9957                edit_action,
 9958                window,
 9959                cx,
 9960            )
 9961        });
 9962
 9963        let height = bp_prompt.update(cx, |this, cx| {
 9964            this.prompt
 9965                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9966        });
 9967        let cloned_prompt = bp_prompt.clone();
 9968        let blocks = vec![BlockProperties {
 9969            style: BlockStyle::Sticky,
 9970            placement: BlockPlacement::Above(anchor),
 9971            height: Some(height),
 9972            render: Arc::new(move |cx| {
 9973                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9974                cloned_prompt.clone().into_any_element()
 9975            }),
 9976            priority: 0,
 9977            render_in_minimap: true,
 9978        }];
 9979
 9980        let focus_handle = bp_prompt.focus_handle(cx);
 9981        window.focus(&focus_handle);
 9982
 9983        let block_ids = self.insert_blocks(blocks, None, cx);
 9984        bp_prompt.update(cx, |prompt, _| {
 9985            prompt.add_block_ids(block_ids);
 9986        });
 9987    }
 9988
 9989    pub(crate) fn breakpoint_at_row(
 9990        &self,
 9991        row: u32,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) -> Option<(Anchor, Breakpoint)> {
 9995        let snapshot = self.snapshot(window, cx);
 9996        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9997
 9998        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9999    }
10000
10001    pub(crate) fn breakpoint_at_anchor(
10002        &self,
10003        breakpoint_position: Anchor,
10004        snapshot: &EditorSnapshot,
10005        cx: &mut Context<Self>,
10006    ) -> Option<(Anchor, Breakpoint)> {
10007        let project = self.project.clone()?;
10008
10009        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10010            snapshot
10011                .buffer_snapshot
10012                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10013        })?;
10014
10015        let enclosing_excerpt = breakpoint_position.excerpt_id;
10016        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10017        let buffer_snapshot = buffer.read(cx).snapshot();
10018
10019        let row = buffer_snapshot
10020            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10021            .row;
10022
10023        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10024        let anchor_end = snapshot
10025            .buffer_snapshot
10026            .anchor_after(Point::new(row, line_len));
10027
10028        let bp = self
10029            .breakpoint_store
10030            .as_ref()?
10031            .read_with(cx, |breakpoint_store, cx| {
10032                breakpoint_store
10033                    .breakpoints(
10034                        &buffer,
10035                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10036                        &buffer_snapshot,
10037                        cx,
10038                    )
10039                    .next()
10040                    .and_then(|(bp, _)| {
10041                        let breakpoint_row = buffer_snapshot
10042                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10043                            .row;
10044
10045                        if breakpoint_row == row {
10046                            snapshot
10047                                .buffer_snapshot
10048                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10049                                .map(|position| (position, bp.bp.clone()))
10050                        } else {
10051                            None
10052                        }
10053                    })
10054            });
10055        bp
10056    }
10057
10058    pub fn edit_log_breakpoint(
10059        &mut self,
10060        _: &EditLogBreakpoint,
10061        window: &mut Window,
10062        cx: &mut Context<Self>,
10063    ) {
10064        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10065            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10066                message: None,
10067                state: BreakpointState::Enabled,
10068                condition: None,
10069                hit_condition: None,
10070            });
10071
10072            self.add_edit_breakpoint_block(
10073                anchor,
10074                &breakpoint,
10075                BreakpointPromptEditAction::Log,
10076                window,
10077                cx,
10078            );
10079        }
10080    }
10081
10082    fn breakpoints_at_cursors(
10083        &self,
10084        window: &mut Window,
10085        cx: &mut Context<Self>,
10086    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10087        let snapshot = self.snapshot(window, cx);
10088        let cursors = self
10089            .selections
10090            .disjoint_anchors()
10091            .into_iter()
10092            .map(|selection| {
10093                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10094
10095                let breakpoint_position = self
10096                    .breakpoint_at_row(cursor_position.row, window, cx)
10097                    .map(|bp| bp.0)
10098                    .unwrap_or_else(|| {
10099                        snapshot
10100                            .display_snapshot
10101                            .buffer_snapshot
10102                            .anchor_after(Point::new(cursor_position.row, 0))
10103                    });
10104
10105                let breakpoint = self
10106                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10107                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10108
10109                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10110            })
10111            // 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.
10112            .collect::<HashMap<Anchor, _>>();
10113
10114        cursors.into_iter().collect()
10115    }
10116
10117    pub fn enable_breakpoint(
10118        &mut self,
10119        _: &crate::actions::EnableBreakpoint,
10120        window: &mut Window,
10121        cx: &mut Context<Self>,
10122    ) {
10123        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10124            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10125                continue;
10126            };
10127            self.edit_breakpoint_at_anchor(
10128                anchor,
10129                breakpoint,
10130                BreakpointEditAction::InvertState,
10131                cx,
10132            );
10133        }
10134    }
10135
10136    pub fn disable_breakpoint(
10137        &mut self,
10138        _: &crate::actions::DisableBreakpoint,
10139        window: &mut Window,
10140        cx: &mut Context<Self>,
10141    ) {
10142        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10143            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10144                continue;
10145            };
10146            self.edit_breakpoint_at_anchor(
10147                anchor,
10148                breakpoint,
10149                BreakpointEditAction::InvertState,
10150                cx,
10151            );
10152        }
10153    }
10154
10155    pub fn toggle_breakpoint(
10156        &mut self,
10157        _: &crate::actions::ToggleBreakpoint,
10158        window: &mut Window,
10159        cx: &mut Context<Self>,
10160    ) {
10161        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10162            if let Some(breakpoint) = breakpoint {
10163                self.edit_breakpoint_at_anchor(
10164                    anchor,
10165                    breakpoint,
10166                    BreakpointEditAction::Toggle,
10167                    cx,
10168                );
10169            } else {
10170                self.edit_breakpoint_at_anchor(
10171                    anchor,
10172                    Breakpoint::new_standard(),
10173                    BreakpointEditAction::Toggle,
10174                    cx,
10175                );
10176            }
10177        }
10178    }
10179
10180    pub fn edit_breakpoint_at_anchor(
10181        &mut self,
10182        breakpoint_position: Anchor,
10183        breakpoint: Breakpoint,
10184        edit_action: BreakpointEditAction,
10185        cx: &mut Context<Self>,
10186    ) {
10187        let Some(breakpoint_store) = &self.breakpoint_store else {
10188            return;
10189        };
10190
10191        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10192            if breakpoint_position == Anchor::min() {
10193                self.buffer()
10194                    .read(cx)
10195                    .excerpt_buffer_ids()
10196                    .into_iter()
10197                    .next()
10198            } else {
10199                None
10200            }
10201        }) else {
10202            return;
10203        };
10204
10205        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10206            return;
10207        };
10208
10209        breakpoint_store.update(cx, |breakpoint_store, cx| {
10210            breakpoint_store.toggle_breakpoint(
10211                buffer,
10212                BreakpointWithPosition {
10213                    position: breakpoint_position.text_anchor,
10214                    bp: breakpoint,
10215                },
10216                edit_action,
10217                cx,
10218            );
10219        });
10220
10221        cx.notify();
10222    }
10223
10224    #[cfg(any(test, feature = "test-support"))]
10225    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10226        self.breakpoint_store.clone()
10227    }
10228
10229    pub fn prepare_restore_change(
10230        &self,
10231        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10232        hunk: &MultiBufferDiffHunk,
10233        cx: &mut App,
10234    ) -> Option<()> {
10235        if hunk.is_created_file() {
10236            return None;
10237        }
10238        let buffer = self.buffer.read(cx);
10239        let diff = buffer.diff_for(hunk.buffer_id)?;
10240        let buffer = buffer.buffer(hunk.buffer_id)?;
10241        let buffer = buffer.read(cx);
10242        let original_text = diff
10243            .read(cx)
10244            .base_text()
10245            .as_rope()
10246            .slice(hunk.diff_base_byte_range.clone());
10247        let buffer_snapshot = buffer.snapshot();
10248        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10249        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10250            probe
10251                .0
10252                .start
10253                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10254                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10255        }) {
10256            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10257            Some(())
10258        } else {
10259            None
10260        }
10261    }
10262
10263    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10264        self.manipulate_lines(window, cx, |lines| lines.reverse())
10265    }
10266
10267    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10268        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10269    }
10270
10271    fn manipulate_lines<Fn>(
10272        &mut self,
10273        window: &mut Window,
10274        cx: &mut Context<Self>,
10275        mut callback: Fn,
10276    ) where
10277        Fn: FnMut(&mut Vec<&str>),
10278    {
10279        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10280
10281        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10282        let buffer = self.buffer.read(cx).snapshot(cx);
10283
10284        let mut edits = Vec::new();
10285
10286        let selections = self.selections.all::<Point>(cx);
10287        let mut selections = selections.iter().peekable();
10288        let mut contiguous_row_selections = Vec::new();
10289        let mut new_selections = Vec::new();
10290        let mut added_lines = 0;
10291        let mut removed_lines = 0;
10292
10293        while let Some(selection) = selections.next() {
10294            let (start_row, end_row) = consume_contiguous_rows(
10295                &mut contiguous_row_selections,
10296                selection,
10297                &display_map,
10298                &mut selections,
10299            );
10300
10301            let start_point = Point::new(start_row.0, 0);
10302            let end_point = Point::new(
10303                end_row.previous_row().0,
10304                buffer.line_len(end_row.previous_row()),
10305            );
10306            let text = buffer
10307                .text_for_range(start_point..end_point)
10308                .collect::<String>();
10309
10310            let mut lines = text.split('\n').collect_vec();
10311
10312            let lines_before = lines.len();
10313            callback(&mut lines);
10314            let lines_after = lines.len();
10315
10316            edits.push((start_point..end_point, lines.join("\n")));
10317
10318            // Selections must change based on added and removed line count
10319            let start_row =
10320                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10321            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10322            new_selections.push(Selection {
10323                id: selection.id,
10324                start: start_row,
10325                end: end_row,
10326                goal: SelectionGoal::None,
10327                reversed: selection.reversed,
10328            });
10329
10330            if lines_after > lines_before {
10331                added_lines += lines_after - lines_before;
10332            } else if lines_before > lines_after {
10333                removed_lines += lines_before - lines_after;
10334            }
10335        }
10336
10337        self.transact(window, cx, |this, window, cx| {
10338            let buffer = this.buffer.update(cx, |buffer, cx| {
10339                buffer.edit(edits, None, cx);
10340                buffer.snapshot(cx)
10341            });
10342
10343            // Recalculate offsets on newly edited buffer
10344            let new_selections = new_selections
10345                .iter()
10346                .map(|s| {
10347                    let start_point = Point::new(s.start.0, 0);
10348                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10349                    Selection {
10350                        id: s.id,
10351                        start: buffer.point_to_offset(start_point),
10352                        end: buffer.point_to_offset(end_point),
10353                        goal: s.goal,
10354                        reversed: s.reversed,
10355                    }
10356                })
10357                .collect();
10358
10359            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10360                s.select(new_selections);
10361            });
10362
10363            this.request_autoscroll(Autoscroll::fit(), cx);
10364        });
10365    }
10366
10367    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10368        self.manipulate_text(window, cx, |text| {
10369            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10370            if has_upper_case_characters {
10371                text.to_lowercase()
10372            } else {
10373                text.to_uppercase()
10374            }
10375        })
10376    }
10377
10378    pub fn convert_to_upper_case(
10379        &mut self,
10380        _: &ConvertToUpperCase,
10381        window: &mut Window,
10382        cx: &mut Context<Self>,
10383    ) {
10384        self.manipulate_text(window, cx, |text| text.to_uppercase())
10385    }
10386
10387    pub fn convert_to_lower_case(
10388        &mut self,
10389        _: &ConvertToLowerCase,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        self.manipulate_text(window, cx, |text| text.to_lowercase())
10394    }
10395
10396    pub fn convert_to_title_case(
10397        &mut self,
10398        _: &ConvertToTitleCase,
10399        window: &mut Window,
10400        cx: &mut Context<Self>,
10401    ) {
10402        self.manipulate_text(window, cx, |text| {
10403            text.split('\n')
10404                .map(|line| line.to_case(Case::Title))
10405                .join("\n")
10406        })
10407    }
10408
10409    pub fn convert_to_snake_case(
10410        &mut self,
10411        _: &ConvertToSnakeCase,
10412        window: &mut Window,
10413        cx: &mut Context<Self>,
10414    ) {
10415        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10416    }
10417
10418    pub fn convert_to_kebab_case(
10419        &mut self,
10420        _: &ConvertToKebabCase,
10421        window: &mut Window,
10422        cx: &mut Context<Self>,
10423    ) {
10424        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10425    }
10426
10427    pub fn convert_to_upper_camel_case(
10428        &mut self,
10429        _: &ConvertToUpperCamelCase,
10430        window: &mut Window,
10431        cx: &mut Context<Self>,
10432    ) {
10433        self.manipulate_text(window, cx, |text| {
10434            text.split('\n')
10435                .map(|line| line.to_case(Case::UpperCamel))
10436                .join("\n")
10437        })
10438    }
10439
10440    pub fn convert_to_lower_camel_case(
10441        &mut self,
10442        _: &ConvertToLowerCamelCase,
10443        window: &mut Window,
10444        cx: &mut Context<Self>,
10445    ) {
10446        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10447    }
10448
10449    pub fn convert_to_opposite_case(
10450        &mut self,
10451        _: &ConvertToOppositeCase,
10452        window: &mut Window,
10453        cx: &mut Context<Self>,
10454    ) {
10455        self.manipulate_text(window, cx, |text| {
10456            text.chars()
10457                .fold(String::with_capacity(text.len()), |mut t, c| {
10458                    if c.is_uppercase() {
10459                        t.extend(c.to_lowercase());
10460                    } else {
10461                        t.extend(c.to_uppercase());
10462                    }
10463                    t
10464                })
10465        })
10466    }
10467
10468    pub fn convert_to_rot13(
10469        &mut self,
10470        _: &ConvertToRot13,
10471        window: &mut Window,
10472        cx: &mut Context<Self>,
10473    ) {
10474        self.manipulate_text(window, cx, |text| {
10475            text.chars()
10476                .map(|c| match c {
10477                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10478                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10479                    _ => c,
10480                })
10481                .collect()
10482        })
10483    }
10484
10485    pub fn convert_to_rot47(
10486        &mut self,
10487        _: &ConvertToRot47,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) {
10491        self.manipulate_text(window, cx, |text| {
10492            text.chars()
10493                .map(|c| {
10494                    let code_point = c as u32;
10495                    if code_point >= 33 && code_point <= 126 {
10496                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10497                    }
10498                    c
10499                })
10500                .collect()
10501        })
10502    }
10503
10504    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10505    where
10506        Fn: FnMut(&str) -> String,
10507    {
10508        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10509        let buffer = self.buffer.read(cx).snapshot(cx);
10510
10511        let mut new_selections = Vec::new();
10512        let mut edits = Vec::new();
10513        let mut selection_adjustment = 0i32;
10514
10515        for selection in self.selections.all::<usize>(cx) {
10516            let selection_is_empty = selection.is_empty();
10517
10518            let (start, end) = if selection_is_empty {
10519                let word_range = movement::surrounding_word(
10520                    &display_map,
10521                    selection.start.to_display_point(&display_map),
10522                );
10523                let start = word_range.start.to_offset(&display_map, Bias::Left);
10524                let end = word_range.end.to_offset(&display_map, Bias::Left);
10525                (start, end)
10526            } else {
10527                (selection.start, selection.end)
10528            };
10529
10530            let text = buffer.text_for_range(start..end).collect::<String>();
10531            let old_length = text.len() as i32;
10532            let text = callback(&text);
10533
10534            new_selections.push(Selection {
10535                start: (start as i32 - selection_adjustment) as usize,
10536                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10537                goal: SelectionGoal::None,
10538                ..selection
10539            });
10540
10541            selection_adjustment += old_length - text.len() as i32;
10542
10543            edits.push((start..end, text));
10544        }
10545
10546        self.transact(window, cx, |this, window, cx| {
10547            this.buffer.update(cx, |buffer, cx| {
10548                buffer.edit(edits, None, cx);
10549            });
10550
10551            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10552                s.select(new_selections);
10553            });
10554
10555            this.request_autoscroll(Autoscroll::fit(), cx);
10556        });
10557    }
10558
10559    pub fn duplicate(
10560        &mut self,
10561        upwards: bool,
10562        whole_lines: bool,
10563        window: &mut Window,
10564        cx: &mut Context<Self>,
10565    ) {
10566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10567
10568        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10569        let buffer = &display_map.buffer_snapshot;
10570        let selections = self.selections.all::<Point>(cx);
10571
10572        let mut edits = Vec::new();
10573        let mut selections_iter = selections.iter().peekable();
10574        while let Some(selection) = selections_iter.next() {
10575            let mut rows = selection.spanned_rows(false, &display_map);
10576            // duplicate line-wise
10577            if whole_lines || selection.start == selection.end {
10578                // Avoid duplicating the same lines twice.
10579                while let Some(next_selection) = selections_iter.peek() {
10580                    let next_rows = next_selection.spanned_rows(false, &display_map);
10581                    if next_rows.start < rows.end {
10582                        rows.end = next_rows.end;
10583                        selections_iter.next().unwrap();
10584                    } else {
10585                        break;
10586                    }
10587                }
10588
10589                // Copy the text from the selected row region and splice it either at the start
10590                // or end of the region.
10591                let start = Point::new(rows.start.0, 0);
10592                let end = Point::new(
10593                    rows.end.previous_row().0,
10594                    buffer.line_len(rows.end.previous_row()),
10595                );
10596                let text = buffer
10597                    .text_for_range(start..end)
10598                    .chain(Some("\n"))
10599                    .collect::<String>();
10600                let insert_location = if upwards {
10601                    Point::new(rows.end.0, 0)
10602                } else {
10603                    start
10604                };
10605                edits.push((insert_location..insert_location, text));
10606            } else {
10607                // duplicate character-wise
10608                let start = selection.start;
10609                let end = selection.end;
10610                let text = buffer.text_for_range(start..end).collect::<String>();
10611                edits.push((selection.end..selection.end, text));
10612            }
10613        }
10614
10615        self.transact(window, cx, |this, _, cx| {
10616            this.buffer.update(cx, |buffer, cx| {
10617                buffer.edit(edits, None, cx);
10618            });
10619
10620            this.request_autoscroll(Autoscroll::fit(), cx);
10621        });
10622    }
10623
10624    pub fn duplicate_line_up(
10625        &mut self,
10626        _: &DuplicateLineUp,
10627        window: &mut Window,
10628        cx: &mut Context<Self>,
10629    ) {
10630        self.duplicate(true, true, window, cx);
10631    }
10632
10633    pub fn duplicate_line_down(
10634        &mut self,
10635        _: &DuplicateLineDown,
10636        window: &mut Window,
10637        cx: &mut Context<Self>,
10638    ) {
10639        self.duplicate(false, true, window, cx);
10640    }
10641
10642    pub fn duplicate_selection(
10643        &mut self,
10644        _: &DuplicateSelection,
10645        window: &mut Window,
10646        cx: &mut Context<Self>,
10647    ) {
10648        self.duplicate(false, false, window, cx);
10649    }
10650
10651    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10652        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10653
10654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10655        let buffer = self.buffer.read(cx).snapshot(cx);
10656
10657        let mut edits = Vec::new();
10658        let mut unfold_ranges = Vec::new();
10659        let mut refold_creases = Vec::new();
10660
10661        let selections = self.selections.all::<Point>(cx);
10662        let mut selections = selections.iter().peekable();
10663        let mut contiguous_row_selections = Vec::new();
10664        let mut new_selections = Vec::new();
10665
10666        while let Some(selection) = selections.next() {
10667            // Find all the selections that span a contiguous row range
10668            let (start_row, end_row) = consume_contiguous_rows(
10669                &mut contiguous_row_selections,
10670                selection,
10671                &display_map,
10672                &mut selections,
10673            );
10674
10675            // Move the text spanned by the row range to be before the line preceding the row range
10676            if start_row.0 > 0 {
10677                let range_to_move = Point::new(
10678                    start_row.previous_row().0,
10679                    buffer.line_len(start_row.previous_row()),
10680                )
10681                    ..Point::new(
10682                        end_row.previous_row().0,
10683                        buffer.line_len(end_row.previous_row()),
10684                    );
10685                let insertion_point = display_map
10686                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10687                    .0;
10688
10689                // Don't move lines across excerpts
10690                if buffer
10691                    .excerpt_containing(insertion_point..range_to_move.end)
10692                    .is_some()
10693                {
10694                    let text = buffer
10695                        .text_for_range(range_to_move.clone())
10696                        .flat_map(|s| s.chars())
10697                        .skip(1)
10698                        .chain(['\n'])
10699                        .collect::<String>();
10700
10701                    edits.push((
10702                        buffer.anchor_after(range_to_move.start)
10703                            ..buffer.anchor_before(range_to_move.end),
10704                        String::new(),
10705                    ));
10706                    let insertion_anchor = buffer.anchor_after(insertion_point);
10707                    edits.push((insertion_anchor..insertion_anchor, text));
10708
10709                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10710
10711                    // Move selections up
10712                    new_selections.extend(contiguous_row_selections.drain(..).map(
10713                        |mut selection| {
10714                            selection.start.row -= row_delta;
10715                            selection.end.row -= row_delta;
10716                            selection
10717                        },
10718                    ));
10719
10720                    // Move folds up
10721                    unfold_ranges.push(range_to_move.clone());
10722                    for fold in display_map.folds_in_range(
10723                        buffer.anchor_before(range_to_move.start)
10724                            ..buffer.anchor_after(range_to_move.end),
10725                    ) {
10726                        let mut start = fold.range.start.to_point(&buffer);
10727                        let mut end = fold.range.end.to_point(&buffer);
10728                        start.row -= row_delta;
10729                        end.row -= row_delta;
10730                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10731                    }
10732                }
10733            }
10734
10735            // If we didn't move line(s), preserve the existing selections
10736            new_selections.append(&mut contiguous_row_selections);
10737        }
10738
10739        self.transact(window, cx, |this, window, cx| {
10740            this.unfold_ranges(&unfold_ranges, true, true, cx);
10741            this.buffer.update(cx, |buffer, cx| {
10742                for (range, text) in edits {
10743                    buffer.edit([(range, text)], None, cx);
10744                }
10745            });
10746            this.fold_creases(refold_creases, true, window, cx);
10747            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10748                s.select(new_selections);
10749            })
10750        });
10751    }
10752
10753    pub fn move_line_down(
10754        &mut self,
10755        _: &MoveLineDown,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10760
10761        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10762        let buffer = self.buffer.read(cx).snapshot(cx);
10763
10764        let mut edits = Vec::new();
10765        let mut unfold_ranges = Vec::new();
10766        let mut refold_creases = Vec::new();
10767
10768        let selections = self.selections.all::<Point>(cx);
10769        let mut selections = selections.iter().peekable();
10770        let mut contiguous_row_selections = Vec::new();
10771        let mut new_selections = Vec::new();
10772
10773        while let Some(selection) = selections.next() {
10774            // Find all the selections that span a contiguous row range
10775            let (start_row, end_row) = consume_contiguous_rows(
10776                &mut contiguous_row_selections,
10777                selection,
10778                &display_map,
10779                &mut selections,
10780            );
10781
10782            // Move the text spanned by the row range to be after the last line of the row range
10783            if end_row.0 <= buffer.max_point().row {
10784                let range_to_move =
10785                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10786                let insertion_point = display_map
10787                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10788                    .0;
10789
10790                // Don't move lines across excerpt boundaries
10791                if buffer
10792                    .excerpt_containing(range_to_move.start..insertion_point)
10793                    .is_some()
10794                {
10795                    let mut text = String::from("\n");
10796                    text.extend(buffer.text_for_range(range_to_move.clone()));
10797                    text.pop(); // Drop trailing newline
10798                    edits.push((
10799                        buffer.anchor_after(range_to_move.start)
10800                            ..buffer.anchor_before(range_to_move.end),
10801                        String::new(),
10802                    ));
10803                    let insertion_anchor = buffer.anchor_after(insertion_point);
10804                    edits.push((insertion_anchor..insertion_anchor, text));
10805
10806                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10807
10808                    // Move selections down
10809                    new_selections.extend(contiguous_row_selections.drain(..).map(
10810                        |mut selection| {
10811                            selection.start.row += row_delta;
10812                            selection.end.row += row_delta;
10813                            selection
10814                        },
10815                    ));
10816
10817                    // Move folds down
10818                    unfold_ranges.push(range_to_move.clone());
10819                    for fold in display_map.folds_in_range(
10820                        buffer.anchor_before(range_to_move.start)
10821                            ..buffer.anchor_after(range_to_move.end),
10822                    ) {
10823                        let mut start = fold.range.start.to_point(&buffer);
10824                        let mut end = fold.range.end.to_point(&buffer);
10825                        start.row += row_delta;
10826                        end.row += row_delta;
10827                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10828                    }
10829                }
10830            }
10831
10832            // If we didn't move line(s), preserve the existing selections
10833            new_selections.append(&mut contiguous_row_selections);
10834        }
10835
10836        self.transact(window, cx, |this, window, cx| {
10837            this.unfold_ranges(&unfold_ranges, true, true, cx);
10838            this.buffer.update(cx, |buffer, cx| {
10839                for (range, text) in edits {
10840                    buffer.edit([(range, text)], None, cx);
10841                }
10842            });
10843            this.fold_creases(refold_creases, true, window, cx);
10844            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10845                s.select(new_selections)
10846            });
10847        });
10848    }
10849
10850    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10851        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10852        let text_layout_details = &self.text_layout_details(window);
10853        self.transact(window, cx, |this, window, cx| {
10854            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10855                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10856                s.move_with(|display_map, selection| {
10857                    if !selection.is_empty() {
10858                        return;
10859                    }
10860
10861                    let mut head = selection.head();
10862                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10863                    if head.column() == display_map.line_len(head.row()) {
10864                        transpose_offset = display_map
10865                            .buffer_snapshot
10866                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10867                    }
10868
10869                    if transpose_offset == 0 {
10870                        return;
10871                    }
10872
10873                    *head.column_mut() += 1;
10874                    head = display_map.clip_point(head, Bias::Right);
10875                    let goal = SelectionGoal::HorizontalPosition(
10876                        display_map
10877                            .x_for_display_point(head, text_layout_details)
10878                            .into(),
10879                    );
10880                    selection.collapse_to(head, goal);
10881
10882                    let transpose_start = display_map
10883                        .buffer_snapshot
10884                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10885                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10886                        let transpose_end = display_map
10887                            .buffer_snapshot
10888                            .clip_offset(transpose_offset + 1, Bias::Right);
10889                        if let Some(ch) =
10890                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10891                        {
10892                            edits.push((transpose_start..transpose_offset, String::new()));
10893                            edits.push((transpose_end..transpose_end, ch.to_string()));
10894                        }
10895                    }
10896                });
10897                edits
10898            });
10899            this.buffer
10900                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10901            let selections = this.selections.all::<usize>(cx);
10902            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10903                s.select(selections);
10904            });
10905        });
10906    }
10907
10908    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10909        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10910        self.rewrap_impl(RewrapOptions::default(), cx)
10911    }
10912
10913    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10914        let buffer = self.buffer.read(cx).snapshot(cx);
10915        let selections = self.selections.all::<Point>(cx);
10916
10917        // Shrink and split selections to respect paragraph boundaries.
10918        let ranges = selections.into_iter().flat_map(|selection| {
10919            let language_settings = buffer.language_settings_at(selection.head(), cx);
10920            let language_scope = buffer.language_scope_at(selection.head());
10921
10922            let Some(start_row) = (selection.start.row..=selection.end.row)
10923                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
10924            else {
10925                return vec![];
10926            };
10927            let Some(end_row) = (selection.start.row..=selection.end.row)
10928                .rev()
10929                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
10930            else {
10931                return vec![];
10932            };
10933
10934            let mut row = start_row;
10935            let mut ranges = Vec::new();
10936            while let Some(blank_row) =
10937                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
10938            {
10939                let next_paragraph_start = (blank_row + 1..=end_row)
10940                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
10941                    .unwrap();
10942                ranges.push((
10943                    language_settings.clone(),
10944                    language_scope.clone(),
10945                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
10946                ));
10947                row = next_paragraph_start;
10948            }
10949            ranges.push((
10950                language_settings.clone(),
10951                language_scope.clone(),
10952                Point::new(row, 0)..Point::new(end_row, 0),
10953            ));
10954
10955            ranges
10956        });
10957
10958        let mut edits = Vec::new();
10959        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10960
10961        for (language_settings, language_scope, range) in ranges {
10962            let mut start_row = range.start.row;
10963            let mut end_row = range.end.row;
10964
10965            // Skip selections that overlap with a range that has already been rewrapped.
10966            let selection_range = start_row..end_row;
10967            if rewrapped_row_ranges
10968                .iter()
10969                .any(|range| range.overlaps(&selection_range))
10970            {
10971                continue;
10972            }
10973
10974            let tab_size = language_settings.tab_size;
10975
10976            // Since not all lines in the selection may be at the same indent
10977            // level, choose the indent size that is the most common between all
10978            // of the lines.
10979            //
10980            // If there is a tie, we use the deepest indent.
10981            let (indent_size, indent_end) = {
10982                let mut indent_size_occurrences = HashMap::default();
10983                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10984
10985                for row in start_row..=end_row {
10986                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10987                    rows_by_indent_size.entry(indent).or_default().push(row);
10988                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10989                }
10990
10991                let indent_size = indent_size_occurrences
10992                    .into_iter()
10993                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10994                    .map(|(indent, _)| indent)
10995                    .unwrap_or_default();
10996                let row = rows_by_indent_size[&indent_size][0];
10997                let indent_end = Point::new(row, indent_size.len);
10998
10999                (indent_size, indent_end)
11000            };
11001
11002            let mut line_prefix = indent_size.chars().collect::<String>();
11003
11004            let mut inside_comment = false;
11005            if let Some(comment_prefix) = language_scope.and_then(|language| {
11006                language
11007                    .line_comment_prefixes()
11008                    .iter()
11009                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11010                    .cloned()
11011            }) {
11012                line_prefix.push_str(&comment_prefix);
11013                inside_comment = true;
11014            }
11015
11016            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11017                RewrapBehavior::InComments => inside_comment,
11018                RewrapBehavior::InSelections => !range.is_empty(),
11019                RewrapBehavior::Anywhere => true,
11020            };
11021
11022            let should_rewrap = options.override_language_settings
11023                || allow_rewrap_based_on_language
11024                || self.hard_wrap.is_some();
11025            if !should_rewrap {
11026                continue;
11027            }
11028
11029            if range.is_empty() {
11030                'expand_upwards: while start_row > 0 {
11031                    let prev_row = start_row - 1;
11032                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11033                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11034                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11035                    {
11036                        start_row = prev_row;
11037                    } else {
11038                        break 'expand_upwards;
11039                    }
11040                }
11041
11042                'expand_downwards: while end_row < buffer.max_point().row {
11043                    let next_row = end_row + 1;
11044                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11045                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11046                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11047                    {
11048                        end_row = next_row;
11049                    } else {
11050                        break 'expand_downwards;
11051                    }
11052                }
11053            }
11054
11055            let start = Point::new(start_row, 0);
11056            let start_offset = start.to_offset(&buffer);
11057            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11058            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11059            let Some(lines_without_prefixes) = selection_text
11060                .lines()
11061                .map(|line| {
11062                    line.strip_prefix(&line_prefix)
11063                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11064                        .with_context(|| {
11065                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11066                        })
11067                })
11068                .collect::<Result<Vec<_>, _>>()
11069                .log_err()
11070            else {
11071                continue;
11072            };
11073
11074            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11075                buffer
11076                    .language_settings_at(Point::new(start_row, 0), cx)
11077                    .preferred_line_length as usize
11078            });
11079            let wrapped_text = wrap_with_prefix(
11080                line_prefix,
11081                lines_without_prefixes.join("\n"),
11082                wrap_column,
11083                tab_size,
11084                options.preserve_existing_whitespace,
11085            );
11086
11087            // TODO: should always use char-based diff while still supporting cursor behavior that
11088            // matches vim.
11089            let mut diff_options = DiffOptions::default();
11090            if options.override_language_settings {
11091                diff_options.max_word_diff_len = 0;
11092                diff_options.max_word_diff_line_count = 0;
11093            } else {
11094                diff_options.max_word_diff_len = usize::MAX;
11095                diff_options.max_word_diff_line_count = usize::MAX;
11096            }
11097
11098            for (old_range, new_text) in
11099                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11100            {
11101                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11102                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11103                edits.push((edit_start..edit_end, new_text));
11104            }
11105
11106            rewrapped_row_ranges.push(start_row..=end_row);
11107        }
11108
11109        self.buffer
11110            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11111    }
11112
11113    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11114        let mut text = String::new();
11115        let buffer = self.buffer.read(cx).snapshot(cx);
11116        let mut selections = self.selections.all::<Point>(cx);
11117        let mut clipboard_selections = Vec::with_capacity(selections.len());
11118        {
11119            let max_point = buffer.max_point();
11120            let mut is_first = true;
11121            for selection in &mut selections {
11122                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11123                if is_entire_line {
11124                    selection.start = Point::new(selection.start.row, 0);
11125                    if !selection.is_empty() && selection.end.column == 0 {
11126                        selection.end = cmp::min(max_point, selection.end);
11127                    } else {
11128                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11129                    }
11130                    selection.goal = SelectionGoal::None;
11131                }
11132                if is_first {
11133                    is_first = false;
11134                } else {
11135                    text += "\n";
11136                }
11137                let mut len = 0;
11138                for chunk in buffer.text_for_range(selection.start..selection.end) {
11139                    text.push_str(chunk);
11140                    len += chunk.len();
11141                }
11142                clipboard_selections.push(ClipboardSelection {
11143                    len,
11144                    is_entire_line,
11145                    first_line_indent: buffer
11146                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11147                        .len,
11148                });
11149            }
11150        }
11151
11152        self.transact(window, cx, |this, window, cx| {
11153            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11154                s.select(selections);
11155            });
11156            this.insert("", window, cx);
11157        });
11158        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11159    }
11160
11161    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11162        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11163        let item = self.cut_common(window, cx);
11164        cx.write_to_clipboard(item);
11165    }
11166
11167    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11168        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11169        self.change_selections(None, window, cx, |s| {
11170            s.move_with(|snapshot, sel| {
11171                if sel.is_empty() {
11172                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11173                }
11174            });
11175        });
11176        let item = self.cut_common(window, cx);
11177        cx.set_global(KillRing(item))
11178    }
11179
11180    pub fn kill_ring_yank(
11181        &mut self,
11182        _: &KillRingYank,
11183        window: &mut Window,
11184        cx: &mut Context<Self>,
11185    ) {
11186        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11187        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11188            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11189                (kill_ring.text().to_string(), kill_ring.metadata_json())
11190            } else {
11191                return;
11192            }
11193        } else {
11194            return;
11195        };
11196        self.do_paste(&text, metadata, false, window, cx);
11197    }
11198
11199    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11200        self.do_copy(true, cx);
11201    }
11202
11203    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11204        self.do_copy(false, cx);
11205    }
11206
11207    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11208        let selections = self.selections.all::<Point>(cx);
11209        let buffer = self.buffer.read(cx).read(cx);
11210        let mut text = String::new();
11211
11212        let mut clipboard_selections = Vec::with_capacity(selections.len());
11213        {
11214            let max_point = buffer.max_point();
11215            let mut is_first = true;
11216            for selection in &selections {
11217                let mut start = selection.start;
11218                let mut end = selection.end;
11219                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11220                if is_entire_line {
11221                    start = Point::new(start.row, 0);
11222                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11223                }
11224
11225                let mut trimmed_selections = Vec::new();
11226                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11227                    let row = MultiBufferRow(start.row);
11228                    let first_indent = buffer.indent_size_for_line(row);
11229                    if first_indent.len == 0 || start.column > first_indent.len {
11230                        trimmed_selections.push(start..end);
11231                    } else {
11232                        trimmed_selections.push(
11233                            Point::new(row.0, first_indent.len)
11234                                ..Point::new(row.0, buffer.line_len(row)),
11235                        );
11236                        for row in start.row + 1..=end.row {
11237                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11238                            if row == end.row {
11239                                line_len = end.column;
11240                            }
11241                            if line_len == 0 {
11242                                trimmed_selections
11243                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11244                                continue;
11245                            }
11246                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11247                            if row_indent_size.len >= first_indent.len {
11248                                trimmed_selections.push(
11249                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11250                                );
11251                            } else {
11252                                trimmed_selections.clear();
11253                                trimmed_selections.push(start..end);
11254                                break;
11255                            }
11256                        }
11257                    }
11258                } else {
11259                    trimmed_selections.push(start..end);
11260                }
11261
11262                for trimmed_range in trimmed_selections {
11263                    if is_first {
11264                        is_first = false;
11265                    } else {
11266                        text += "\n";
11267                    }
11268                    let mut len = 0;
11269                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11270                        text.push_str(chunk);
11271                        len += chunk.len();
11272                    }
11273                    clipboard_selections.push(ClipboardSelection {
11274                        len,
11275                        is_entire_line,
11276                        first_line_indent: buffer
11277                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11278                            .len,
11279                    });
11280                }
11281            }
11282        }
11283
11284        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11285            text,
11286            clipboard_selections,
11287        ));
11288    }
11289
11290    pub fn do_paste(
11291        &mut self,
11292        text: &String,
11293        clipboard_selections: Option<Vec<ClipboardSelection>>,
11294        handle_entire_lines: bool,
11295        window: &mut Window,
11296        cx: &mut Context<Self>,
11297    ) {
11298        if self.read_only(cx) {
11299            return;
11300        }
11301
11302        let clipboard_text = Cow::Borrowed(text);
11303
11304        self.transact(window, cx, |this, window, cx| {
11305            if let Some(mut clipboard_selections) = clipboard_selections {
11306                let old_selections = this.selections.all::<usize>(cx);
11307                let all_selections_were_entire_line =
11308                    clipboard_selections.iter().all(|s| s.is_entire_line);
11309                let first_selection_indent_column =
11310                    clipboard_selections.first().map(|s| s.first_line_indent);
11311                if clipboard_selections.len() != old_selections.len() {
11312                    clipboard_selections.drain(..);
11313                }
11314                let cursor_offset = this.selections.last::<usize>(cx).head();
11315                let mut auto_indent_on_paste = true;
11316
11317                this.buffer.update(cx, |buffer, cx| {
11318                    let snapshot = buffer.read(cx);
11319                    auto_indent_on_paste = snapshot
11320                        .language_settings_at(cursor_offset, cx)
11321                        .auto_indent_on_paste;
11322
11323                    let mut start_offset = 0;
11324                    let mut edits = Vec::new();
11325                    let mut original_indent_columns = Vec::new();
11326                    for (ix, selection) in old_selections.iter().enumerate() {
11327                        let to_insert;
11328                        let entire_line;
11329                        let original_indent_column;
11330                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11331                            let end_offset = start_offset + clipboard_selection.len;
11332                            to_insert = &clipboard_text[start_offset..end_offset];
11333                            entire_line = clipboard_selection.is_entire_line;
11334                            start_offset = end_offset + 1;
11335                            original_indent_column = Some(clipboard_selection.first_line_indent);
11336                        } else {
11337                            to_insert = clipboard_text.as_str();
11338                            entire_line = all_selections_were_entire_line;
11339                            original_indent_column = first_selection_indent_column
11340                        }
11341
11342                        // If the corresponding selection was empty when this slice of the
11343                        // clipboard text was written, then the entire line containing the
11344                        // selection was copied. If this selection is also currently empty,
11345                        // then paste the line before the current line of the buffer.
11346                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11347                            let column = selection.start.to_point(&snapshot).column as usize;
11348                            let line_start = selection.start - column;
11349                            line_start..line_start
11350                        } else {
11351                            selection.range()
11352                        };
11353
11354                        edits.push((range, to_insert));
11355                        original_indent_columns.push(original_indent_column);
11356                    }
11357                    drop(snapshot);
11358
11359                    buffer.edit(
11360                        edits,
11361                        if auto_indent_on_paste {
11362                            Some(AutoindentMode::Block {
11363                                original_indent_columns,
11364                            })
11365                        } else {
11366                            None
11367                        },
11368                        cx,
11369                    );
11370                });
11371
11372                let selections = this.selections.all::<usize>(cx);
11373                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11374                    s.select(selections)
11375                });
11376            } else {
11377                this.insert(&clipboard_text, window, cx);
11378            }
11379        });
11380    }
11381
11382    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11383        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11384        if let Some(item) = cx.read_from_clipboard() {
11385            let entries = item.entries();
11386
11387            match entries.first() {
11388                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11389                // of all the pasted entries.
11390                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11391                    .do_paste(
11392                        clipboard_string.text(),
11393                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11394                        true,
11395                        window,
11396                        cx,
11397                    ),
11398                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11399            }
11400        }
11401    }
11402
11403    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11404        if self.read_only(cx) {
11405            return;
11406        }
11407
11408        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11409
11410        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11411            if let Some((selections, _)) =
11412                self.selection_history.transaction(transaction_id).cloned()
11413            {
11414                self.change_selections(None, window, cx, |s| {
11415                    s.select_anchors(selections.to_vec());
11416                });
11417            } else {
11418                log::error!(
11419                    "No entry in selection_history found for undo. \
11420                     This may correspond to a bug where undo does not update the selection. \
11421                     If this is occurring, please add details to \
11422                     https://github.com/zed-industries/zed/issues/22692"
11423                );
11424            }
11425            self.request_autoscroll(Autoscroll::fit(), cx);
11426            self.unmark_text(window, cx);
11427            self.refresh_inline_completion(true, false, window, cx);
11428            cx.emit(EditorEvent::Edited { transaction_id });
11429            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11430        }
11431    }
11432
11433    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11434        if self.read_only(cx) {
11435            return;
11436        }
11437
11438        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11439
11440        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11441            if let Some((_, Some(selections))) =
11442                self.selection_history.transaction(transaction_id).cloned()
11443            {
11444                self.change_selections(None, window, cx, |s| {
11445                    s.select_anchors(selections.to_vec());
11446                });
11447            } else {
11448                log::error!(
11449                    "No entry in selection_history found for redo. \
11450                     This may correspond to a bug where undo does not update the selection. \
11451                     If this is occurring, please add details to \
11452                     https://github.com/zed-industries/zed/issues/22692"
11453                );
11454            }
11455            self.request_autoscroll(Autoscroll::fit(), cx);
11456            self.unmark_text(window, cx);
11457            self.refresh_inline_completion(true, false, window, cx);
11458            cx.emit(EditorEvent::Edited { transaction_id });
11459        }
11460    }
11461
11462    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11463        self.buffer
11464            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11465    }
11466
11467    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11468        self.buffer
11469            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11470    }
11471
11472    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11474        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11475            s.move_with(|map, selection| {
11476                let cursor = if selection.is_empty() {
11477                    movement::left(map, selection.start)
11478                } else {
11479                    selection.start
11480                };
11481                selection.collapse_to(cursor, SelectionGoal::None);
11482            });
11483        })
11484    }
11485
11486    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11487        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11488        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11489            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11490        })
11491    }
11492
11493    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11494        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11495        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11496            s.move_with(|map, selection| {
11497                let cursor = if selection.is_empty() {
11498                    movement::right(map, selection.end)
11499                } else {
11500                    selection.end
11501                };
11502                selection.collapse_to(cursor, SelectionGoal::None)
11503            });
11504        })
11505    }
11506
11507    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11508        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11509        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11510            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11511        })
11512    }
11513
11514    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11515        if self.take_rename(true, window, cx).is_some() {
11516            return;
11517        }
11518
11519        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11520            cx.propagate();
11521            return;
11522        }
11523
11524        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11525
11526        let text_layout_details = &self.text_layout_details(window);
11527        let selection_count = self.selections.count();
11528        let first_selection = self.selections.first_anchor();
11529
11530        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11531            s.move_with(|map, selection| {
11532                if !selection.is_empty() {
11533                    selection.goal = SelectionGoal::None;
11534                }
11535                let (cursor, goal) = movement::up(
11536                    map,
11537                    selection.start,
11538                    selection.goal,
11539                    false,
11540                    text_layout_details,
11541                );
11542                selection.collapse_to(cursor, goal);
11543            });
11544        });
11545
11546        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11547        {
11548            cx.propagate();
11549        }
11550    }
11551
11552    pub fn move_up_by_lines(
11553        &mut self,
11554        action: &MoveUpByLines,
11555        window: &mut Window,
11556        cx: &mut Context<Self>,
11557    ) {
11558        if self.take_rename(true, window, cx).is_some() {
11559            return;
11560        }
11561
11562        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11563            cx.propagate();
11564            return;
11565        }
11566
11567        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11568
11569        let text_layout_details = &self.text_layout_details(window);
11570
11571        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11572            s.move_with(|map, selection| {
11573                if !selection.is_empty() {
11574                    selection.goal = SelectionGoal::None;
11575                }
11576                let (cursor, goal) = movement::up_by_rows(
11577                    map,
11578                    selection.start,
11579                    action.lines,
11580                    selection.goal,
11581                    false,
11582                    text_layout_details,
11583                );
11584                selection.collapse_to(cursor, goal);
11585            });
11586        })
11587    }
11588
11589    pub fn move_down_by_lines(
11590        &mut self,
11591        action: &MoveDownByLines,
11592        window: &mut Window,
11593        cx: &mut Context<Self>,
11594    ) {
11595        if self.take_rename(true, window, cx).is_some() {
11596            return;
11597        }
11598
11599        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11600            cx.propagate();
11601            return;
11602        }
11603
11604        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11605
11606        let text_layout_details = &self.text_layout_details(window);
11607
11608        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11609            s.move_with(|map, selection| {
11610                if !selection.is_empty() {
11611                    selection.goal = SelectionGoal::None;
11612                }
11613                let (cursor, goal) = movement::down_by_rows(
11614                    map,
11615                    selection.start,
11616                    action.lines,
11617                    selection.goal,
11618                    false,
11619                    text_layout_details,
11620                );
11621                selection.collapse_to(cursor, goal);
11622            });
11623        })
11624    }
11625
11626    pub fn select_down_by_lines(
11627        &mut self,
11628        action: &SelectDownByLines,
11629        window: &mut Window,
11630        cx: &mut Context<Self>,
11631    ) {
11632        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11633        let text_layout_details = &self.text_layout_details(window);
11634        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11635            s.move_heads_with(|map, head, goal| {
11636                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11637            })
11638        })
11639    }
11640
11641    pub fn select_up_by_lines(
11642        &mut self,
11643        action: &SelectUpByLines,
11644        window: &mut Window,
11645        cx: &mut Context<Self>,
11646    ) {
11647        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11648        let text_layout_details = &self.text_layout_details(window);
11649        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11650            s.move_heads_with(|map, head, goal| {
11651                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11652            })
11653        })
11654    }
11655
11656    pub fn select_page_up(
11657        &mut self,
11658        _: &SelectPageUp,
11659        window: &mut Window,
11660        cx: &mut Context<Self>,
11661    ) {
11662        let Some(row_count) = self.visible_row_count() else {
11663            return;
11664        };
11665
11666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11667
11668        let text_layout_details = &self.text_layout_details(window);
11669
11670        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11671            s.move_heads_with(|map, head, goal| {
11672                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11673            })
11674        })
11675    }
11676
11677    pub fn move_page_up(
11678        &mut self,
11679        action: &MovePageUp,
11680        window: &mut Window,
11681        cx: &mut Context<Self>,
11682    ) {
11683        if self.take_rename(true, window, cx).is_some() {
11684            return;
11685        }
11686
11687        if self
11688            .context_menu
11689            .borrow_mut()
11690            .as_mut()
11691            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11692            .unwrap_or(false)
11693        {
11694            return;
11695        }
11696
11697        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11698            cx.propagate();
11699            return;
11700        }
11701
11702        let Some(row_count) = self.visible_row_count() else {
11703            return;
11704        };
11705
11706        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11707
11708        let autoscroll = if action.center_cursor {
11709            Autoscroll::center()
11710        } else {
11711            Autoscroll::fit()
11712        };
11713
11714        let text_layout_details = &self.text_layout_details(window);
11715
11716        self.change_selections(Some(autoscroll), window, cx, |s| {
11717            s.move_with(|map, selection| {
11718                if !selection.is_empty() {
11719                    selection.goal = SelectionGoal::None;
11720                }
11721                let (cursor, goal) = movement::up_by_rows(
11722                    map,
11723                    selection.end,
11724                    row_count,
11725                    selection.goal,
11726                    false,
11727                    text_layout_details,
11728                );
11729                selection.collapse_to(cursor, goal);
11730            });
11731        });
11732    }
11733
11734    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11735        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11736        let text_layout_details = &self.text_layout_details(window);
11737        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11738            s.move_heads_with(|map, head, goal| {
11739                movement::up(map, head, goal, false, text_layout_details)
11740            })
11741        })
11742    }
11743
11744    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11745        self.take_rename(true, window, cx);
11746
11747        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11748            cx.propagate();
11749            return;
11750        }
11751
11752        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11753
11754        let text_layout_details = &self.text_layout_details(window);
11755        let selection_count = self.selections.count();
11756        let first_selection = self.selections.first_anchor();
11757
11758        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11759            s.move_with(|map, selection| {
11760                if !selection.is_empty() {
11761                    selection.goal = SelectionGoal::None;
11762                }
11763                let (cursor, goal) = movement::down(
11764                    map,
11765                    selection.end,
11766                    selection.goal,
11767                    false,
11768                    text_layout_details,
11769                );
11770                selection.collapse_to(cursor, goal);
11771            });
11772        });
11773
11774        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11775        {
11776            cx.propagate();
11777        }
11778    }
11779
11780    pub fn select_page_down(
11781        &mut self,
11782        _: &SelectPageDown,
11783        window: &mut Window,
11784        cx: &mut Context<Self>,
11785    ) {
11786        let Some(row_count) = self.visible_row_count() else {
11787            return;
11788        };
11789
11790        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11791
11792        let text_layout_details = &self.text_layout_details(window);
11793
11794        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11795            s.move_heads_with(|map, head, goal| {
11796                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11797            })
11798        })
11799    }
11800
11801    pub fn move_page_down(
11802        &mut self,
11803        action: &MovePageDown,
11804        window: &mut Window,
11805        cx: &mut Context<Self>,
11806    ) {
11807        if self.take_rename(true, window, cx).is_some() {
11808            return;
11809        }
11810
11811        if self
11812            .context_menu
11813            .borrow_mut()
11814            .as_mut()
11815            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11816            .unwrap_or(false)
11817        {
11818            return;
11819        }
11820
11821        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11822            cx.propagate();
11823            return;
11824        }
11825
11826        let Some(row_count) = self.visible_row_count() else {
11827            return;
11828        };
11829
11830        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11831
11832        let autoscroll = if action.center_cursor {
11833            Autoscroll::center()
11834        } else {
11835            Autoscroll::fit()
11836        };
11837
11838        let text_layout_details = &self.text_layout_details(window);
11839        self.change_selections(Some(autoscroll), window, cx, |s| {
11840            s.move_with(|map, selection| {
11841                if !selection.is_empty() {
11842                    selection.goal = SelectionGoal::None;
11843                }
11844                let (cursor, goal) = movement::down_by_rows(
11845                    map,
11846                    selection.end,
11847                    row_count,
11848                    selection.goal,
11849                    false,
11850                    text_layout_details,
11851                );
11852                selection.collapse_to(cursor, goal);
11853            });
11854        });
11855    }
11856
11857    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11858        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11859        let text_layout_details = &self.text_layout_details(window);
11860        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11861            s.move_heads_with(|map, head, goal| {
11862                movement::down(map, head, goal, false, text_layout_details)
11863            })
11864        });
11865    }
11866
11867    pub fn context_menu_first(
11868        &mut self,
11869        _: &ContextMenuFirst,
11870        window: &mut Window,
11871        cx: &mut Context<Self>,
11872    ) {
11873        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11874            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11875        }
11876    }
11877
11878    pub fn context_menu_prev(
11879        &mut self,
11880        _: &ContextMenuPrevious,
11881        window: &mut Window,
11882        cx: &mut Context<Self>,
11883    ) {
11884        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11885            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11886        }
11887    }
11888
11889    pub fn context_menu_next(
11890        &mut self,
11891        _: &ContextMenuNext,
11892        window: &mut Window,
11893        cx: &mut Context<Self>,
11894    ) {
11895        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11896            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11897        }
11898    }
11899
11900    pub fn context_menu_last(
11901        &mut self,
11902        _: &ContextMenuLast,
11903        window: &mut Window,
11904        cx: &mut Context<Self>,
11905    ) {
11906        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11907            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11908        }
11909    }
11910
11911    pub fn move_to_previous_word_start(
11912        &mut self,
11913        _: &MoveToPreviousWordStart,
11914        window: &mut Window,
11915        cx: &mut Context<Self>,
11916    ) {
11917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11918        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11919            s.move_cursors_with(|map, head, _| {
11920                (
11921                    movement::previous_word_start(map, head),
11922                    SelectionGoal::None,
11923                )
11924            });
11925        })
11926    }
11927
11928    pub fn move_to_previous_subword_start(
11929        &mut self,
11930        _: &MoveToPreviousSubwordStart,
11931        window: &mut Window,
11932        cx: &mut Context<Self>,
11933    ) {
11934        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11935        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11936            s.move_cursors_with(|map, head, _| {
11937                (
11938                    movement::previous_subword_start(map, head),
11939                    SelectionGoal::None,
11940                )
11941            });
11942        })
11943    }
11944
11945    pub fn select_to_previous_word_start(
11946        &mut self,
11947        _: &SelectToPreviousWordStart,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11952        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11953            s.move_heads_with(|map, head, _| {
11954                (
11955                    movement::previous_word_start(map, head),
11956                    SelectionGoal::None,
11957                )
11958            });
11959        })
11960    }
11961
11962    pub fn select_to_previous_subword_start(
11963        &mut self,
11964        _: &SelectToPreviousSubwordStart,
11965        window: &mut Window,
11966        cx: &mut Context<Self>,
11967    ) {
11968        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11969        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11970            s.move_heads_with(|map, head, _| {
11971                (
11972                    movement::previous_subword_start(map, head),
11973                    SelectionGoal::None,
11974                )
11975            });
11976        })
11977    }
11978
11979    pub fn delete_to_previous_word_start(
11980        &mut self,
11981        action: &DeleteToPreviousWordStart,
11982        window: &mut Window,
11983        cx: &mut Context<Self>,
11984    ) {
11985        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11986        self.transact(window, cx, |this, window, cx| {
11987            this.select_autoclose_pair(window, cx);
11988            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11989                s.move_with(|map, selection| {
11990                    if selection.is_empty() {
11991                        let cursor = if action.ignore_newlines {
11992                            movement::previous_word_start(map, selection.head())
11993                        } else {
11994                            movement::previous_word_start_or_newline(map, selection.head())
11995                        };
11996                        selection.set_head(cursor, SelectionGoal::None);
11997                    }
11998                });
11999            });
12000            this.insert("", window, cx);
12001        });
12002    }
12003
12004    pub fn delete_to_previous_subword_start(
12005        &mut self,
12006        _: &DeleteToPreviousSubwordStart,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12011        self.transact(window, cx, |this, window, cx| {
12012            this.select_autoclose_pair(window, cx);
12013            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12014                s.move_with(|map, selection| {
12015                    if selection.is_empty() {
12016                        let cursor = movement::previous_subword_start(map, selection.head());
12017                        selection.set_head(cursor, SelectionGoal::None);
12018                    }
12019                });
12020            });
12021            this.insert("", window, cx);
12022        });
12023    }
12024
12025    pub fn move_to_next_word_end(
12026        &mut self,
12027        _: &MoveToNextWordEnd,
12028        window: &mut Window,
12029        cx: &mut Context<Self>,
12030    ) {
12031        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12032        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12033            s.move_cursors_with(|map, head, _| {
12034                (movement::next_word_end(map, head), SelectionGoal::None)
12035            });
12036        })
12037    }
12038
12039    pub fn move_to_next_subword_end(
12040        &mut self,
12041        _: &MoveToNextSubwordEnd,
12042        window: &mut Window,
12043        cx: &mut Context<Self>,
12044    ) {
12045        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12046        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12047            s.move_cursors_with(|map, head, _| {
12048                (movement::next_subword_end(map, head), SelectionGoal::None)
12049            });
12050        })
12051    }
12052
12053    pub fn select_to_next_word_end(
12054        &mut self,
12055        _: &SelectToNextWordEnd,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058    ) {
12059        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12060        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12061            s.move_heads_with(|map, head, _| {
12062                (movement::next_word_end(map, head), SelectionGoal::None)
12063            });
12064        })
12065    }
12066
12067    pub fn select_to_next_subword_end(
12068        &mut self,
12069        _: &SelectToNextSubwordEnd,
12070        window: &mut Window,
12071        cx: &mut Context<Self>,
12072    ) {
12073        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12074        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12075            s.move_heads_with(|map, head, _| {
12076                (movement::next_subword_end(map, head), SelectionGoal::None)
12077            });
12078        })
12079    }
12080
12081    pub fn delete_to_next_word_end(
12082        &mut self,
12083        action: &DeleteToNextWordEnd,
12084        window: &mut Window,
12085        cx: &mut Context<Self>,
12086    ) {
12087        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12088        self.transact(window, cx, |this, window, cx| {
12089            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12090                s.move_with(|map, selection| {
12091                    if selection.is_empty() {
12092                        let cursor = if action.ignore_newlines {
12093                            movement::next_word_end(map, selection.head())
12094                        } else {
12095                            movement::next_word_end_or_newline(map, selection.head())
12096                        };
12097                        selection.set_head(cursor, SelectionGoal::None);
12098                    }
12099                });
12100            });
12101            this.insert("", window, cx);
12102        });
12103    }
12104
12105    pub fn delete_to_next_subword_end(
12106        &mut self,
12107        _: &DeleteToNextSubwordEnd,
12108        window: &mut Window,
12109        cx: &mut Context<Self>,
12110    ) {
12111        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12112        self.transact(window, cx, |this, window, cx| {
12113            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12114                s.move_with(|map, selection| {
12115                    if selection.is_empty() {
12116                        let cursor = movement::next_subword_end(map, selection.head());
12117                        selection.set_head(cursor, SelectionGoal::None);
12118                    }
12119                });
12120            });
12121            this.insert("", window, cx);
12122        });
12123    }
12124
12125    pub fn move_to_beginning_of_line(
12126        &mut self,
12127        action: &MoveToBeginningOfLine,
12128        window: &mut Window,
12129        cx: &mut Context<Self>,
12130    ) {
12131        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12132        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12133            s.move_cursors_with(|map, head, _| {
12134                (
12135                    movement::indented_line_beginning(
12136                        map,
12137                        head,
12138                        action.stop_at_soft_wraps,
12139                        action.stop_at_indent,
12140                    ),
12141                    SelectionGoal::None,
12142                )
12143            });
12144        })
12145    }
12146
12147    pub fn select_to_beginning_of_line(
12148        &mut self,
12149        action: &SelectToBeginningOfLine,
12150        window: &mut Window,
12151        cx: &mut Context<Self>,
12152    ) {
12153        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12154        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12155            s.move_heads_with(|map, head, _| {
12156                (
12157                    movement::indented_line_beginning(
12158                        map,
12159                        head,
12160                        action.stop_at_soft_wraps,
12161                        action.stop_at_indent,
12162                    ),
12163                    SelectionGoal::None,
12164                )
12165            });
12166        });
12167    }
12168
12169    pub fn delete_to_beginning_of_line(
12170        &mut self,
12171        action: &DeleteToBeginningOfLine,
12172        window: &mut Window,
12173        cx: &mut Context<Self>,
12174    ) {
12175        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12176        self.transact(window, cx, |this, window, cx| {
12177            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12178                s.move_with(|_, selection| {
12179                    selection.reversed = true;
12180                });
12181            });
12182
12183            this.select_to_beginning_of_line(
12184                &SelectToBeginningOfLine {
12185                    stop_at_soft_wraps: false,
12186                    stop_at_indent: action.stop_at_indent,
12187                },
12188                window,
12189                cx,
12190            );
12191            this.backspace(&Backspace, window, cx);
12192        });
12193    }
12194
12195    pub fn move_to_end_of_line(
12196        &mut self,
12197        action: &MoveToEndOfLine,
12198        window: &mut Window,
12199        cx: &mut Context<Self>,
12200    ) {
12201        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12202        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12203            s.move_cursors_with(|map, head, _| {
12204                (
12205                    movement::line_end(map, head, action.stop_at_soft_wraps),
12206                    SelectionGoal::None,
12207                )
12208            });
12209        })
12210    }
12211
12212    pub fn select_to_end_of_line(
12213        &mut self,
12214        action: &SelectToEndOfLine,
12215        window: &mut Window,
12216        cx: &mut Context<Self>,
12217    ) {
12218        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12219        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12220            s.move_heads_with(|map, head, _| {
12221                (
12222                    movement::line_end(map, head, action.stop_at_soft_wraps),
12223                    SelectionGoal::None,
12224                )
12225            });
12226        })
12227    }
12228
12229    pub fn delete_to_end_of_line(
12230        &mut self,
12231        _: &DeleteToEndOfLine,
12232        window: &mut Window,
12233        cx: &mut Context<Self>,
12234    ) {
12235        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12236        self.transact(window, cx, |this, window, cx| {
12237            this.select_to_end_of_line(
12238                &SelectToEndOfLine {
12239                    stop_at_soft_wraps: false,
12240                },
12241                window,
12242                cx,
12243            );
12244            this.delete(&Delete, window, cx);
12245        });
12246    }
12247
12248    pub fn cut_to_end_of_line(
12249        &mut self,
12250        _: &CutToEndOfLine,
12251        window: &mut Window,
12252        cx: &mut Context<Self>,
12253    ) {
12254        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12255        self.transact(window, cx, |this, window, cx| {
12256            this.select_to_end_of_line(
12257                &SelectToEndOfLine {
12258                    stop_at_soft_wraps: false,
12259                },
12260                window,
12261                cx,
12262            );
12263            this.cut(&Cut, window, cx);
12264        });
12265    }
12266
12267    pub fn move_to_start_of_paragraph(
12268        &mut self,
12269        _: &MoveToStartOfParagraph,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12274            cx.propagate();
12275            return;
12276        }
12277        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12278        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12279            s.move_with(|map, selection| {
12280                selection.collapse_to(
12281                    movement::start_of_paragraph(map, selection.head(), 1),
12282                    SelectionGoal::None,
12283                )
12284            });
12285        })
12286    }
12287
12288    pub fn move_to_end_of_paragraph(
12289        &mut self,
12290        _: &MoveToEndOfParagraph,
12291        window: &mut Window,
12292        cx: &mut Context<Self>,
12293    ) {
12294        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12295            cx.propagate();
12296            return;
12297        }
12298        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12299        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12300            s.move_with(|map, selection| {
12301                selection.collapse_to(
12302                    movement::end_of_paragraph(map, selection.head(), 1),
12303                    SelectionGoal::None,
12304                )
12305            });
12306        })
12307    }
12308
12309    pub fn select_to_start_of_paragraph(
12310        &mut self,
12311        _: &SelectToStartOfParagraph,
12312        window: &mut Window,
12313        cx: &mut Context<Self>,
12314    ) {
12315        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12316            cx.propagate();
12317            return;
12318        }
12319        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12320        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12321            s.move_heads_with(|map, head, _| {
12322                (
12323                    movement::start_of_paragraph(map, head, 1),
12324                    SelectionGoal::None,
12325                )
12326            });
12327        })
12328    }
12329
12330    pub fn select_to_end_of_paragraph(
12331        &mut self,
12332        _: &SelectToEndOfParagraph,
12333        window: &mut Window,
12334        cx: &mut Context<Self>,
12335    ) {
12336        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12337            cx.propagate();
12338            return;
12339        }
12340        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12341        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12342            s.move_heads_with(|map, head, _| {
12343                (
12344                    movement::end_of_paragraph(map, head, 1),
12345                    SelectionGoal::None,
12346                )
12347            });
12348        })
12349    }
12350
12351    pub fn move_to_start_of_excerpt(
12352        &mut self,
12353        _: &MoveToStartOfExcerpt,
12354        window: &mut Window,
12355        cx: &mut Context<Self>,
12356    ) {
12357        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12358            cx.propagate();
12359            return;
12360        }
12361        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12362        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12363            s.move_with(|map, selection| {
12364                selection.collapse_to(
12365                    movement::start_of_excerpt(
12366                        map,
12367                        selection.head(),
12368                        workspace::searchable::Direction::Prev,
12369                    ),
12370                    SelectionGoal::None,
12371                )
12372            });
12373        })
12374    }
12375
12376    pub fn move_to_start_of_next_excerpt(
12377        &mut self,
12378        _: &MoveToStartOfNextExcerpt,
12379        window: &mut Window,
12380        cx: &mut Context<Self>,
12381    ) {
12382        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12383            cx.propagate();
12384            return;
12385        }
12386
12387        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12388            s.move_with(|map, selection| {
12389                selection.collapse_to(
12390                    movement::start_of_excerpt(
12391                        map,
12392                        selection.head(),
12393                        workspace::searchable::Direction::Next,
12394                    ),
12395                    SelectionGoal::None,
12396                )
12397            });
12398        })
12399    }
12400
12401    pub fn move_to_end_of_excerpt(
12402        &mut self,
12403        _: &MoveToEndOfExcerpt,
12404        window: &mut Window,
12405        cx: &mut Context<Self>,
12406    ) {
12407        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12408            cx.propagate();
12409            return;
12410        }
12411        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12412        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12413            s.move_with(|map, selection| {
12414                selection.collapse_to(
12415                    movement::end_of_excerpt(
12416                        map,
12417                        selection.head(),
12418                        workspace::searchable::Direction::Next,
12419                    ),
12420                    SelectionGoal::None,
12421                )
12422            });
12423        })
12424    }
12425
12426    pub fn move_to_end_of_previous_excerpt(
12427        &mut self,
12428        _: &MoveToEndOfPreviousExcerpt,
12429        window: &mut Window,
12430        cx: &mut Context<Self>,
12431    ) {
12432        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12433            cx.propagate();
12434            return;
12435        }
12436        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12437        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12438            s.move_with(|map, selection| {
12439                selection.collapse_to(
12440                    movement::end_of_excerpt(
12441                        map,
12442                        selection.head(),
12443                        workspace::searchable::Direction::Prev,
12444                    ),
12445                    SelectionGoal::None,
12446                )
12447            });
12448        })
12449    }
12450
12451    pub fn select_to_start_of_excerpt(
12452        &mut self,
12453        _: &SelectToStartOfExcerpt,
12454        window: &mut Window,
12455        cx: &mut Context<Self>,
12456    ) {
12457        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12458            cx.propagate();
12459            return;
12460        }
12461        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12462        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12463            s.move_heads_with(|map, head, _| {
12464                (
12465                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12466                    SelectionGoal::None,
12467                )
12468            });
12469        })
12470    }
12471
12472    pub fn select_to_start_of_next_excerpt(
12473        &mut self,
12474        _: &SelectToStartOfNextExcerpt,
12475        window: &mut Window,
12476        cx: &mut Context<Self>,
12477    ) {
12478        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12479            cx.propagate();
12480            return;
12481        }
12482        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12483        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12484            s.move_heads_with(|map, head, _| {
12485                (
12486                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12487                    SelectionGoal::None,
12488                )
12489            });
12490        })
12491    }
12492
12493    pub fn select_to_end_of_excerpt(
12494        &mut self,
12495        _: &SelectToEndOfExcerpt,
12496        window: &mut Window,
12497        cx: &mut Context<Self>,
12498    ) {
12499        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12500            cx.propagate();
12501            return;
12502        }
12503        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12504        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12505            s.move_heads_with(|map, head, _| {
12506                (
12507                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12508                    SelectionGoal::None,
12509                )
12510            });
12511        })
12512    }
12513
12514    pub fn select_to_end_of_previous_excerpt(
12515        &mut self,
12516        _: &SelectToEndOfPreviousExcerpt,
12517        window: &mut Window,
12518        cx: &mut Context<Self>,
12519    ) {
12520        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12521            cx.propagate();
12522            return;
12523        }
12524        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12525        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12526            s.move_heads_with(|map, head, _| {
12527                (
12528                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12529                    SelectionGoal::None,
12530                )
12531            });
12532        })
12533    }
12534
12535    pub fn move_to_beginning(
12536        &mut self,
12537        _: &MoveToBeginning,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12542            cx.propagate();
12543            return;
12544        }
12545        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12546        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12547            s.select_ranges(vec![0..0]);
12548        });
12549    }
12550
12551    pub fn select_to_beginning(
12552        &mut self,
12553        _: &SelectToBeginning,
12554        window: &mut Window,
12555        cx: &mut Context<Self>,
12556    ) {
12557        let mut selection = self.selections.last::<Point>(cx);
12558        selection.set_head(Point::zero(), SelectionGoal::None);
12559        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12560        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12561            s.select(vec![selection]);
12562        });
12563    }
12564
12565    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12566        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12567            cx.propagate();
12568            return;
12569        }
12570        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12571        let cursor = self.buffer.read(cx).read(cx).len();
12572        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12573            s.select_ranges(vec![cursor..cursor])
12574        });
12575    }
12576
12577    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12578        self.nav_history = nav_history;
12579    }
12580
12581    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12582        self.nav_history.as_ref()
12583    }
12584
12585    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12586        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12587    }
12588
12589    fn push_to_nav_history(
12590        &mut self,
12591        cursor_anchor: Anchor,
12592        new_position: Option<Point>,
12593        is_deactivate: bool,
12594        cx: &mut Context<Self>,
12595    ) {
12596        if let Some(nav_history) = self.nav_history.as_mut() {
12597            let buffer = self.buffer.read(cx).read(cx);
12598            let cursor_position = cursor_anchor.to_point(&buffer);
12599            let scroll_state = self.scroll_manager.anchor();
12600            let scroll_top_row = scroll_state.top_row(&buffer);
12601            drop(buffer);
12602
12603            if let Some(new_position) = new_position {
12604                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12605                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12606                    return;
12607                }
12608            }
12609
12610            nav_history.push(
12611                Some(NavigationData {
12612                    cursor_anchor,
12613                    cursor_position,
12614                    scroll_anchor: scroll_state,
12615                    scroll_top_row,
12616                }),
12617                cx,
12618            );
12619            cx.emit(EditorEvent::PushedToNavHistory {
12620                anchor: cursor_anchor,
12621                is_deactivate,
12622            })
12623        }
12624    }
12625
12626    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12627        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12628        let buffer = self.buffer.read(cx).snapshot(cx);
12629        let mut selection = self.selections.first::<usize>(cx);
12630        selection.set_head(buffer.len(), SelectionGoal::None);
12631        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12632            s.select(vec![selection]);
12633        });
12634    }
12635
12636    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12638        let end = self.buffer.read(cx).read(cx).len();
12639        self.change_selections(None, window, cx, |s| {
12640            s.select_ranges(vec![0..end]);
12641        });
12642    }
12643
12644    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12646        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12647        let mut selections = self.selections.all::<Point>(cx);
12648        let max_point = display_map.buffer_snapshot.max_point();
12649        for selection in &mut selections {
12650            let rows = selection.spanned_rows(true, &display_map);
12651            selection.start = Point::new(rows.start.0, 0);
12652            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12653            selection.reversed = false;
12654        }
12655        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12656            s.select(selections);
12657        });
12658    }
12659
12660    pub fn split_selection_into_lines(
12661        &mut self,
12662        _: &SplitSelectionIntoLines,
12663        window: &mut Window,
12664        cx: &mut Context<Self>,
12665    ) {
12666        let selections = self
12667            .selections
12668            .all::<Point>(cx)
12669            .into_iter()
12670            .map(|selection| selection.start..selection.end)
12671            .collect::<Vec<_>>();
12672        self.unfold_ranges(&selections, true, true, cx);
12673
12674        let mut new_selection_ranges = Vec::new();
12675        {
12676            let buffer = self.buffer.read(cx).read(cx);
12677            for selection in selections {
12678                for row in selection.start.row..selection.end.row {
12679                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12680                    new_selection_ranges.push(cursor..cursor);
12681                }
12682
12683                let is_multiline_selection = selection.start.row != selection.end.row;
12684                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12685                // so this action feels more ergonomic when paired with other selection operations
12686                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12687                if !should_skip_last {
12688                    new_selection_ranges.push(selection.end..selection.end);
12689                }
12690            }
12691        }
12692        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12693            s.select_ranges(new_selection_ranges);
12694        });
12695    }
12696
12697    pub fn add_selection_above(
12698        &mut self,
12699        _: &AddSelectionAbove,
12700        window: &mut Window,
12701        cx: &mut Context<Self>,
12702    ) {
12703        self.add_selection(true, window, cx);
12704    }
12705
12706    pub fn add_selection_below(
12707        &mut self,
12708        _: &AddSelectionBelow,
12709        window: &mut Window,
12710        cx: &mut Context<Self>,
12711    ) {
12712        self.add_selection(false, window, cx);
12713    }
12714
12715    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12716        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12717
12718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12719        let all_selections = self.selections.all::<Point>(cx);
12720        let text_layout_details = self.text_layout_details(window);
12721
12722        let (mut columnar_selections, new_selections_to_columnarize) = {
12723            if let Some(state) = self.add_selections_state.as_ref() {
12724                let columnar_selection_ids: HashSet<_> = state
12725                    .groups
12726                    .iter()
12727                    .flat_map(|group| group.stack.iter())
12728                    .copied()
12729                    .collect();
12730
12731                all_selections
12732                    .into_iter()
12733                    .partition(|s| columnar_selection_ids.contains(&s.id))
12734            } else {
12735                (Vec::new(), all_selections)
12736            }
12737        };
12738
12739        let mut state = self
12740            .add_selections_state
12741            .take()
12742            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12743
12744        for selection in new_selections_to_columnarize {
12745            let range = selection.display_range(&display_map).sorted();
12746            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12747            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12748            let positions = start_x.min(end_x)..start_x.max(end_x);
12749            let mut stack = Vec::new();
12750            for row in range.start.row().0..=range.end.row().0 {
12751                if let Some(selection) = self.selections.build_columnar_selection(
12752                    &display_map,
12753                    DisplayRow(row),
12754                    &positions,
12755                    selection.reversed,
12756                    &text_layout_details,
12757                ) {
12758                    stack.push(selection.id);
12759                    columnar_selections.push(selection);
12760                }
12761            }
12762            if !stack.is_empty() {
12763                if above {
12764                    stack.reverse();
12765                }
12766                state.groups.push(AddSelectionsGroup { above, stack });
12767            }
12768        }
12769
12770        let mut final_selections = Vec::new();
12771        let end_row = if above {
12772            DisplayRow(0)
12773        } else {
12774            display_map.max_point().row()
12775        };
12776
12777        let mut last_added_item_per_group = HashMap::default();
12778        for group in state.groups.iter_mut() {
12779            if let Some(last_id) = group.stack.last() {
12780                last_added_item_per_group.insert(*last_id, group);
12781            }
12782        }
12783
12784        for selection in columnar_selections {
12785            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12786                if above == group.above {
12787                    let range = selection.display_range(&display_map).sorted();
12788                    debug_assert_eq!(range.start.row(), range.end.row());
12789                    let mut row = range.start.row();
12790                    let positions =
12791                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12792                            px(start)..px(end)
12793                        } else {
12794                            let start_x =
12795                                display_map.x_for_display_point(range.start, &text_layout_details);
12796                            let end_x =
12797                                display_map.x_for_display_point(range.end, &text_layout_details);
12798                            start_x.min(end_x)..start_x.max(end_x)
12799                        };
12800
12801                    let mut maybe_new_selection = None;
12802                    while row != end_row {
12803                        if above {
12804                            row.0 -= 1;
12805                        } else {
12806                            row.0 += 1;
12807                        }
12808                        if let Some(new_selection) = self.selections.build_columnar_selection(
12809                            &display_map,
12810                            row,
12811                            &positions,
12812                            selection.reversed,
12813                            &text_layout_details,
12814                        ) {
12815                            maybe_new_selection = Some(new_selection);
12816                            break;
12817                        }
12818                    }
12819
12820                    if let Some(new_selection) = maybe_new_selection {
12821                        group.stack.push(new_selection.id);
12822                        if above {
12823                            final_selections.push(new_selection);
12824                            final_selections.push(selection);
12825                        } else {
12826                            final_selections.push(selection);
12827                            final_selections.push(new_selection);
12828                        }
12829                    } else {
12830                        final_selections.push(selection);
12831                    }
12832                } else {
12833                    group.stack.pop();
12834                }
12835            } else {
12836                final_selections.push(selection);
12837            }
12838        }
12839
12840        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12841            s.select(final_selections);
12842        });
12843
12844        let final_selection_ids: HashSet<_> = self
12845            .selections
12846            .all::<Point>(cx)
12847            .iter()
12848            .map(|s| s.id)
12849            .collect();
12850        state.groups.retain_mut(|group| {
12851            // selections might get merged above so we remove invalid items from stacks
12852            group.stack.retain(|id| final_selection_ids.contains(id));
12853
12854            // single selection in stack can be treated as initial state
12855            group.stack.len() > 1
12856        });
12857
12858        if !state.groups.is_empty() {
12859            self.add_selections_state = Some(state);
12860        }
12861    }
12862
12863    fn select_match_ranges(
12864        &mut self,
12865        range: Range<usize>,
12866        reversed: bool,
12867        replace_newest: bool,
12868        auto_scroll: Option<Autoscroll>,
12869        window: &mut Window,
12870        cx: &mut Context<Editor>,
12871    ) {
12872        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12873        self.change_selections(auto_scroll, window, cx, |s| {
12874            if replace_newest {
12875                s.delete(s.newest_anchor().id);
12876            }
12877            if reversed {
12878                s.insert_range(range.end..range.start);
12879            } else {
12880                s.insert_range(range);
12881            }
12882        });
12883    }
12884
12885    pub fn select_next_match_internal(
12886        &mut self,
12887        display_map: &DisplaySnapshot,
12888        replace_newest: bool,
12889        autoscroll: Option<Autoscroll>,
12890        window: &mut Window,
12891        cx: &mut Context<Self>,
12892    ) -> Result<()> {
12893        let buffer = &display_map.buffer_snapshot;
12894        let mut selections = self.selections.all::<usize>(cx);
12895        if let Some(mut select_next_state) = self.select_next_state.take() {
12896            let query = &select_next_state.query;
12897            if !select_next_state.done {
12898                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12899                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12900                let mut next_selected_range = None;
12901
12902                let bytes_after_last_selection =
12903                    buffer.bytes_in_range(last_selection.end..buffer.len());
12904                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12905                let query_matches = query
12906                    .stream_find_iter(bytes_after_last_selection)
12907                    .map(|result| (last_selection.end, result))
12908                    .chain(
12909                        query
12910                            .stream_find_iter(bytes_before_first_selection)
12911                            .map(|result| (0, result)),
12912                    );
12913
12914                for (start_offset, query_match) in query_matches {
12915                    let query_match = query_match.unwrap(); // can only fail due to I/O
12916                    let offset_range =
12917                        start_offset + query_match.start()..start_offset + query_match.end();
12918                    let display_range = offset_range.start.to_display_point(display_map)
12919                        ..offset_range.end.to_display_point(display_map);
12920
12921                    if !select_next_state.wordwise
12922                        || (!movement::is_inside_word(display_map, display_range.start)
12923                            && !movement::is_inside_word(display_map, display_range.end))
12924                    {
12925                        // TODO: This is n^2, because we might check all the selections
12926                        if !selections
12927                            .iter()
12928                            .any(|selection| selection.range().overlaps(&offset_range))
12929                        {
12930                            next_selected_range = Some(offset_range);
12931                            break;
12932                        }
12933                    }
12934                }
12935
12936                if let Some(next_selected_range) = next_selected_range {
12937                    self.select_match_ranges(
12938                        next_selected_range,
12939                        last_selection.reversed,
12940                        replace_newest,
12941                        autoscroll,
12942                        window,
12943                        cx,
12944                    );
12945                } else {
12946                    select_next_state.done = true;
12947                }
12948            }
12949
12950            self.select_next_state = Some(select_next_state);
12951        } else {
12952            let mut only_carets = true;
12953            let mut same_text_selected = true;
12954            let mut selected_text = None;
12955
12956            let mut selections_iter = selections.iter().peekable();
12957            while let Some(selection) = selections_iter.next() {
12958                if selection.start != selection.end {
12959                    only_carets = false;
12960                }
12961
12962                if same_text_selected {
12963                    if selected_text.is_none() {
12964                        selected_text =
12965                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12966                    }
12967
12968                    if let Some(next_selection) = selections_iter.peek() {
12969                        if next_selection.range().len() == selection.range().len() {
12970                            let next_selected_text = buffer
12971                                .text_for_range(next_selection.range())
12972                                .collect::<String>();
12973                            if Some(next_selected_text) != selected_text {
12974                                same_text_selected = false;
12975                                selected_text = None;
12976                            }
12977                        } else {
12978                            same_text_selected = false;
12979                            selected_text = None;
12980                        }
12981                    }
12982                }
12983            }
12984
12985            if only_carets {
12986                for selection in &mut selections {
12987                    let word_range = movement::surrounding_word(
12988                        display_map,
12989                        selection.start.to_display_point(display_map),
12990                    );
12991                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12992                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12993                    selection.goal = SelectionGoal::None;
12994                    selection.reversed = false;
12995                    self.select_match_ranges(
12996                        selection.start..selection.end,
12997                        selection.reversed,
12998                        replace_newest,
12999                        autoscroll,
13000                        window,
13001                        cx,
13002                    );
13003                }
13004
13005                if selections.len() == 1 {
13006                    let selection = selections
13007                        .last()
13008                        .expect("ensured that there's only one selection");
13009                    let query = buffer
13010                        .text_for_range(selection.start..selection.end)
13011                        .collect::<String>();
13012                    let is_empty = query.is_empty();
13013                    let select_state = SelectNextState {
13014                        query: AhoCorasick::new(&[query])?,
13015                        wordwise: true,
13016                        done: is_empty,
13017                    };
13018                    self.select_next_state = Some(select_state);
13019                } else {
13020                    self.select_next_state = None;
13021                }
13022            } else if let Some(selected_text) = selected_text {
13023                self.select_next_state = Some(SelectNextState {
13024                    query: AhoCorasick::new(&[selected_text])?,
13025                    wordwise: false,
13026                    done: false,
13027                });
13028                self.select_next_match_internal(
13029                    display_map,
13030                    replace_newest,
13031                    autoscroll,
13032                    window,
13033                    cx,
13034                )?;
13035            }
13036        }
13037        Ok(())
13038    }
13039
13040    pub fn select_all_matches(
13041        &mut self,
13042        _action: &SelectAllMatches,
13043        window: &mut Window,
13044        cx: &mut Context<Self>,
13045    ) -> Result<()> {
13046        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13047
13048        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13049
13050        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13051        let Some(select_next_state) = self.select_next_state.as_mut() else {
13052            return Ok(());
13053        };
13054        if select_next_state.done {
13055            return Ok(());
13056        }
13057
13058        let mut new_selections = Vec::new();
13059
13060        let reversed = self.selections.oldest::<usize>(cx).reversed;
13061        let buffer = &display_map.buffer_snapshot;
13062        let query_matches = select_next_state
13063            .query
13064            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13065
13066        for query_match in query_matches.into_iter() {
13067            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13068            let offset_range = if reversed {
13069                query_match.end()..query_match.start()
13070            } else {
13071                query_match.start()..query_match.end()
13072            };
13073            let display_range = offset_range.start.to_display_point(&display_map)
13074                ..offset_range.end.to_display_point(&display_map);
13075
13076            if !select_next_state.wordwise
13077                || (!movement::is_inside_word(&display_map, display_range.start)
13078                    && !movement::is_inside_word(&display_map, display_range.end))
13079            {
13080                new_selections.push(offset_range.start..offset_range.end);
13081            }
13082        }
13083
13084        select_next_state.done = true;
13085        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13086        self.change_selections(None, window, cx, |selections| {
13087            selections.select_ranges(new_selections)
13088        });
13089
13090        Ok(())
13091    }
13092
13093    pub fn select_next(
13094        &mut self,
13095        action: &SelectNext,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) -> Result<()> {
13099        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13101        self.select_next_match_internal(
13102            &display_map,
13103            action.replace_newest,
13104            Some(Autoscroll::newest()),
13105            window,
13106            cx,
13107        )?;
13108        Ok(())
13109    }
13110
13111    pub fn select_previous(
13112        &mut self,
13113        action: &SelectPrevious,
13114        window: &mut Window,
13115        cx: &mut Context<Self>,
13116    ) -> Result<()> {
13117        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13118        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13119        let buffer = &display_map.buffer_snapshot;
13120        let mut selections = self.selections.all::<usize>(cx);
13121        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13122            let query = &select_prev_state.query;
13123            if !select_prev_state.done {
13124                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13125                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13126                let mut next_selected_range = None;
13127                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13128                let bytes_before_last_selection =
13129                    buffer.reversed_bytes_in_range(0..last_selection.start);
13130                let bytes_after_first_selection =
13131                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13132                let query_matches = query
13133                    .stream_find_iter(bytes_before_last_selection)
13134                    .map(|result| (last_selection.start, result))
13135                    .chain(
13136                        query
13137                            .stream_find_iter(bytes_after_first_selection)
13138                            .map(|result| (buffer.len(), result)),
13139                    );
13140                for (end_offset, query_match) in query_matches {
13141                    let query_match = query_match.unwrap(); // can only fail due to I/O
13142                    let offset_range =
13143                        end_offset - query_match.end()..end_offset - query_match.start();
13144                    let display_range = offset_range.start.to_display_point(&display_map)
13145                        ..offset_range.end.to_display_point(&display_map);
13146
13147                    if !select_prev_state.wordwise
13148                        || (!movement::is_inside_word(&display_map, display_range.start)
13149                            && !movement::is_inside_word(&display_map, display_range.end))
13150                    {
13151                        next_selected_range = Some(offset_range);
13152                        break;
13153                    }
13154                }
13155
13156                if let Some(next_selected_range) = next_selected_range {
13157                    self.select_match_ranges(
13158                        next_selected_range,
13159                        last_selection.reversed,
13160                        action.replace_newest,
13161                        Some(Autoscroll::newest()),
13162                        window,
13163                        cx,
13164                    );
13165                } else {
13166                    select_prev_state.done = true;
13167                }
13168            }
13169
13170            self.select_prev_state = Some(select_prev_state);
13171        } else {
13172            let mut only_carets = true;
13173            let mut same_text_selected = true;
13174            let mut selected_text = None;
13175
13176            let mut selections_iter = selections.iter().peekable();
13177            while let Some(selection) = selections_iter.next() {
13178                if selection.start != selection.end {
13179                    only_carets = false;
13180                }
13181
13182                if same_text_selected {
13183                    if selected_text.is_none() {
13184                        selected_text =
13185                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13186                    }
13187
13188                    if let Some(next_selection) = selections_iter.peek() {
13189                        if next_selection.range().len() == selection.range().len() {
13190                            let next_selected_text = buffer
13191                                .text_for_range(next_selection.range())
13192                                .collect::<String>();
13193                            if Some(next_selected_text) != selected_text {
13194                                same_text_selected = false;
13195                                selected_text = None;
13196                            }
13197                        } else {
13198                            same_text_selected = false;
13199                            selected_text = None;
13200                        }
13201                    }
13202                }
13203            }
13204
13205            if only_carets {
13206                for selection in &mut selections {
13207                    let word_range = movement::surrounding_word(
13208                        &display_map,
13209                        selection.start.to_display_point(&display_map),
13210                    );
13211                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13212                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13213                    selection.goal = SelectionGoal::None;
13214                    selection.reversed = false;
13215                    self.select_match_ranges(
13216                        selection.start..selection.end,
13217                        selection.reversed,
13218                        action.replace_newest,
13219                        Some(Autoscroll::newest()),
13220                        window,
13221                        cx,
13222                    );
13223                }
13224                if selections.len() == 1 {
13225                    let selection = selections
13226                        .last()
13227                        .expect("ensured that there's only one selection");
13228                    let query = buffer
13229                        .text_for_range(selection.start..selection.end)
13230                        .collect::<String>();
13231                    let is_empty = query.is_empty();
13232                    let select_state = SelectNextState {
13233                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13234                        wordwise: true,
13235                        done: is_empty,
13236                    };
13237                    self.select_prev_state = Some(select_state);
13238                } else {
13239                    self.select_prev_state = None;
13240                }
13241            } else if let Some(selected_text) = selected_text {
13242                self.select_prev_state = Some(SelectNextState {
13243                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13244                    wordwise: false,
13245                    done: false,
13246                });
13247                self.select_previous(action, window, cx)?;
13248            }
13249        }
13250        Ok(())
13251    }
13252
13253    pub fn find_next_match(
13254        &mut self,
13255        _: &FindNextMatch,
13256        window: &mut Window,
13257        cx: &mut Context<Self>,
13258    ) -> Result<()> {
13259        let selections = self.selections.disjoint_anchors();
13260        match selections.first() {
13261            Some(first) if selections.len() >= 2 => {
13262                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13263                    s.select_ranges([first.range()]);
13264                });
13265            }
13266            _ => self.select_next(
13267                &SelectNext {
13268                    replace_newest: true,
13269                },
13270                window,
13271                cx,
13272            )?,
13273        }
13274        Ok(())
13275    }
13276
13277    pub fn find_previous_match(
13278        &mut self,
13279        _: &FindPreviousMatch,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) -> Result<()> {
13283        let selections = self.selections.disjoint_anchors();
13284        match selections.last() {
13285            Some(last) if selections.len() >= 2 => {
13286                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13287                    s.select_ranges([last.range()]);
13288                });
13289            }
13290            _ => self.select_previous(
13291                &SelectPrevious {
13292                    replace_newest: true,
13293                },
13294                window,
13295                cx,
13296            )?,
13297        }
13298        Ok(())
13299    }
13300
13301    pub fn toggle_comments(
13302        &mut self,
13303        action: &ToggleComments,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        if self.read_only(cx) {
13308            return;
13309        }
13310        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13311        let text_layout_details = &self.text_layout_details(window);
13312        self.transact(window, cx, |this, window, cx| {
13313            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13314            let mut edits = Vec::new();
13315            let mut selection_edit_ranges = Vec::new();
13316            let mut last_toggled_row = None;
13317            let snapshot = this.buffer.read(cx).read(cx);
13318            let empty_str: Arc<str> = Arc::default();
13319            let mut suffixes_inserted = Vec::new();
13320            let ignore_indent = action.ignore_indent;
13321
13322            fn comment_prefix_range(
13323                snapshot: &MultiBufferSnapshot,
13324                row: MultiBufferRow,
13325                comment_prefix: &str,
13326                comment_prefix_whitespace: &str,
13327                ignore_indent: bool,
13328            ) -> Range<Point> {
13329                let indent_size = if ignore_indent {
13330                    0
13331                } else {
13332                    snapshot.indent_size_for_line(row).len
13333                };
13334
13335                let start = Point::new(row.0, indent_size);
13336
13337                let mut line_bytes = snapshot
13338                    .bytes_in_range(start..snapshot.max_point())
13339                    .flatten()
13340                    .copied();
13341
13342                // If this line currently begins with the line comment prefix, then record
13343                // the range containing the prefix.
13344                if line_bytes
13345                    .by_ref()
13346                    .take(comment_prefix.len())
13347                    .eq(comment_prefix.bytes())
13348                {
13349                    // Include any whitespace that matches the comment prefix.
13350                    let matching_whitespace_len = line_bytes
13351                        .zip(comment_prefix_whitespace.bytes())
13352                        .take_while(|(a, b)| a == b)
13353                        .count() as u32;
13354                    let end = Point::new(
13355                        start.row,
13356                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13357                    );
13358                    start..end
13359                } else {
13360                    start..start
13361                }
13362            }
13363
13364            fn comment_suffix_range(
13365                snapshot: &MultiBufferSnapshot,
13366                row: MultiBufferRow,
13367                comment_suffix: &str,
13368                comment_suffix_has_leading_space: bool,
13369            ) -> Range<Point> {
13370                let end = Point::new(row.0, snapshot.line_len(row));
13371                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13372
13373                let mut line_end_bytes = snapshot
13374                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13375                    .flatten()
13376                    .copied();
13377
13378                let leading_space_len = if suffix_start_column > 0
13379                    && line_end_bytes.next() == Some(b' ')
13380                    && comment_suffix_has_leading_space
13381                {
13382                    1
13383                } else {
13384                    0
13385                };
13386
13387                // If this line currently begins with the line comment prefix, then record
13388                // the range containing the prefix.
13389                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13390                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13391                    start..end
13392                } else {
13393                    end..end
13394                }
13395            }
13396
13397            // TODO: Handle selections that cross excerpts
13398            for selection in &mut selections {
13399                let start_column = snapshot
13400                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13401                    .len;
13402                let language = if let Some(language) =
13403                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13404                {
13405                    language
13406                } else {
13407                    continue;
13408                };
13409
13410                selection_edit_ranges.clear();
13411
13412                // If multiple selections contain a given row, avoid processing that
13413                // row more than once.
13414                let mut start_row = MultiBufferRow(selection.start.row);
13415                if last_toggled_row == Some(start_row) {
13416                    start_row = start_row.next_row();
13417                }
13418                let end_row =
13419                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13420                        MultiBufferRow(selection.end.row - 1)
13421                    } else {
13422                        MultiBufferRow(selection.end.row)
13423                    };
13424                last_toggled_row = Some(end_row);
13425
13426                if start_row > end_row {
13427                    continue;
13428                }
13429
13430                // If the language has line comments, toggle those.
13431                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13432
13433                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13434                if ignore_indent {
13435                    full_comment_prefixes = full_comment_prefixes
13436                        .into_iter()
13437                        .map(|s| Arc::from(s.trim_end()))
13438                        .collect();
13439                }
13440
13441                if !full_comment_prefixes.is_empty() {
13442                    let first_prefix = full_comment_prefixes
13443                        .first()
13444                        .expect("prefixes is non-empty");
13445                    let prefix_trimmed_lengths = full_comment_prefixes
13446                        .iter()
13447                        .map(|p| p.trim_end_matches(' ').len())
13448                        .collect::<SmallVec<[usize; 4]>>();
13449
13450                    let mut all_selection_lines_are_comments = true;
13451
13452                    for row in start_row.0..=end_row.0 {
13453                        let row = MultiBufferRow(row);
13454                        if start_row < end_row && snapshot.is_line_blank(row) {
13455                            continue;
13456                        }
13457
13458                        let prefix_range = full_comment_prefixes
13459                            .iter()
13460                            .zip(prefix_trimmed_lengths.iter().copied())
13461                            .map(|(prefix, trimmed_prefix_len)| {
13462                                comment_prefix_range(
13463                                    snapshot.deref(),
13464                                    row,
13465                                    &prefix[..trimmed_prefix_len],
13466                                    &prefix[trimmed_prefix_len..],
13467                                    ignore_indent,
13468                                )
13469                            })
13470                            .max_by_key(|range| range.end.column - range.start.column)
13471                            .expect("prefixes is non-empty");
13472
13473                        if prefix_range.is_empty() {
13474                            all_selection_lines_are_comments = false;
13475                        }
13476
13477                        selection_edit_ranges.push(prefix_range);
13478                    }
13479
13480                    if all_selection_lines_are_comments {
13481                        edits.extend(
13482                            selection_edit_ranges
13483                                .iter()
13484                                .cloned()
13485                                .map(|range| (range, empty_str.clone())),
13486                        );
13487                    } else {
13488                        let min_column = selection_edit_ranges
13489                            .iter()
13490                            .map(|range| range.start.column)
13491                            .min()
13492                            .unwrap_or(0);
13493                        edits.extend(selection_edit_ranges.iter().map(|range| {
13494                            let position = Point::new(range.start.row, min_column);
13495                            (position..position, first_prefix.clone())
13496                        }));
13497                    }
13498                } else if let Some((full_comment_prefix, comment_suffix)) =
13499                    language.block_comment_delimiters()
13500                {
13501                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13502                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13503                    let prefix_range = comment_prefix_range(
13504                        snapshot.deref(),
13505                        start_row,
13506                        comment_prefix,
13507                        comment_prefix_whitespace,
13508                        ignore_indent,
13509                    );
13510                    let suffix_range = comment_suffix_range(
13511                        snapshot.deref(),
13512                        end_row,
13513                        comment_suffix.trim_start_matches(' '),
13514                        comment_suffix.starts_with(' '),
13515                    );
13516
13517                    if prefix_range.is_empty() || suffix_range.is_empty() {
13518                        edits.push((
13519                            prefix_range.start..prefix_range.start,
13520                            full_comment_prefix.clone(),
13521                        ));
13522                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13523                        suffixes_inserted.push((end_row, comment_suffix.len()));
13524                    } else {
13525                        edits.push((prefix_range, empty_str.clone()));
13526                        edits.push((suffix_range, empty_str.clone()));
13527                    }
13528                } else {
13529                    continue;
13530                }
13531            }
13532
13533            drop(snapshot);
13534            this.buffer.update(cx, |buffer, cx| {
13535                buffer.edit(edits, None, cx);
13536            });
13537
13538            // Adjust selections so that they end before any comment suffixes that
13539            // were inserted.
13540            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13541            let mut selections = this.selections.all::<Point>(cx);
13542            let snapshot = this.buffer.read(cx).read(cx);
13543            for selection in &mut selections {
13544                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13545                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13546                        Ordering::Less => {
13547                            suffixes_inserted.next();
13548                            continue;
13549                        }
13550                        Ordering::Greater => break,
13551                        Ordering::Equal => {
13552                            if selection.end.column == snapshot.line_len(row) {
13553                                if selection.is_empty() {
13554                                    selection.start.column -= suffix_len as u32;
13555                                }
13556                                selection.end.column -= suffix_len as u32;
13557                            }
13558                            break;
13559                        }
13560                    }
13561                }
13562            }
13563
13564            drop(snapshot);
13565            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13566                s.select(selections)
13567            });
13568
13569            let selections = this.selections.all::<Point>(cx);
13570            let selections_on_single_row = selections.windows(2).all(|selections| {
13571                selections[0].start.row == selections[1].start.row
13572                    && selections[0].end.row == selections[1].end.row
13573                    && selections[0].start.row == selections[0].end.row
13574            });
13575            let selections_selecting = selections
13576                .iter()
13577                .any(|selection| selection.start != selection.end);
13578            let advance_downwards = action.advance_downwards
13579                && selections_on_single_row
13580                && !selections_selecting
13581                && !matches!(this.mode, EditorMode::SingleLine { .. });
13582
13583            if advance_downwards {
13584                let snapshot = this.buffer.read(cx).snapshot(cx);
13585
13586                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13587                    s.move_cursors_with(|display_snapshot, display_point, _| {
13588                        let mut point = display_point.to_point(display_snapshot);
13589                        point.row += 1;
13590                        point = snapshot.clip_point(point, Bias::Left);
13591                        let display_point = point.to_display_point(display_snapshot);
13592                        let goal = SelectionGoal::HorizontalPosition(
13593                            display_snapshot
13594                                .x_for_display_point(display_point, text_layout_details)
13595                                .into(),
13596                        );
13597                        (display_point, goal)
13598                    })
13599                });
13600            }
13601        });
13602    }
13603
13604    pub fn select_enclosing_symbol(
13605        &mut self,
13606        _: &SelectEnclosingSymbol,
13607        window: &mut Window,
13608        cx: &mut Context<Self>,
13609    ) {
13610        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13611
13612        let buffer = self.buffer.read(cx).snapshot(cx);
13613        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13614
13615        fn update_selection(
13616            selection: &Selection<usize>,
13617            buffer_snap: &MultiBufferSnapshot,
13618        ) -> Option<Selection<usize>> {
13619            let cursor = selection.head();
13620            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13621            for symbol in symbols.iter().rev() {
13622                let start = symbol.range.start.to_offset(buffer_snap);
13623                let end = symbol.range.end.to_offset(buffer_snap);
13624                let new_range = start..end;
13625                if start < selection.start || end > selection.end {
13626                    return Some(Selection {
13627                        id: selection.id,
13628                        start: new_range.start,
13629                        end: new_range.end,
13630                        goal: SelectionGoal::None,
13631                        reversed: selection.reversed,
13632                    });
13633                }
13634            }
13635            None
13636        }
13637
13638        let mut selected_larger_symbol = false;
13639        let new_selections = old_selections
13640            .iter()
13641            .map(|selection| match update_selection(selection, &buffer) {
13642                Some(new_selection) => {
13643                    if new_selection.range() != selection.range() {
13644                        selected_larger_symbol = true;
13645                    }
13646                    new_selection
13647                }
13648                None => selection.clone(),
13649            })
13650            .collect::<Vec<_>>();
13651
13652        if selected_larger_symbol {
13653            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13654                s.select(new_selections);
13655            });
13656        }
13657    }
13658
13659    pub fn select_larger_syntax_node(
13660        &mut self,
13661        _: &SelectLargerSyntaxNode,
13662        window: &mut Window,
13663        cx: &mut Context<Self>,
13664    ) {
13665        let Some(visible_row_count) = self.visible_row_count() else {
13666            return;
13667        };
13668        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13669        if old_selections.is_empty() {
13670            return;
13671        }
13672
13673        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13674
13675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13676        let buffer = self.buffer.read(cx).snapshot(cx);
13677
13678        let mut selected_larger_node = false;
13679        let mut new_selections = old_selections
13680            .iter()
13681            .map(|selection| {
13682                let old_range = selection.start..selection.end;
13683
13684                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13685                    // manually select word at selection
13686                    if ["string_content", "inline"].contains(&node.kind()) {
13687                        let word_range = {
13688                            let display_point = buffer
13689                                .offset_to_point(old_range.start)
13690                                .to_display_point(&display_map);
13691                            let Range { start, end } =
13692                                movement::surrounding_word(&display_map, display_point);
13693                            start.to_point(&display_map).to_offset(&buffer)
13694                                ..end.to_point(&display_map).to_offset(&buffer)
13695                        };
13696                        // ignore if word is already selected
13697                        if !word_range.is_empty() && old_range != word_range {
13698                            let last_word_range = {
13699                                let display_point = buffer
13700                                    .offset_to_point(old_range.end)
13701                                    .to_display_point(&display_map);
13702                                let Range { start, end } =
13703                                    movement::surrounding_word(&display_map, display_point);
13704                                start.to_point(&display_map).to_offset(&buffer)
13705                                    ..end.to_point(&display_map).to_offset(&buffer)
13706                            };
13707                            // only select word if start and end point belongs to same word
13708                            if word_range == last_word_range {
13709                                selected_larger_node = true;
13710                                return Selection {
13711                                    id: selection.id,
13712                                    start: word_range.start,
13713                                    end: word_range.end,
13714                                    goal: SelectionGoal::None,
13715                                    reversed: selection.reversed,
13716                                };
13717                            }
13718                        }
13719                    }
13720                }
13721
13722                let mut new_range = old_range.clone();
13723                while let Some((_node, containing_range)) =
13724                    buffer.syntax_ancestor(new_range.clone())
13725                {
13726                    new_range = match containing_range {
13727                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13728                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13729                    };
13730                    if !display_map.intersects_fold(new_range.start)
13731                        && !display_map.intersects_fold(new_range.end)
13732                    {
13733                        break;
13734                    }
13735                }
13736
13737                selected_larger_node |= new_range != old_range;
13738                Selection {
13739                    id: selection.id,
13740                    start: new_range.start,
13741                    end: new_range.end,
13742                    goal: SelectionGoal::None,
13743                    reversed: selection.reversed,
13744                }
13745            })
13746            .collect::<Vec<_>>();
13747
13748        if !selected_larger_node {
13749            return; // don't put this call in the history
13750        }
13751
13752        // scroll based on transformation done to the last selection created by the user
13753        let (last_old, last_new) = old_selections
13754            .last()
13755            .zip(new_selections.last().cloned())
13756            .expect("old_selections isn't empty");
13757
13758        // revert selection
13759        let is_selection_reversed = {
13760            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13761            new_selections.last_mut().expect("checked above").reversed =
13762                should_newest_selection_be_reversed;
13763            should_newest_selection_be_reversed
13764        };
13765
13766        if selected_larger_node {
13767            self.select_syntax_node_history.disable_clearing = true;
13768            self.change_selections(None, window, cx, |s| {
13769                s.select(new_selections.clone());
13770            });
13771            self.select_syntax_node_history.disable_clearing = false;
13772        }
13773
13774        let start_row = last_new.start.to_display_point(&display_map).row().0;
13775        let end_row = last_new.end.to_display_point(&display_map).row().0;
13776        let selection_height = end_row - start_row + 1;
13777        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13778
13779        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13780        let scroll_behavior = if fits_on_the_screen {
13781            self.request_autoscroll(Autoscroll::fit(), cx);
13782            SelectSyntaxNodeScrollBehavior::FitSelection
13783        } else if is_selection_reversed {
13784            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13785            SelectSyntaxNodeScrollBehavior::CursorTop
13786        } else {
13787            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13788            SelectSyntaxNodeScrollBehavior::CursorBottom
13789        };
13790
13791        self.select_syntax_node_history.push((
13792            old_selections,
13793            scroll_behavior,
13794            is_selection_reversed,
13795        ));
13796    }
13797
13798    pub fn select_smaller_syntax_node(
13799        &mut self,
13800        _: &SelectSmallerSyntaxNode,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13805
13806        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13807            self.select_syntax_node_history.pop()
13808        {
13809            if let Some(selection) = selections.last_mut() {
13810                selection.reversed = is_selection_reversed;
13811            }
13812
13813            self.select_syntax_node_history.disable_clearing = true;
13814            self.change_selections(None, window, cx, |s| {
13815                s.select(selections.to_vec());
13816            });
13817            self.select_syntax_node_history.disable_clearing = false;
13818
13819            match scroll_behavior {
13820                SelectSyntaxNodeScrollBehavior::CursorTop => {
13821                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13822                }
13823                SelectSyntaxNodeScrollBehavior::FitSelection => {
13824                    self.request_autoscroll(Autoscroll::fit(), cx);
13825                }
13826                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13827                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13828                }
13829            }
13830        }
13831    }
13832
13833    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13834        if !EditorSettings::get_global(cx).gutter.runnables {
13835            self.clear_tasks();
13836            return Task::ready(());
13837        }
13838        let project = self.project.as_ref().map(Entity::downgrade);
13839        let task_sources = self.lsp_task_sources(cx);
13840        let multi_buffer = self.buffer.downgrade();
13841        cx.spawn_in(window, async move |editor, cx| {
13842            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13843            let Some(project) = project.and_then(|p| p.upgrade()) else {
13844                return;
13845            };
13846            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13847                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13848            }) else {
13849                return;
13850            };
13851
13852            let hide_runnables = project
13853                .update(cx, |project, cx| {
13854                    // Do not display any test indicators in non-dev server remote projects.
13855                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13856                })
13857                .unwrap_or(true);
13858            if hide_runnables {
13859                return;
13860            }
13861            let new_rows =
13862                cx.background_spawn({
13863                    let snapshot = display_snapshot.clone();
13864                    async move {
13865                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13866                    }
13867                })
13868                    .await;
13869            let Ok(lsp_tasks) =
13870                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13871            else {
13872                return;
13873            };
13874            let lsp_tasks = lsp_tasks.await;
13875
13876            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13877                lsp_tasks
13878                    .into_iter()
13879                    .flat_map(|(kind, tasks)| {
13880                        tasks.into_iter().filter_map(move |(location, task)| {
13881                            Some((kind.clone(), location?, task))
13882                        })
13883                    })
13884                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13885                        let buffer = location.target.buffer;
13886                        let buffer_snapshot = buffer.read(cx).snapshot();
13887                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13888                            |(excerpt_id, snapshot, _)| {
13889                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13890                                    display_snapshot
13891                                        .buffer_snapshot
13892                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13893                                } else {
13894                                    None
13895                                }
13896                            },
13897                        );
13898                        if let Some(offset) = offset {
13899                            let task_buffer_range =
13900                                location.target.range.to_point(&buffer_snapshot);
13901                            let context_buffer_range =
13902                                task_buffer_range.to_offset(&buffer_snapshot);
13903                            let context_range = BufferOffset(context_buffer_range.start)
13904                                ..BufferOffset(context_buffer_range.end);
13905
13906                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13907                                .or_insert_with(|| RunnableTasks {
13908                                    templates: Vec::new(),
13909                                    offset,
13910                                    column: task_buffer_range.start.column,
13911                                    extra_variables: HashMap::default(),
13912                                    context_range,
13913                                })
13914                                .templates
13915                                .push((kind, task.original_task().clone()));
13916                        }
13917
13918                        acc
13919                    })
13920            }) else {
13921                return;
13922            };
13923
13924            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13925                buffer.language_settings(cx).tasks.prefer_lsp
13926            }) else {
13927                return;
13928            };
13929
13930            let rows = Self::runnable_rows(
13931                project,
13932                display_snapshot,
13933                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13934                new_rows,
13935                cx.clone(),
13936            );
13937            editor
13938                .update(cx, |editor, _| {
13939                    editor.clear_tasks();
13940                    for (key, mut value) in rows {
13941                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13942                            value.templates.extend(lsp_tasks.templates);
13943                        }
13944
13945                        editor.insert_tasks(key, value);
13946                    }
13947                    for (key, value) in lsp_tasks_by_rows {
13948                        editor.insert_tasks(key, value);
13949                    }
13950                })
13951                .ok();
13952        })
13953    }
13954    fn fetch_runnable_ranges(
13955        snapshot: &DisplaySnapshot,
13956        range: Range<Anchor>,
13957    ) -> Vec<language::RunnableRange> {
13958        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13959    }
13960
13961    fn runnable_rows(
13962        project: Entity<Project>,
13963        snapshot: DisplaySnapshot,
13964        prefer_lsp: bool,
13965        runnable_ranges: Vec<RunnableRange>,
13966        mut cx: AsyncWindowContext,
13967    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13968        runnable_ranges
13969            .into_iter()
13970            .filter_map(|mut runnable| {
13971                let mut tasks = cx
13972                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13973                    .ok()?;
13974                if prefer_lsp {
13975                    tasks.retain(|(task_kind, _)| {
13976                        !matches!(task_kind, TaskSourceKind::Language { .. })
13977                    });
13978                }
13979                if tasks.is_empty() {
13980                    return None;
13981                }
13982
13983                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13984
13985                let row = snapshot
13986                    .buffer_snapshot
13987                    .buffer_line_for_row(MultiBufferRow(point.row))?
13988                    .1
13989                    .start
13990                    .row;
13991
13992                let context_range =
13993                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13994                Some((
13995                    (runnable.buffer_id, row),
13996                    RunnableTasks {
13997                        templates: tasks,
13998                        offset: snapshot
13999                            .buffer_snapshot
14000                            .anchor_before(runnable.run_range.start),
14001                        context_range,
14002                        column: point.column,
14003                        extra_variables: runnable.extra_captures,
14004                    },
14005                ))
14006            })
14007            .collect()
14008    }
14009
14010    fn templates_with_tags(
14011        project: &Entity<Project>,
14012        runnable: &mut Runnable,
14013        cx: &mut App,
14014    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
14015        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14016            let (worktree_id, file) = project
14017                .buffer_for_id(runnable.buffer, cx)
14018                .and_then(|buffer| buffer.read(cx).file())
14019                .map(|file| (file.worktree_id(cx), file.clone()))
14020                .unzip();
14021
14022            (
14023                project.task_store().read(cx).task_inventory().cloned(),
14024                worktree_id,
14025                file,
14026            )
14027        });
14028
14029        let mut templates_with_tags = mem::take(&mut runnable.tags)
14030            .into_iter()
14031            .flat_map(|RunnableTag(tag)| {
14032                inventory
14033                    .as_ref()
14034                    .into_iter()
14035                    .flat_map(|inventory| {
14036                        inventory.read(cx).list_tasks(
14037                            file.clone(),
14038                            Some(runnable.language.clone()),
14039                            worktree_id,
14040                            cx,
14041                        )
14042                    })
14043                    .filter(move |(_, template)| {
14044                        template.tags.iter().any(|source_tag| source_tag == &tag)
14045                    })
14046            })
14047            .sorted_by_key(|(kind, _)| kind.to_owned())
14048            .collect::<Vec<_>>();
14049        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14050            // Strongest source wins; if we have worktree tag binding, prefer that to
14051            // global and language bindings;
14052            // if we have a global binding, prefer that to language binding.
14053            let first_mismatch = templates_with_tags
14054                .iter()
14055                .position(|(tag_source, _)| tag_source != leading_tag_source);
14056            if let Some(index) = first_mismatch {
14057                templates_with_tags.truncate(index);
14058            }
14059        }
14060
14061        templates_with_tags
14062    }
14063
14064    pub fn move_to_enclosing_bracket(
14065        &mut self,
14066        _: &MoveToEnclosingBracket,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) {
14070        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14071        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14072            s.move_offsets_with(|snapshot, selection| {
14073                let Some(enclosing_bracket_ranges) =
14074                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14075                else {
14076                    return;
14077                };
14078
14079                let mut best_length = usize::MAX;
14080                let mut best_inside = false;
14081                let mut best_in_bracket_range = false;
14082                let mut best_destination = None;
14083                for (open, close) in enclosing_bracket_ranges {
14084                    let close = close.to_inclusive();
14085                    let length = close.end() - open.start;
14086                    let inside = selection.start >= open.end && selection.end <= *close.start();
14087                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14088                        || close.contains(&selection.head());
14089
14090                    // If best is next to a bracket and current isn't, skip
14091                    if !in_bracket_range && best_in_bracket_range {
14092                        continue;
14093                    }
14094
14095                    // Prefer smaller lengths unless best is inside and current isn't
14096                    if length > best_length && (best_inside || !inside) {
14097                        continue;
14098                    }
14099
14100                    best_length = length;
14101                    best_inside = inside;
14102                    best_in_bracket_range = in_bracket_range;
14103                    best_destination = Some(
14104                        if close.contains(&selection.start) && close.contains(&selection.end) {
14105                            if inside { open.end } else { open.start }
14106                        } else if inside {
14107                            *close.start()
14108                        } else {
14109                            *close.end()
14110                        },
14111                    );
14112                }
14113
14114                if let Some(destination) = best_destination {
14115                    selection.collapse_to(destination, SelectionGoal::None);
14116                }
14117            })
14118        });
14119    }
14120
14121    pub fn undo_selection(
14122        &mut self,
14123        _: &UndoSelection,
14124        window: &mut Window,
14125        cx: &mut Context<Self>,
14126    ) {
14127        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14128        self.end_selection(window, cx);
14129        self.selection_history.mode = SelectionHistoryMode::Undoing;
14130        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14131            self.change_selections(None, window, cx, |s| {
14132                s.select_anchors(entry.selections.to_vec())
14133            });
14134            self.select_next_state = entry.select_next_state;
14135            self.select_prev_state = entry.select_prev_state;
14136            self.add_selections_state = entry.add_selections_state;
14137            self.request_autoscroll(Autoscroll::newest(), cx);
14138        }
14139        self.selection_history.mode = SelectionHistoryMode::Normal;
14140    }
14141
14142    pub fn redo_selection(
14143        &mut self,
14144        _: &RedoSelection,
14145        window: &mut Window,
14146        cx: &mut Context<Self>,
14147    ) {
14148        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14149        self.end_selection(window, cx);
14150        self.selection_history.mode = SelectionHistoryMode::Redoing;
14151        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14152            self.change_selections(None, window, cx, |s| {
14153                s.select_anchors(entry.selections.to_vec())
14154            });
14155            self.select_next_state = entry.select_next_state;
14156            self.select_prev_state = entry.select_prev_state;
14157            self.add_selections_state = entry.add_selections_state;
14158            self.request_autoscroll(Autoscroll::newest(), cx);
14159        }
14160        self.selection_history.mode = SelectionHistoryMode::Normal;
14161    }
14162
14163    pub fn expand_excerpts(
14164        &mut self,
14165        action: &ExpandExcerpts,
14166        _: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) {
14169        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14170    }
14171
14172    pub fn expand_excerpts_down(
14173        &mut self,
14174        action: &ExpandExcerptsDown,
14175        _: &mut Window,
14176        cx: &mut Context<Self>,
14177    ) {
14178        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14179    }
14180
14181    pub fn expand_excerpts_up(
14182        &mut self,
14183        action: &ExpandExcerptsUp,
14184        _: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14188    }
14189
14190    pub fn expand_excerpts_for_direction(
14191        &mut self,
14192        lines: u32,
14193        direction: ExpandExcerptDirection,
14194
14195        cx: &mut Context<Self>,
14196    ) {
14197        let selections = self.selections.disjoint_anchors();
14198
14199        let lines = if lines == 0 {
14200            EditorSettings::get_global(cx).expand_excerpt_lines
14201        } else {
14202            lines
14203        };
14204
14205        self.buffer.update(cx, |buffer, cx| {
14206            let snapshot = buffer.snapshot(cx);
14207            let mut excerpt_ids = selections
14208                .iter()
14209                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14210                .collect::<Vec<_>>();
14211            excerpt_ids.sort();
14212            excerpt_ids.dedup();
14213            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14214        })
14215    }
14216
14217    pub fn expand_excerpt(
14218        &mut self,
14219        excerpt: ExcerptId,
14220        direction: ExpandExcerptDirection,
14221        window: &mut Window,
14222        cx: &mut Context<Self>,
14223    ) {
14224        let current_scroll_position = self.scroll_position(cx);
14225        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14226        let mut should_scroll_up = false;
14227
14228        if direction == ExpandExcerptDirection::Down {
14229            let multi_buffer = self.buffer.read(cx);
14230            let snapshot = multi_buffer.snapshot(cx);
14231            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14232                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14233                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14234                        let buffer_snapshot = buffer.read(cx).snapshot();
14235                        let excerpt_end_row =
14236                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14237                        let last_row = buffer_snapshot.max_point().row;
14238                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14239                        should_scroll_up = lines_below >= lines_to_expand;
14240                    }
14241                }
14242            }
14243        }
14244
14245        self.buffer.update(cx, |buffer, cx| {
14246            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14247        });
14248
14249        if should_scroll_up {
14250            let new_scroll_position =
14251                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14252            self.set_scroll_position(new_scroll_position, window, cx);
14253        }
14254    }
14255
14256    pub fn go_to_singleton_buffer_point(
14257        &mut self,
14258        point: Point,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) {
14262        self.go_to_singleton_buffer_range(point..point, window, cx);
14263    }
14264
14265    pub fn go_to_singleton_buffer_range(
14266        &mut self,
14267        range: Range<Point>,
14268        window: &mut Window,
14269        cx: &mut Context<Self>,
14270    ) {
14271        let multibuffer = self.buffer().read(cx);
14272        let Some(buffer) = multibuffer.as_singleton() else {
14273            return;
14274        };
14275        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14276            return;
14277        };
14278        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14279            return;
14280        };
14281        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14282            s.select_anchor_ranges([start..end])
14283        });
14284    }
14285
14286    pub fn go_to_diagnostic(
14287        &mut self,
14288        _: &GoToDiagnostic,
14289        window: &mut Window,
14290        cx: &mut Context<Self>,
14291    ) {
14292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14293        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14294    }
14295
14296    pub fn go_to_prev_diagnostic(
14297        &mut self,
14298        _: &GoToPreviousDiagnostic,
14299        window: &mut Window,
14300        cx: &mut Context<Self>,
14301    ) {
14302        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14303        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14304    }
14305
14306    pub fn go_to_diagnostic_impl(
14307        &mut self,
14308        direction: Direction,
14309        window: &mut Window,
14310        cx: &mut Context<Self>,
14311    ) {
14312        let buffer = self.buffer.read(cx).snapshot(cx);
14313        let selection = self.selections.newest::<usize>(cx);
14314
14315        let mut active_group_id = None;
14316        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14317            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14318                active_group_id = Some(active_group.group_id);
14319            }
14320        }
14321
14322        fn filtered(
14323            snapshot: EditorSnapshot,
14324            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14325        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14326            diagnostics
14327                .filter(|entry| entry.range.start != entry.range.end)
14328                .filter(|entry| !entry.diagnostic.is_unnecessary)
14329                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14330        }
14331
14332        let snapshot = self.snapshot(window, cx);
14333        let before = filtered(
14334            snapshot.clone(),
14335            buffer
14336                .diagnostics_in_range(0..selection.start)
14337                .filter(|entry| entry.range.start <= selection.start),
14338        );
14339        let after = filtered(
14340            snapshot,
14341            buffer
14342                .diagnostics_in_range(selection.start..buffer.len())
14343                .filter(|entry| entry.range.start >= selection.start),
14344        );
14345
14346        let mut found: Option<DiagnosticEntry<usize>> = None;
14347        if direction == Direction::Prev {
14348            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14349            {
14350                for diagnostic in prev_diagnostics.into_iter().rev() {
14351                    if diagnostic.range.start != selection.start
14352                        || active_group_id
14353                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14354                    {
14355                        found = Some(diagnostic);
14356                        break 'outer;
14357                    }
14358                }
14359            }
14360        } else {
14361            for diagnostic in after.chain(before) {
14362                if diagnostic.range.start != selection.start
14363                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14364                {
14365                    found = Some(diagnostic);
14366                    break;
14367                }
14368            }
14369        }
14370        let Some(next_diagnostic) = found else {
14371            return;
14372        };
14373
14374        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14375            return;
14376        };
14377        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14378            s.select_ranges(vec![
14379                next_diagnostic.range.start..next_diagnostic.range.start,
14380            ])
14381        });
14382        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14383        self.refresh_inline_completion(false, true, window, cx);
14384    }
14385
14386    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14387        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14388        let snapshot = self.snapshot(window, cx);
14389        let selection = self.selections.newest::<Point>(cx);
14390        self.go_to_hunk_before_or_after_position(
14391            &snapshot,
14392            selection.head(),
14393            Direction::Next,
14394            window,
14395            cx,
14396        );
14397    }
14398
14399    pub fn go_to_hunk_before_or_after_position(
14400        &mut self,
14401        snapshot: &EditorSnapshot,
14402        position: Point,
14403        direction: Direction,
14404        window: &mut Window,
14405        cx: &mut Context<Editor>,
14406    ) {
14407        let row = if direction == Direction::Next {
14408            self.hunk_after_position(snapshot, position)
14409                .map(|hunk| hunk.row_range.start)
14410        } else {
14411            self.hunk_before_position(snapshot, position)
14412        };
14413
14414        if let Some(row) = row {
14415            let destination = Point::new(row.0, 0);
14416            let autoscroll = Autoscroll::center();
14417
14418            self.unfold_ranges(&[destination..destination], false, false, cx);
14419            self.change_selections(Some(autoscroll), window, cx, |s| {
14420                s.select_ranges([destination..destination]);
14421            });
14422        }
14423    }
14424
14425    fn hunk_after_position(
14426        &mut self,
14427        snapshot: &EditorSnapshot,
14428        position: Point,
14429    ) -> Option<MultiBufferDiffHunk> {
14430        snapshot
14431            .buffer_snapshot
14432            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14433            .find(|hunk| hunk.row_range.start.0 > position.row)
14434            .or_else(|| {
14435                snapshot
14436                    .buffer_snapshot
14437                    .diff_hunks_in_range(Point::zero()..position)
14438                    .find(|hunk| hunk.row_range.end.0 < position.row)
14439            })
14440    }
14441
14442    fn go_to_prev_hunk(
14443        &mut self,
14444        _: &GoToPreviousHunk,
14445        window: &mut Window,
14446        cx: &mut Context<Self>,
14447    ) {
14448        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14449        let snapshot = self.snapshot(window, cx);
14450        let selection = self.selections.newest::<Point>(cx);
14451        self.go_to_hunk_before_or_after_position(
14452            &snapshot,
14453            selection.head(),
14454            Direction::Prev,
14455            window,
14456            cx,
14457        );
14458    }
14459
14460    fn hunk_before_position(
14461        &mut self,
14462        snapshot: &EditorSnapshot,
14463        position: Point,
14464    ) -> Option<MultiBufferRow> {
14465        snapshot
14466            .buffer_snapshot
14467            .diff_hunk_before(position)
14468            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14469    }
14470
14471    fn go_to_next_change(
14472        &mut self,
14473        _: &GoToNextChange,
14474        window: &mut Window,
14475        cx: &mut Context<Self>,
14476    ) {
14477        if let Some(selections) = self
14478            .change_list
14479            .next_change(1, Direction::Next)
14480            .map(|s| s.to_vec())
14481        {
14482            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14483                let map = s.display_map();
14484                s.select_display_ranges(selections.iter().map(|a| {
14485                    let point = a.to_display_point(&map);
14486                    point..point
14487                }))
14488            })
14489        }
14490    }
14491
14492    fn go_to_previous_change(
14493        &mut self,
14494        _: &GoToPreviousChange,
14495        window: &mut Window,
14496        cx: &mut Context<Self>,
14497    ) {
14498        if let Some(selections) = self
14499            .change_list
14500            .next_change(1, Direction::Prev)
14501            .map(|s| s.to_vec())
14502        {
14503            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14504                let map = s.display_map();
14505                s.select_display_ranges(selections.iter().map(|a| {
14506                    let point = a.to_display_point(&map);
14507                    point..point
14508                }))
14509            })
14510        }
14511    }
14512
14513    fn go_to_line<T: 'static>(
14514        &mut self,
14515        position: Anchor,
14516        highlight_color: Option<Hsla>,
14517        window: &mut Window,
14518        cx: &mut Context<Self>,
14519    ) {
14520        let snapshot = self.snapshot(window, cx).display_snapshot;
14521        let position = position.to_point(&snapshot.buffer_snapshot);
14522        let start = snapshot
14523            .buffer_snapshot
14524            .clip_point(Point::new(position.row, 0), Bias::Left);
14525        let end = start + Point::new(1, 0);
14526        let start = snapshot.buffer_snapshot.anchor_before(start);
14527        let end = snapshot.buffer_snapshot.anchor_before(end);
14528
14529        self.highlight_rows::<T>(
14530            start..end,
14531            highlight_color
14532                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14533            Default::default(),
14534            cx,
14535        );
14536
14537        if self.buffer.read(cx).is_singleton() {
14538            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14539        }
14540    }
14541
14542    pub fn go_to_definition(
14543        &mut self,
14544        _: &GoToDefinition,
14545        window: &mut Window,
14546        cx: &mut Context<Self>,
14547    ) -> Task<Result<Navigated>> {
14548        let definition =
14549            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14550        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14551        cx.spawn_in(window, async move |editor, cx| {
14552            if definition.await? == Navigated::Yes {
14553                return Ok(Navigated::Yes);
14554            }
14555            match fallback_strategy {
14556                GoToDefinitionFallback::None => Ok(Navigated::No),
14557                GoToDefinitionFallback::FindAllReferences => {
14558                    match editor.update_in(cx, |editor, window, cx| {
14559                        editor.find_all_references(&FindAllReferences, window, cx)
14560                    })? {
14561                        Some(references) => references.await,
14562                        None => Ok(Navigated::No),
14563                    }
14564                }
14565            }
14566        })
14567    }
14568
14569    pub fn go_to_declaration(
14570        &mut self,
14571        _: &GoToDeclaration,
14572        window: &mut Window,
14573        cx: &mut Context<Self>,
14574    ) -> Task<Result<Navigated>> {
14575        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14576    }
14577
14578    pub fn go_to_declaration_split(
14579        &mut self,
14580        _: &GoToDeclaration,
14581        window: &mut Window,
14582        cx: &mut Context<Self>,
14583    ) -> Task<Result<Navigated>> {
14584        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14585    }
14586
14587    pub fn go_to_implementation(
14588        &mut self,
14589        _: &GoToImplementation,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) -> Task<Result<Navigated>> {
14593        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14594    }
14595
14596    pub fn go_to_implementation_split(
14597        &mut self,
14598        _: &GoToImplementationSplit,
14599        window: &mut Window,
14600        cx: &mut Context<Self>,
14601    ) -> Task<Result<Navigated>> {
14602        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14603    }
14604
14605    pub fn go_to_type_definition(
14606        &mut self,
14607        _: &GoToTypeDefinition,
14608        window: &mut Window,
14609        cx: &mut Context<Self>,
14610    ) -> Task<Result<Navigated>> {
14611        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14612    }
14613
14614    pub fn go_to_definition_split(
14615        &mut self,
14616        _: &GoToDefinitionSplit,
14617        window: &mut Window,
14618        cx: &mut Context<Self>,
14619    ) -> Task<Result<Navigated>> {
14620        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14621    }
14622
14623    pub fn go_to_type_definition_split(
14624        &mut self,
14625        _: &GoToTypeDefinitionSplit,
14626        window: &mut Window,
14627        cx: &mut Context<Self>,
14628    ) -> Task<Result<Navigated>> {
14629        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14630    }
14631
14632    fn go_to_definition_of_kind(
14633        &mut self,
14634        kind: GotoDefinitionKind,
14635        split: bool,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) -> Task<Result<Navigated>> {
14639        let Some(provider) = self.semantics_provider.clone() else {
14640            return Task::ready(Ok(Navigated::No));
14641        };
14642        let head = self.selections.newest::<usize>(cx).head();
14643        let buffer = self.buffer.read(cx);
14644        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14645            text_anchor
14646        } else {
14647            return Task::ready(Ok(Navigated::No));
14648        };
14649
14650        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14651            return Task::ready(Ok(Navigated::No));
14652        };
14653
14654        cx.spawn_in(window, async move |editor, cx| {
14655            let definitions = definitions.await?;
14656            let navigated = editor
14657                .update_in(cx, |editor, window, cx| {
14658                    editor.navigate_to_hover_links(
14659                        Some(kind),
14660                        definitions
14661                            .into_iter()
14662                            .filter(|location| {
14663                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14664                            })
14665                            .map(HoverLink::Text)
14666                            .collect::<Vec<_>>(),
14667                        split,
14668                        window,
14669                        cx,
14670                    )
14671                })?
14672                .await?;
14673            anyhow::Ok(navigated)
14674        })
14675    }
14676
14677    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14678        let selection = self.selections.newest_anchor();
14679        let head = selection.head();
14680        let tail = selection.tail();
14681
14682        let Some((buffer, start_position)) =
14683            self.buffer.read(cx).text_anchor_for_position(head, cx)
14684        else {
14685            return;
14686        };
14687
14688        let end_position = if head != tail {
14689            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14690                return;
14691            };
14692            Some(pos)
14693        } else {
14694            None
14695        };
14696
14697        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14698            let url = if let Some(end_pos) = end_position {
14699                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14700            } else {
14701                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14702            };
14703
14704            if let Some(url) = url {
14705                editor.update(cx, |_, cx| {
14706                    cx.open_url(&url);
14707                })
14708            } else {
14709                Ok(())
14710            }
14711        });
14712
14713        url_finder.detach();
14714    }
14715
14716    pub fn open_selected_filename(
14717        &mut self,
14718        _: &OpenSelectedFilename,
14719        window: &mut Window,
14720        cx: &mut Context<Self>,
14721    ) {
14722        let Some(workspace) = self.workspace() else {
14723            return;
14724        };
14725
14726        let position = self.selections.newest_anchor().head();
14727
14728        let Some((buffer, buffer_position)) =
14729            self.buffer.read(cx).text_anchor_for_position(position, cx)
14730        else {
14731            return;
14732        };
14733
14734        let project = self.project.clone();
14735
14736        cx.spawn_in(window, async move |_, cx| {
14737            let result = find_file(&buffer, project, buffer_position, cx).await;
14738
14739            if let Some((_, path)) = result {
14740                workspace
14741                    .update_in(cx, |workspace, window, cx| {
14742                        workspace.open_resolved_path(path, window, cx)
14743                    })?
14744                    .await?;
14745            }
14746            anyhow::Ok(())
14747        })
14748        .detach();
14749    }
14750
14751    pub(crate) fn navigate_to_hover_links(
14752        &mut self,
14753        kind: Option<GotoDefinitionKind>,
14754        mut definitions: Vec<HoverLink>,
14755        split: bool,
14756        window: &mut Window,
14757        cx: &mut Context<Editor>,
14758    ) -> Task<Result<Navigated>> {
14759        // If there is one definition, just open it directly
14760        if definitions.len() == 1 {
14761            let definition = definitions.pop().unwrap();
14762
14763            enum TargetTaskResult {
14764                Location(Option<Location>),
14765                AlreadyNavigated,
14766            }
14767
14768            let target_task = match definition {
14769                HoverLink::Text(link) => {
14770                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14771                }
14772                HoverLink::InlayHint(lsp_location, server_id) => {
14773                    let computation =
14774                        self.compute_target_location(lsp_location, server_id, window, cx);
14775                    cx.background_spawn(async move {
14776                        let location = computation.await?;
14777                        Ok(TargetTaskResult::Location(location))
14778                    })
14779                }
14780                HoverLink::Url(url) => {
14781                    cx.open_url(&url);
14782                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14783                }
14784                HoverLink::File(path) => {
14785                    if let Some(workspace) = self.workspace() {
14786                        cx.spawn_in(window, async move |_, cx| {
14787                            workspace
14788                                .update_in(cx, |workspace, window, cx| {
14789                                    workspace.open_resolved_path(path, window, cx)
14790                                })?
14791                                .await
14792                                .map(|_| TargetTaskResult::AlreadyNavigated)
14793                        })
14794                    } else {
14795                        Task::ready(Ok(TargetTaskResult::Location(None)))
14796                    }
14797                }
14798            };
14799            cx.spawn_in(window, async move |editor, cx| {
14800                let target = match target_task.await.context("target resolution task")? {
14801                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14802                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14803                    TargetTaskResult::Location(Some(target)) => target,
14804                };
14805
14806                editor.update_in(cx, |editor, window, cx| {
14807                    let Some(workspace) = editor.workspace() else {
14808                        return Navigated::No;
14809                    };
14810                    let pane = workspace.read(cx).active_pane().clone();
14811
14812                    let range = target.range.to_point(target.buffer.read(cx));
14813                    let range = editor.range_for_match(&range);
14814                    let range = collapse_multiline_range(range);
14815
14816                    if !split
14817                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14818                    {
14819                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14820                    } else {
14821                        window.defer(cx, move |window, cx| {
14822                            let target_editor: Entity<Self> =
14823                                workspace.update(cx, |workspace, cx| {
14824                                    let pane = if split {
14825                                        workspace.adjacent_pane(window, cx)
14826                                    } else {
14827                                        workspace.active_pane().clone()
14828                                    };
14829
14830                                    workspace.open_project_item(
14831                                        pane,
14832                                        target.buffer.clone(),
14833                                        true,
14834                                        true,
14835                                        window,
14836                                        cx,
14837                                    )
14838                                });
14839                            target_editor.update(cx, |target_editor, cx| {
14840                                // When selecting a definition in a different buffer, disable the nav history
14841                                // to avoid creating a history entry at the previous cursor location.
14842                                pane.update(cx, |pane, _| pane.disable_history());
14843                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14844                                pane.update(cx, |pane, _| pane.enable_history());
14845                            });
14846                        });
14847                    }
14848                    Navigated::Yes
14849                })
14850            })
14851        } else if !definitions.is_empty() {
14852            cx.spawn_in(window, async move |editor, cx| {
14853                let (title, location_tasks, workspace) = editor
14854                    .update_in(cx, |editor, window, cx| {
14855                        let tab_kind = match kind {
14856                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14857                            _ => "Definitions",
14858                        };
14859                        let title = definitions
14860                            .iter()
14861                            .find_map(|definition| match definition {
14862                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14863                                    let buffer = origin.buffer.read(cx);
14864                                    format!(
14865                                        "{} for {}",
14866                                        tab_kind,
14867                                        buffer
14868                                            .text_for_range(origin.range.clone())
14869                                            .collect::<String>()
14870                                    )
14871                                }),
14872                                HoverLink::InlayHint(_, _) => None,
14873                                HoverLink::Url(_) => None,
14874                                HoverLink::File(_) => None,
14875                            })
14876                            .unwrap_or(tab_kind.to_string());
14877                        let location_tasks = definitions
14878                            .into_iter()
14879                            .map(|definition| match definition {
14880                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14881                                HoverLink::InlayHint(lsp_location, server_id) => editor
14882                                    .compute_target_location(lsp_location, server_id, window, cx),
14883                                HoverLink::Url(_) => Task::ready(Ok(None)),
14884                                HoverLink::File(_) => Task::ready(Ok(None)),
14885                            })
14886                            .collect::<Vec<_>>();
14887                        (title, location_tasks, editor.workspace().clone())
14888                    })
14889                    .context("location tasks preparation")?;
14890
14891                let locations = future::join_all(location_tasks)
14892                    .await
14893                    .into_iter()
14894                    .filter_map(|location| location.transpose())
14895                    .collect::<Result<_>>()
14896                    .context("location tasks")?;
14897
14898                let Some(workspace) = workspace else {
14899                    return Ok(Navigated::No);
14900                };
14901                let opened = workspace
14902                    .update_in(cx, |workspace, window, cx| {
14903                        Self::open_locations_in_multibuffer(
14904                            workspace,
14905                            locations,
14906                            title,
14907                            split,
14908                            MultibufferSelectionMode::First,
14909                            window,
14910                            cx,
14911                        )
14912                    })
14913                    .ok();
14914
14915                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14916            })
14917        } else {
14918            Task::ready(Ok(Navigated::No))
14919        }
14920    }
14921
14922    fn compute_target_location(
14923        &self,
14924        lsp_location: lsp::Location,
14925        server_id: LanguageServerId,
14926        window: &mut Window,
14927        cx: &mut Context<Self>,
14928    ) -> Task<anyhow::Result<Option<Location>>> {
14929        let Some(project) = self.project.clone() else {
14930            return Task::ready(Ok(None));
14931        };
14932
14933        cx.spawn_in(window, async move |editor, cx| {
14934            let location_task = editor.update(cx, |_, cx| {
14935                project.update(cx, |project, cx| {
14936                    let language_server_name = project
14937                        .language_server_statuses(cx)
14938                        .find(|(id, _)| server_id == *id)
14939                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14940                    language_server_name.map(|language_server_name| {
14941                        project.open_local_buffer_via_lsp(
14942                            lsp_location.uri.clone(),
14943                            server_id,
14944                            language_server_name,
14945                            cx,
14946                        )
14947                    })
14948                })
14949            })?;
14950            let location = match location_task {
14951                Some(task) => Some({
14952                    let target_buffer_handle = task.await.context("open local buffer")?;
14953                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14954                        let target_start = target_buffer
14955                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14956                        let target_end = target_buffer
14957                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14958                        target_buffer.anchor_after(target_start)
14959                            ..target_buffer.anchor_before(target_end)
14960                    })?;
14961                    Location {
14962                        buffer: target_buffer_handle,
14963                        range,
14964                    }
14965                }),
14966                None => None,
14967            };
14968            Ok(location)
14969        })
14970    }
14971
14972    pub fn find_all_references(
14973        &mut self,
14974        _: &FindAllReferences,
14975        window: &mut Window,
14976        cx: &mut Context<Self>,
14977    ) -> Option<Task<Result<Navigated>>> {
14978        let selection = self.selections.newest::<usize>(cx);
14979        let multi_buffer = self.buffer.read(cx);
14980        let head = selection.head();
14981
14982        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14983        let head_anchor = multi_buffer_snapshot.anchor_at(
14984            head,
14985            if head < selection.tail() {
14986                Bias::Right
14987            } else {
14988                Bias::Left
14989            },
14990        );
14991
14992        match self
14993            .find_all_references_task_sources
14994            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14995        {
14996            Ok(_) => {
14997                log::info!(
14998                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14999                );
15000                return None;
15001            }
15002            Err(i) => {
15003                self.find_all_references_task_sources.insert(i, head_anchor);
15004            }
15005        }
15006
15007        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15008        let workspace = self.workspace()?;
15009        let project = workspace.read(cx).project().clone();
15010        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15011        Some(cx.spawn_in(window, async move |editor, cx| {
15012            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15013                if let Ok(i) = editor
15014                    .find_all_references_task_sources
15015                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15016                {
15017                    editor.find_all_references_task_sources.remove(i);
15018                }
15019            });
15020
15021            let locations = references.await?;
15022            if locations.is_empty() {
15023                return anyhow::Ok(Navigated::No);
15024            }
15025
15026            workspace.update_in(cx, |workspace, window, cx| {
15027                let title = locations
15028                    .first()
15029                    .as_ref()
15030                    .map(|location| {
15031                        let buffer = location.buffer.read(cx);
15032                        format!(
15033                            "References to `{}`",
15034                            buffer
15035                                .text_for_range(location.range.clone())
15036                                .collect::<String>()
15037                        )
15038                    })
15039                    .unwrap();
15040                Self::open_locations_in_multibuffer(
15041                    workspace,
15042                    locations,
15043                    title,
15044                    false,
15045                    MultibufferSelectionMode::First,
15046                    window,
15047                    cx,
15048                );
15049                Navigated::Yes
15050            })
15051        }))
15052    }
15053
15054    /// Opens a multibuffer with the given project locations in it
15055    pub fn open_locations_in_multibuffer(
15056        workspace: &mut Workspace,
15057        mut locations: Vec<Location>,
15058        title: String,
15059        split: bool,
15060        multibuffer_selection_mode: MultibufferSelectionMode,
15061        window: &mut Window,
15062        cx: &mut Context<Workspace>,
15063    ) {
15064        // If there are multiple definitions, open them in a multibuffer
15065        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15066        let mut locations = locations.into_iter().peekable();
15067        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15068        let capability = workspace.project().read(cx).capability();
15069
15070        let excerpt_buffer = cx.new(|cx| {
15071            let mut multibuffer = MultiBuffer::new(capability);
15072            while let Some(location) = locations.next() {
15073                let buffer = location.buffer.read(cx);
15074                let mut ranges_for_buffer = Vec::new();
15075                let range = location.range.to_point(buffer);
15076                ranges_for_buffer.push(range.clone());
15077
15078                while let Some(next_location) = locations.peek() {
15079                    if next_location.buffer == location.buffer {
15080                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15081                        locations.next();
15082                    } else {
15083                        break;
15084                    }
15085                }
15086
15087                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15088                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15089                    PathKey::for_buffer(&location.buffer, cx),
15090                    location.buffer.clone(),
15091                    ranges_for_buffer,
15092                    DEFAULT_MULTIBUFFER_CONTEXT,
15093                    cx,
15094                );
15095                ranges.extend(new_ranges)
15096            }
15097
15098            multibuffer.with_title(title)
15099        });
15100
15101        let editor = cx.new(|cx| {
15102            Editor::for_multibuffer(
15103                excerpt_buffer,
15104                Some(workspace.project().clone()),
15105                window,
15106                cx,
15107            )
15108        });
15109        editor.update(cx, |editor, cx| {
15110            match multibuffer_selection_mode {
15111                MultibufferSelectionMode::First => {
15112                    if let Some(first_range) = ranges.first() {
15113                        editor.change_selections(None, window, cx, |selections| {
15114                            selections.clear_disjoint();
15115                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15116                        });
15117                    }
15118                    editor.highlight_background::<Self>(
15119                        &ranges,
15120                        |theme| theme.editor_highlighted_line_background,
15121                        cx,
15122                    );
15123                }
15124                MultibufferSelectionMode::All => {
15125                    editor.change_selections(None, window, cx, |selections| {
15126                        selections.clear_disjoint();
15127                        selections.select_anchor_ranges(ranges);
15128                    });
15129                }
15130            }
15131            editor.register_buffers_with_language_servers(cx);
15132        });
15133
15134        let item = Box::new(editor);
15135        let item_id = item.item_id();
15136
15137        if split {
15138            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15139        } else {
15140            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15141                let (preview_item_id, preview_item_idx) =
15142                    workspace.active_pane().read_with(cx, |pane, _| {
15143                        (pane.preview_item_id(), pane.preview_item_idx())
15144                    });
15145
15146                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15147
15148                if let Some(preview_item_id) = preview_item_id {
15149                    workspace.active_pane().update(cx, |pane, cx| {
15150                        pane.remove_item(preview_item_id, false, false, window, cx);
15151                    });
15152                }
15153            } else {
15154                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15155            }
15156        }
15157        workspace.active_pane().update(cx, |pane, cx| {
15158            pane.set_preview_item_id(Some(item_id), cx);
15159        });
15160    }
15161
15162    pub fn rename(
15163        &mut self,
15164        _: &Rename,
15165        window: &mut Window,
15166        cx: &mut Context<Self>,
15167    ) -> Option<Task<Result<()>>> {
15168        use language::ToOffset as _;
15169
15170        let provider = self.semantics_provider.clone()?;
15171        let selection = self.selections.newest_anchor().clone();
15172        let (cursor_buffer, cursor_buffer_position) = self
15173            .buffer
15174            .read(cx)
15175            .text_anchor_for_position(selection.head(), cx)?;
15176        let (tail_buffer, cursor_buffer_position_end) = self
15177            .buffer
15178            .read(cx)
15179            .text_anchor_for_position(selection.tail(), cx)?;
15180        if tail_buffer != cursor_buffer {
15181            return None;
15182        }
15183
15184        let snapshot = cursor_buffer.read(cx).snapshot();
15185        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15186        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15187        let prepare_rename = provider
15188            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15189            .unwrap_or_else(|| Task::ready(Ok(None)));
15190        drop(snapshot);
15191
15192        Some(cx.spawn_in(window, async move |this, cx| {
15193            let rename_range = if let Some(range) = prepare_rename.await? {
15194                Some(range)
15195            } else {
15196                this.update(cx, |this, cx| {
15197                    let buffer = this.buffer.read(cx).snapshot(cx);
15198                    let mut buffer_highlights = this
15199                        .document_highlights_for_position(selection.head(), &buffer)
15200                        .filter(|highlight| {
15201                            highlight.start.excerpt_id == selection.head().excerpt_id
15202                                && highlight.end.excerpt_id == selection.head().excerpt_id
15203                        });
15204                    buffer_highlights
15205                        .next()
15206                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15207                })?
15208            };
15209            if let Some(rename_range) = rename_range {
15210                this.update_in(cx, |this, window, cx| {
15211                    let snapshot = cursor_buffer.read(cx).snapshot();
15212                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15213                    let cursor_offset_in_rename_range =
15214                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15215                    let cursor_offset_in_rename_range_end =
15216                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15217
15218                    this.take_rename(false, window, cx);
15219                    let buffer = this.buffer.read(cx).read(cx);
15220                    let cursor_offset = selection.head().to_offset(&buffer);
15221                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15222                    let rename_end = rename_start + rename_buffer_range.len();
15223                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15224                    let mut old_highlight_id = None;
15225                    let old_name: Arc<str> = buffer
15226                        .chunks(rename_start..rename_end, true)
15227                        .map(|chunk| {
15228                            if old_highlight_id.is_none() {
15229                                old_highlight_id = chunk.syntax_highlight_id;
15230                            }
15231                            chunk.text
15232                        })
15233                        .collect::<String>()
15234                        .into();
15235
15236                    drop(buffer);
15237
15238                    // Position the selection in the rename editor so that it matches the current selection.
15239                    this.show_local_selections = false;
15240                    let rename_editor = cx.new(|cx| {
15241                        let mut editor = Editor::single_line(window, cx);
15242                        editor.buffer.update(cx, |buffer, cx| {
15243                            buffer.edit([(0..0, old_name.clone())], None, cx)
15244                        });
15245                        let rename_selection_range = match cursor_offset_in_rename_range
15246                            .cmp(&cursor_offset_in_rename_range_end)
15247                        {
15248                            Ordering::Equal => {
15249                                editor.select_all(&SelectAll, window, cx);
15250                                return editor;
15251                            }
15252                            Ordering::Less => {
15253                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15254                            }
15255                            Ordering::Greater => {
15256                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15257                            }
15258                        };
15259                        if rename_selection_range.end > old_name.len() {
15260                            editor.select_all(&SelectAll, window, cx);
15261                        } else {
15262                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15263                                s.select_ranges([rename_selection_range]);
15264                            });
15265                        }
15266                        editor
15267                    });
15268                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15269                        if e == &EditorEvent::Focused {
15270                            cx.emit(EditorEvent::FocusedIn)
15271                        }
15272                    })
15273                    .detach();
15274
15275                    let write_highlights =
15276                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15277                    let read_highlights =
15278                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15279                    let ranges = write_highlights
15280                        .iter()
15281                        .flat_map(|(_, ranges)| ranges.iter())
15282                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15283                        .cloned()
15284                        .collect();
15285
15286                    this.highlight_text::<Rename>(
15287                        ranges,
15288                        HighlightStyle {
15289                            fade_out: Some(0.6),
15290                            ..Default::default()
15291                        },
15292                        cx,
15293                    );
15294                    let rename_focus_handle = rename_editor.focus_handle(cx);
15295                    window.focus(&rename_focus_handle);
15296                    let block_id = this.insert_blocks(
15297                        [BlockProperties {
15298                            style: BlockStyle::Flex,
15299                            placement: BlockPlacement::Below(range.start),
15300                            height: Some(1),
15301                            render: Arc::new({
15302                                let rename_editor = rename_editor.clone();
15303                                move |cx: &mut BlockContext| {
15304                                    let mut text_style = cx.editor_style.text.clone();
15305                                    if let Some(highlight_style) = old_highlight_id
15306                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15307                                    {
15308                                        text_style = text_style.highlight(highlight_style);
15309                                    }
15310                                    div()
15311                                        .block_mouse_except_scroll()
15312                                        .pl(cx.anchor_x)
15313                                        .child(EditorElement::new(
15314                                            &rename_editor,
15315                                            EditorStyle {
15316                                                background: cx.theme().system().transparent,
15317                                                local_player: cx.editor_style.local_player,
15318                                                text: text_style,
15319                                                scrollbar_width: cx.editor_style.scrollbar_width,
15320                                                syntax: cx.editor_style.syntax.clone(),
15321                                                status: cx.editor_style.status.clone(),
15322                                                inlay_hints_style: HighlightStyle {
15323                                                    font_weight: Some(FontWeight::BOLD),
15324                                                    ..make_inlay_hints_style(cx.app)
15325                                                },
15326                                                inline_completion_styles: make_suggestion_styles(
15327                                                    cx.app,
15328                                                ),
15329                                                ..EditorStyle::default()
15330                                            },
15331                                        ))
15332                                        .into_any_element()
15333                                }
15334                            }),
15335                            priority: 0,
15336                            render_in_minimap: true,
15337                        }],
15338                        Some(Autoscroll::fit()),
15339                        cx,
15340                    )[0];
15341                    this.pending_rename = Some(RenameState {
15342                        range,
15343                        old_name,
15344                        editor: rename_editor,
15345                        block_id,
15346                    });
15347                })?;
15348            }
15349
15350            Ok(())
15351        }))
15352    }
15353
15354    pub fn confirm_rename(
15355        &mut self,
15356        _: &ConfirmRename,
15357        window: &mut Window,
15358        cx: &mut Context<Self>,
15359    ) -> Option<Task<Result<()>>> {
15360        let rename = self.take_rename(false, window, cx)?;
15361        let workspace = self.workspace()?.downgrade();
15362        let (buffer, start) = self
15363            .buffer
15364            .read(cx)
15365            .text_anchor_for_position(rename.range.start, cx)?;
15366        let (end_buffer, _) = self
15367            .buffer
15368            .read(cx)
15369            .text_anchor_for_position(rename.range.end, cx)?;
15370        if buffer != end_buffer {
15371            return None;
15372        }
15373
15374        let old_name = rename.old_name;
15375        let new_name = rename.editor.read(cx).text(cx);
15376
15377        let rename = self.semantics_provider.as_ref()?.perform_rename(
15378            &buffer,
15379            start,
15380            new_name.clone(),
15381            cx,
15382        )?;
15383
15384        Some(cx.spawn_in(window, async move |editor, cx| {
15385            let project_transaction = rename.await?;
15386            Self::open_project_transaction(
15387                &editor,
15388                workspace,
15389                project_transaction,
15390                format!("Rename: {}{}", old_name, new_name),
15391                cx,
15392            )
15393            .await?;
15394
15395            editor.update(cx, |editor, cx| {
15396                editor.refresh_document_highlights(cx);
15397            })?;
15398            Ok(())
15399        }))
15400    }
15401
15402    fn take_rename(
15403        &mut self,
15404        moving_cursor: bool,
15405        window: &mut Window,
15406        cx: &mut Context<Self>,
15407    ) -> Option<RenameState> {
15408        let rename = self.pending_rename.take()?;
15409        if rename.editor.focus_handle(cx).is_focused(window) {
15410            window.focus(&self.focus_handle);
15411        }
15412
15413        self.remove_blocks(
15414            [rename.block_id].into_iter().collect(),
15415            Some(Autoscroll::fit()),
15416            cx,
15417        );
15418        self.clear_highlights::<Rename>(cx);
15419        self.show_local_selections = true;
15420
15421        if moving_cursor {
15422            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15423                editor.selections.newest::<usize>(cx).head()
15424            });
15425
15426            // Update the selection to match the position of the selection inside
15427            // the rename editor.
15428            let snapshot = self.buffer.read(cx).read(cx);
15429            let rename_range = rename.range.to_offset(&snapshot);
15430            let cursor_in_editor = snapshot
15431                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15432                .min(rename_range.end);
15433            drop(snapshot);
15434
15435            self.change_selections(None, window, cx, |s| {
15436                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15437            });
15438        } else {
15439            self.refresh_document_highlights(cx);
15440        }
15441
15442        Some(rename)
15443    }
15444
15445    pub fn pending_rename(&self) -> Option<&RenameState> {
15446        self.pending_rename.as_ref()
15447    }
15448
15449    fn format(
15450        &mut self,
15451        _: &Format,
15452        window: &mut Window,
15453        cx: &mut Context<Self>,
15454    ) -> Option<Task<Result<()>>> {
15455        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15456
15457        let project = match &self.project {
15458            Some(project) => project.clone(),
15459            None => return None,
15460        };
15461
15462        Some(self.perform_format(
15463            project,
15464            FormatTrigger::Manual,
15465            FormatTarget::Buffers,
15466            window,
15467            cx,
15468        ))
15469    }
15470
15471    fn format_selections(
15472        &mut self,
15473        _: &FormatSelections,
15474        window: &mut Window,
15475        cx: &mut Context<Self>,
15476    ) -> Option<Task<Result<()>>> {
15477        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15478
15479        let project = match &self.project {
15480            Some(project) => project.clone(),
15481            None => return None,
15482        };
15483
15484        let ranges = self
15485            .selections
15486            .all_adjusted(cx)
15487            .into_iter()
15488            .map(|selection| selection.range())
15489            .collect_vec();
15490
15491        Some(self.perform_format(
15492            project,
15493            FormatTrigger::Manual,
15494            FormatTarget::Ranges(ranges),
15495            window,
15496            cx,
15497        ))
15498    }
15499
15500    fn perform_format(
15501        &mut self,
15502        project: Entity<Project>,
15503        trigger: FormatTrigger,
15504        target: FormatTarget,
15505        window: &mut Window,
15506        cx: &mut Context<Self>,
15507    ) -> Task<Result<()>> {
15508        let buffer = self.buffer.clone();
15509        let (buffers, target) = match target {
15510            FormatTarget::Buffers => {
15511                let mut buffers = buffer.read(cx).all_buffers();
15512                if trigger == FormatTrigger::Save {
15513                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15514                }
15515                (buffers, LspFormatTarget::Buffers)
15516            }
15517            FormatTarget::Ranges(selection_ranges) => {
15518                let multi_buffer = buffer.read(cx);
15519                let snapshot = multi_buffer.read(cx);
15520                let mut buffers = HashSet::default();
15521                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15522                    BTreeMap::new();
15523                for selection_range in selection_ranges {
15524                    for (buffer, buffer_range, _) in
15525                        snapshot.range_to_buffer_ranges(selection_range)
15526                    {
15527                        let buffer_id = buffer.remote_id();
15528                        let start = buffer.anchor_before(buffer_range.start);
15529                        let end = buffer.anchor_after(buffer_range.end);
15530                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15531                        buffer_id_to_ranges
15532                            .entry(buffer_id)
15533                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15534                            .or_insert_with(|| vec![start..end]);
15535                    }
15536                }
15537                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15538            }
15539        };
15540
15541        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15542        let selections_prev = transaction_id_prev
15543            .and_then(|transaction_id_prev| {
15544                // default to selections as they were after the last edit, if we have them,
15545                // instead of how they are now.
15546                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15547                // will take you back to where you made the last edit, instead of staying where you scrolled
15548                self.selection_history
15549                    .transaction(transaction_id_prev)
15550                    .map(|t| t.0.clone())
15551            })
15552            .unwrap_or_else(|| {
15553                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15554                self.selections.disjoint_anchors()
15555            });
15556
15557        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15558        let format = project.update(cx, |project, cx| {
15559            project.format(buffers, target, true, trigger, cx)
15560        });
15561
15562        cx.spawn_in(window, async move |editor, cx| {
15563            let transaction = futures::select_biased! {
15564                transaction = format.log_err().fuse() => transaction,
15565                () = timeout => {
15566                    log::warn!("timed out waiting for formatting");
15567                    None
15568                }
15569            };
15570
15571            buffer
15572                .update(cx, |buffer, cx| {
15573                    if let Some(transaction) = transaction {
15574                        if !buffer.is_singleton() {
15575                            buffer.push_transaction(&transaction.0, cx);
15576                        }
15577                    }
15578                    cx.notify();
15579                })
15580                .ok();
15581
15582            if let Some(transaction_id_now) =
15583                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15584            {
15585                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15586                if has_new_transaction {
15587                    _ = editor.update(cx, |editor, _| {
15588                        editor
15589                            .selection_history
15590                            .insert_transaction(transaction_id_now, selections_prev);
15591                    });
15592                }
15593            }
15594
15595            Ok(())
15596        })
15597    }
15598
15599    fn organize_imports(
15600        &mut self,
15601        _: &OrganizeImports,
15602        window: &mut Window,
15603        cx: &mut Context<Self>,
15604    ) -> Option<Task<Result<()>>> {
15605        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15606        let project = match &self.project {
15607            Some(project) => project.clone(),
15608            None => return None,
15609        };
15610        Some(self.perform_code_action_kind(
15611            project,
15612            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15613            window,
15614            cx,
15615        ))
15616    }
15617
15618    fn perform_code_action_kind(
15619        &mut self,
15620        project: Entity<Project>,
15621        kind: CodeActionKind,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) -> Task<Result<()>> {
15625        let buffer = self.buffer.clone();
15626        let buffers = buffer.read(cx).all_buffers();
15627        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15628        let apply_action = project.update(cx, |project, cx| {
15629            project.apply_code_action_kind(buffers, kind, true, cx)
15630        });
15631        cx.spawn_in(window, async move |_, cx| {
15632            let transaction = futures::select_biased! {
15633                () = timeout => {
15634                    log::warn!("timed out waiting for executing code action");
15635                    None
15636                }
15637                transaction = apply_action.log_err().fuse() => transaction,
15638            };
15639            buffer
15640                .update(cx, |buffer, cx| {
15641                    // check if we need this
15642                    if let Some(transaction) = transaction {
15643                        if !buffer.is_singleton() {
15644                            buffer.push_transaction(&transaction.0, cx);
15645                        }
15646                    }
15647                    cx.notify();
15648                })
15649                .ok();
15650            Ok(())
15651        })
15652    }
15653
15654    fn restart_language_server(
15655        &mut self,
15656        _: &RestartLanguageServer,
15657        _: &mut Window,
15658        cx: &mut Context<Self>,
15659    ) {
15660        if let Some(project) = self.project.clone() {
15661            self.buffer.update(cx, |multi_buffer, cx| {
15662                project.update(cx, |project, cx| {
15663                    project.restart_language_servers_for_buffers(
15664                        multi_buffer.all_buffers().into_iter().collect(),
15665                        cx,
15666                    );
15667                });
15668            })
15669        }
15670    }
15671
15672    fn stop_language_server(
15673        &mut self,
15674        _: &StopLanguageServer,
15675        _: &mut Window,
15676        cx: &mut Context<Self>,
15677    ) {
15678        if let Some(project) = self.project.clone() {
15679            self.buffer.update(cx, |multi_buffer, cx| {
15680                project.update(cx, |project, cx| {
15681                    project.stop_language_servers_for_buffers(
15682                        multi_buffer.all_buffers().into_iter().collect(),
15683                        cx,
15684                    );
15685                    cx.emit(project::Event::RefreshInlayHints);
15686                });
15687            });
15688        }
15689    }
15690
15691    fn cancel_language_server_work(
15692        workspace: &mut Workspace,
15693        _: &actions::CancelLanguageServerWork,
15694        _: &mut Window,
15695        cx: &mut Context<Workspace>,
15696    ) {
15697        let project = workspace.project();
15698        let buffers = workspace
15699            .active_item(cx)
15700            .and_then(|item| item.act_as::<Editor>(cx))
15701            .map_or(HashSet::default(), |editor| {
15702                editor.read(cx).buffer.read(cx).all_buffers()
15703            });
15704        project.update(cx, |project, cx| {
15705            project.cancel_language_server_work_for_buffers(buffers, cx);
15706        });
15707    }
15708
15709    fn show_character_palette(
15710        &mut self,
15711        _: &ShowCharacterPalette,
15712        window: &mut Window,
15713        _: &mut Context<Self>,
15714    ) {
15715        window.show_character_palette();
15716    }
15717
15718    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15719        if self.mode.is_minimap() {
15720            return;
15721        }
15722
15723        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15724            let buffer = self.buffer.read(cx).snapshot(cx);
15725            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15726            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15727            let is_valid = buffer
15728                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15729                .any(|entry| {
15730                    entry.diagnostic.is_primary
15731                        && !entry.range.is_empty()
15732                        && entry.range.start == primary_range_start
15733                        && entry.diagnostic.message == active_diagnostics.active_message
15734                });
15735
15736            if !is_valid {
15737                self.dismiss_diagnostics(cx);
15738            }
15739        }
15740    }
15741
15742    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15743        match &self.active_diagnostics {
15744            ActiveDiagnostic::Group(group) => Some(group),
15745            _ => None,
15746        }
15747    }
15748
15749    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15750        self.dismiss_diagnostics(cx);
15751        self.active_diagnostics = ActiveDiagnostic::All;
15752    }
15753
15754    fn activate_diagnostics(
15755        &mut self,
15756        buffer_id: BufferId,
15757        diagnostic: DiagnosticEntry<usize>,
15758        window: &mut Window,
15759        cx: &mut Context<Self>,
15760    ) {
15761        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15762            return;
15763        }
15764        self.dismiss_diagnostics(cx);
15765        let snapshot = self.snapshot(window, cx);
15766        let buffer = self.buffer.read(cx).snapshot(cx);
15767        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15768            return;
15769        };
15770
15771        let diagnostic_group = buffer
15772            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15773            .collect::<Vec<_>>();
15774
15775        let blocks =
15776            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15777
15778        let blocks = self.display_map.update(cx, |display_map, cx| {
15779            display_map.insert_blocks(blocks, cx).into_iter().collect()
15780        });
15781        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15782            active_range: buffer.anchor_before(diagnostic.range.start)
15783                ..buffer.anchor_after(diagnostic.range.end),
15784            active_message: diagnostic.diagnostic.message.clone(),
15785            group_id: diagnostic.diagnostic.group_id,
15786            blocks,
15787        });
15788        cx.notify();
15789    }
15790
15791    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15792        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15793            return;
15794        };
15795
15796        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15797        if let ActiveDiagnostic::Group(group) = prev {
15798            self.display_map.update(cx, |display_map, cx| {
15799                display_map.remove_blocks(group.blocks, cx);
15800            });
15801            cx.notify();
15802        }
15803    }
15804
15805    /// Disable inline diagnostics rendering for this editor.
15806    pub fn disable_inline_diagnostics(&mut self) {
15807        self.inline_diagnostics_enabled = false;
15808        self.inline_diagnostics_update = Task::ready(());
15809        self.inline_diagnostics.clear();
15810    }
15811
15812    pub fn diagnostics_enabled(&self) -> bool {
15813        self.mode.is_full()
15814    }
15815
15816    pub fn inline_diagnostics_enabled(&self) -> bool {
15817        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15818    }
15819
15820    pub fn show_inline_diagnostics(&self) -> bool {
15821        self.show_inline_diagnostics
15822    }
15823
15824    pub fn toggle_inline_diagnostics(
15825        &mut self,
15826        _: &ToggleInlineDiagnostics,
15827        window: &mut Window,
15828        cx: &mut Context<Editor>,
15829    ) {
15830        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15831        self.refresh_inline_diagnostics(false, window, cx);
15832    }
15833
15834    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15835        self.diagnostics_max_severity = severity;
15836        self.display_map.update(cx, |display_map, _| {
15837            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15838        });
15839    }
15840
15841    pub fn toggle_diagnostics(
15842        &mut self,
15843        _: &ToggleDiagnostics,
15844        window: &mut Window,
15845        cx: &mut Context<Editor>,
15846    ) {
15847        if !self.diagnostics_enabled() {
15848            return;
15849        }
15850
15851        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15852            EditorSettings::get_global(cx)
15853                .diagnostics_max_severity
15854                .filter(|severity| severity != &DiagnosticSeverity::Off)
15855                .unwrap_or(DiagnosticSeverity::Hint)
15856        } else {
15857            DiagnosticSeverity::Off
15858        };
15859        self.set_max_diagnostics_severity(new_severity, cx);
15860        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15861            self.active_diagnostics = ActiveDiagnostic::None;
15862            self.inline_diagnostics_update = Task::ready(());
15863            self.inline_diagnostics.clear();
15864        } else {
15865            self.refresh_inline_diagnostics(false, window, cx);
15866        }
15867
15868        cx.notify();
15869    }
15870
15871    pub fn toggle_minimap(
15872        &mut self,
15873        _: &ToggleMinimap,
15874        window: &mut Window,
15875        cx: &mut Context<Editor>,
15876    ) {
15877        if self.supports_minimap(cx) {
15878            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15879        }
15880    }
15881
15882    fn refresh_inline_diagnostics(
15883        &mut self,
15884        debounce: bool,
15885        window: &mut Window,
15886        cx: &mut Context<Self>,
15887    ) {
15888        let max_severity = ProjectSettings::get_global(cx)
15889            .diagnostics
15890            .inline
15891            .max_severity
15892            .unwrap_or(self.diagnostics_max_severity);
15893
15894        if !self.inline_diagnostics_enabled()
15895            || !self.show_inline_diagnostics
15896            || max_severity == DiagnosticSeverity::Off
15897        {
15898            self.inline_diagnostics_update = Task::ready(());
15899            self.inline_diagnostics.clear();
15900            return;
15901        }
15902
15903        let debounce_ms = ProjectSettings::get_global(cx)
15904            .diagnostics
15905            .inline
15906            .update_debounce_ms;
15907        let debounce = if debounce && debounce_ms > 0 {
15908            Some(Duration::from_millis(debounce_ms))
15909        } else {
15910            None
15911        };
15912        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15913            if let Some(debounce) = debounce {
15914                cx.background_executor().timer(debounce).await;
15915            }
15916            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15917                editor
15918                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15919                    .ok()
15920            }) else {
15921                return;
15922            };
15923
15924            let new_inline_diagnostics = cx
15925                .background_spawn(async move {
15926                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15927                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15928                        let message = diagnostic_entry
15929                            .diagnostic
15930                            .message
15931                            .split_once('\n')
15932                            .map(|(line, _)| line)
15933                            .map(SharedString::new)
15934                            .unwrap_or_else(|| {
15935                                SharedString::from(diagnostic_entry.diagnostic.message)
15936                            });
15937                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15938                        let (Ok(i) | Err(i)) = inline_diagnostics
15939                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15940                        inline_diagnostics.insert(
15941                            i,
15942                            (
15943                                start_anchor,
15944                                InlineDiagnostic {
15945                                    message,
15946                                    group_id: diagnostic_entry.diagnostic.group_id,
15947                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15948                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15949                                    severity: diagnostic_entry.diagnostic.severity,
15950                                },
15951                            ),
15952                        );
15953                    }
15954                    inline_diagnostics
15955                })
15956                .await;
15957
15958            editor
15959                .update(cx, |editor, cx| {
15960                    editor.inline_diagnostics = new_inline_diagnostics;
15961                    cx.notify();
15962                })
15963                .ok();
15964        });
15965    }
15966
15967    fn pull_diagnostics(&mut self, window: &Window, cx: &mut Context<Self>) -> Option<()> {
15968        let project = self.project.as_ref()?.downgrade();
15969        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
15970            .diagnostics
15971            .lsp_pull_diagnostics;
15972        if !pull_diagnostics_settings.enabled {
15973            return None;
15974        }
15975        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
15976        let buffers = self.buffer.read(cx).all_buffers();
15977
15978        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
15979            cx.background_executor().timer(debounce).await;
15980
15981            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
15982                buffers
15983                    .into_iter()
15984                    .flat_map(|buffer| {
15985                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
15986                    })
15987                    .collect::<FuturesUnordered<_>>()
15988            }) else {
15989                return;
15990            };
15991
15992            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
15993                match pull_task {
15994                    Ok(()) => {
15995                        if editor
15996                            .update_in(cx, |editor, window, cx| {
15997                                editor.update_diagnostics_state(window, cx);
15998                            })
15999                            .is_err()
16000                        {
16001                            return;
16002                        }
16003                    }
16004                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16005                }
16006            }
16007        });
16008
16009        Some(())
16010    }
16011
16012    pub fn set_selections_from_remote(
16013        &mut self,
16014        selections: Vec<Selection<Anchor>>,
16015        pending_selection: Option<Selection<Anchor>>,
16016        window: &mut Window,
16017        cx: &mut Context<Self>,
16018    ) {
16019        let old_cursor_position = self.selections.newest_anchor().head();
16020        self.selections.change_with(cx, |s| {
16021            s.select_anchors(selections);
16022            if let Some(pending_selection) = pending_selection {
16023                s.set_pending(pending_selection, SelectMode::Character);
16024            } else {
16025                s.clear_pending();
16026            }
16027        });
16028        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16029    }
16030
16031    pub fn transact(
16032        &mut self,
16033        window: &mut Window,
16034        cx: &mut Context<Self>,
16035        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16036    ) -> Option<TransactionId> {
16037        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16038            this.start_transaction_at(Instant::now(), window, cx);
16039            update(this, window, cx);
16040            this.end_transaction_at(Instant::now(), cx)
16041        })
16042    }
16043
16044    pub fn start_transaction_at(
16045        &mut self,
16046        now: Instant,
16047        window: &mut Window,
16048        cx: &mut Context<Self>,
16049    ) {
16050        self.end_selection(window, cx);
16051        if let Some(tx_id) = self
16052            .buffer
16053            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16054        {
16055            self.selection_history
16056                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16057            cx.emit(EditorEvent::TransactionBegun {
16058                transaction_id: tx_id,
16059            })
16060        }
16061    }
16062
16063    pub fn end_transaction_at(
16064        &mut self,
16065        now: Instant,
16066        cx: &mut Context<Self>,
16067    ) -> Option<TransactionId> {
16068        if let Some(transaction_id) = self
16069            .buffer
16070            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16071        {
16072            if let Some((_, end_selections)) =
16073                self.selection_history.transaction_mut(transaction_id)
16074            {
16075                *end_selections = Some(self.selections.disjoint_anchors());
16076            } else {
16077                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16078            }
16079
16080            cx.emit(EditorEvent::Edited { transaction_id });
16081            Some(transaction_id)
16082        } else {
16083            None
16084        }
16085    }
16086
16087    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16088        if self.selection_mark_mode {
16089            self.change_selections(None, window, cx, |s| {
16090                s.move_with(|_, sel| {
16091                    sel.collapse_to(sel.head(), SelectionGoal::None);
16092                });
16093            })
16094        }
16095        self.selection_mark_mode = true;
16096        cx.notify();
16097    }
16098
16099    pub fn swap_selection_ends(
16100        &mut self,
16101        _: &actions::SwapSelectionEnds,
16102        window: &mut Window,
16103        cx: &mut Context<Self>,
16104    ) {
16105        self.change_selections(None, window, cx, |s| {
16106            s.move_with(|_, sel| {
16107                if sel.start != sel.end {
16108                    sel.reversed = !sel.reversed
16109                }
16110            });
16111        });
16112        self.request_autoscroll(Autoscroll::newest(), cx);
16113        cx.notify();
16114    }
16115
16116    pub fn toggle_fold(
16117        &mut self,
16118        _: &actions::ToggleFold,
16119        window: &mut Window,
16120        cx: &mut Context<Self>,
16121    ) {
16122        if self.is_singleton(cx) {
16123            let selection = self.selections.newest::<Point>(cx);
16124
16125            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16126            let range = if selection.is_empty() {
16127                let point = selection.head().to_display_point(&display_map);
16128                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16129                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16130                    .to_point(&display_map);
16131                start..end
16132            } else {
16133                selection.range()
16134            };
16135            if display_map.folds_in_range(range).next().is_some() {
16136                self.unfold_lines(&Default::default(), window, cx)
16137            } else {
16138                self.fold(&Default::default(), window, cx)
16139            }
16140        } else {
16141            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16142            let buffer_ids: HashSet<_> = self
16143                .selections
16144                .disjoint_anchor_ranges()
16145                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16146                .collect();
16147
16148            let should_unfold = buffer_ids
16149                .iter()
16150                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16151
16152            for buffer_id in buffer_ids {
16153                if should_unfold {
16154                    self.unfold_buffer(buffer_id, cx);
16155                } else {
16156                    self.fold_buffer(buffer_id, cx);
16157                }
16158            }
16159        }
16160    }
16161
16162    pub fn toggle_fold_recursive(
16163        &mut self,
16164        _: &actions::ToggleFoldRecursive,
16165        window: &mut Window,
16166        cx: &mut Context<Self>,
16167    ) {
16168        let selection = self.selections.newest::<Point>(cx);
16169
16170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16171        let range = if selection.is_empty() {
16172            let point = selection.head().to_display_point(&display_map);
16173            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16174            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16175                .to_point(&display_map);
16176            start..end
16177        } else {
16178            selection.range()
16179        };
16180        if display_map.folds_in_range(range).next().is_some() {
16181            self.unfold_recursive(&Default::default(), window, cx)
16182        } else {
16183            self.fold_recursive(&Default::default(), window, cx)
16184        }
16185    }
16186
16187    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16188        if self.is_singleton(cx) {
16189            let mut to_fold = Vec::new();
16190            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16191            let selections = self.selections.all_adjusted(cx);
16192
16193            for selection in selections {
16194                let range = selection.range().sorted();
16195                let buffer_start_row = range.start.row;
16196
16197                if range.start.row != range.end.row {
16198                    let mut found = false;
16199                    let mut row = range.start.row;
16200                    while row <= range.end.row {
16201                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16202                        {
16203                            found = true;
16204                            row = crease.range().end.row + 1;
16205                            to_fold.push(crease);
16206                        } else {
16207                            row += 1
16208                        }
16209                    }
16210                    if found {
16211                        continue;
16212                    }
16213                }
16214
16215                for row in (0..=range.start.row).rev() {
16216                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16217                        if crease.range().end.row >= buffer_start_row {
16218                            to_fold.push(crease);
16219                            if row <= range.start.row {
16220                                break;
16221                            }
16222                        }
16223                    }
16224                }
16225            }
16226
16227            self.fold_creases(to_fold, true, window, cx);
16228        } else {
16229            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16230            let buffer_ids = self
16231                .selections
16232                .disjoint_anchor_ranges()
16233                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16234                .collect::<HashSet<_>>();
16235            for buffer_id in buffer_ids {
16236                self.fold_buffer(buffer_id, cx);
16237            }
16238        }
16239    }
16240
16241    fn fold_at_level(
16242        &mut self,
16243        fold_at: &FoldAtLevel,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        if !self.buffer.read(cx).is_singleton() {
16248            return;
16249        }
16250
16251        let fold_at_level = fold_at.0;
16252        let snapshot = self.buffer.read(cx).snapshot(cx);
16253        let mut to_fold = Vec::new();
16254        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16255
16256        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16257            while start_row < end_row {
16258                match self
16259                    .snapshot(window, cx)
16260                    .crease_for_buffer_row(MultiBufferRow(start_row))
16261                {
16262                    Some(crease) => {
16263                        let nested_start_row = crease.range().start.row + 1;
16264                        let nested_end_row = crease.range().end.row;
16265
16266                        if current_level < fold_at_level {
16267                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16268                        } else if current_level == fold_at_level {
16269                            to_fold.push(crease);
16270                        }
16271
16272                        start_row = nested_end_row + 1;
16273                    }
16274                    None => start_row += 1,
16275                }
16276            }
16277        }
16278
16279        self.fold_creases(to_fold, true, window, cx);
16280    }
16281
16282    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16283        if self.buffer.read(cx).is_singleton() {
16284            let mut fold_ranges = Vec::new();
16285            let snapshot = self.buffer.read(cx).snapshot(cx);
16286
16287            for row in 0..snapshot.max_row().0 {
16288                if let Some(foldable_range) = self
16289                    .snapshot(window, cx)
16290                    .crease_for_buffer_row(MultiBufferRow(row))
16291                {
16292                    fold_ranges.push(foldable_range);
16293                }
16294            }
16295
16296            self.fold_creases(fold_ranges, true, window, cx);
16297        } else {
16298            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16299                editor
16300                    .update_in(cx, |editor, _, cx| {
16301                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16302                            editor.fold_buffer(buffer_id, cx);
16303                        }
16304                    })
16305                    .ok();
16306            });
16307        }
16308    }
16309
16310    pub fn fold_function_bodies(
16311        &mut self,
16312        _: &actions::FoldFunctionBodies,
16313        window: &mut Window,
16314        cx: &mut Context<Self>,
16315    ) {
16316        let snapshot = self.buffer.read(cx).snapshot(cx);
16317
16318        let ranges = snapshot
16319            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16320            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16321            .collect::<Vec<_>>();
16322
16323        let creases = ranges
16324            .into_iter()
16325            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16326            .collect();
16327
16328        self.fold_creases(creases, true, window, cx);
16329    }
16330
16331    pub fn fold_recursive(
16332        &mut self,
16333        _: &actions::FoldRecursive,
16334        window: &mut Window,
16335        cx: &mut Context<Self>,
16336    ) {
16337        let mut to_fold = Vec::new();
16338        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16339        let selections = self.selections.all_adjusted(cx);
16340
16341        for selection in selections {
16342            let range = selection.range().sorted();
16343            let buffer_start_row = range.start.row;
16344
16345            if range.start.row != range.end.row {
16346                let mut found = false;
16347                for row in range.start.row..=range.end.row {
16348                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16349                        found = true;
16350                        to_fold.push(crease);
16351                    }
16352                }
16353                if found {
16354                    continue;
16355                }
16356            }
16357
16358            for row in (0..=range.start.row).rev() {
16359                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16360                    if crease.range().end.row >= buffer_start_row {
16361                        to_fold.push(crease);
16362                    } else {
16363                        break;
16364                    }
16365                }
16366            }
16367        }
16368
16369        self.fold_creases(to_fold, true, window, cx);
16370    }
16371
16372    pub fn fold_at(
16373        &mut self,
16374        buffer_row: MultiBufferRow,
16375        window: &mut Window,
16376        cx: &mut Context<Self>,
16377    ) {
16378        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16379
16380        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16381            let autoscroll = self
16382                .selections
16383                .all::<Point>(cx)
16384                .iter()
16385                .any(|selection| crease.range().overlaps(&selection.range()));
16386
16387            self.fold_creases(vec![crease], autoscroll, window, cx);
16388        }
16389    }
16390
16391    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16392        if self.is_singleton(cx) {
16393            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16394            let buffer = &display_map.buffer_snapshot;
16395            let selections = self.selections.all::<Point>(cx);
16396            let ranges = selections
16397                .iter()
16398                .map(|s| {
16399                    let range = s.display_range(&display_map).sorted();
16400                    let mut start = range.start.to_point(&display_map);
16401                    let mut end = range.end.to_point(&display_map);
16402                    start.column = 0;
16403                    end.column = buffer.line_len(MultiBufferRow(end.row));
16404                    start..end
16405                })
16406                .collect::<Vec<_>>();
16407
16408            self.unfold_ranges(&ranges, true, true, cx);
16409        } else {
16410            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16411            let buffer_ids = self
16412                .selections
16413                .disjoint_anchor_ranges()
16414                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16415                .collect::<HashSet<_>>();
16416            for buffer_id in buffer_ids {
16417                self.unfold_buffer(buffer_id, cx);
16418            }
16419        }
16420    }
16421
16422    pub fn unfold_recursive(
16423        &mut self,
16424        _: &UnfoldRecursive,
16425        _window: &mut Window,
16426        cx: &mut Context<Self>,
16427    ) {
16428        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16429        let selections = self.selections.all::<Point>(cx);
16430        let ranges = selections
16431            .iter()
16432            .map(|s| {
16433                let mut range = s.display_range(&display_map).sorted();
16434                *range.start.column_mut() = 0;
16435                *range.end.column_mut() = display_map.line_len(range.end.row());
16436                let start = range.start.to_point(&display_map);
16437                let end = range.end.to_point(&display_map);
16438                start..end
16439            })
16440            .collect::<Vec<_>>();
16441
16442        self.unfold_ranges(&ranges, true, true, cx);
16443    }
16444
16445    pub fn unfold_at(
16446        &mut self,
16447        buffer_row: MultiBufferRow,
16448        _window: &mut Window,
16449        cx: &mut Context<Self>,
16450    ) {
16451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16452
16453        let intersection_range = Point::new(buffer_row.0, 0)
16454            ..Point::new(
16455                buffer_row.0,
16456                display_map.buffer_snapshot.line_len(buffer_row),
16457            );
16458
16459        let autoscroll = self
16460            .selections
16461            .all::<Point>(cx)
16462            .iter()
16463            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16464
16465        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16466    }
16467
16468    pub fn unfold_all(
16469        &mut self,
16470        _: &actions::UnfoldAll,
16471        _window: &mut Window,
16472        cx: &mut Context<Self>,
16473    ) {
16474        if self.buffer.read(cx).is_singleton() {
16475            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16476            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16477        } else {
16478            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16479                editor
16480                    .update(cx, |editor, cx| {
16481                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16482                            editor.unfold_buffer(buffer_id, cx);
16483                        }
16484                    })
16485                    .ok();
16486            });
16487        }
16488    }
16489
16490    pub fn fold_selected_ranges(
16491        &mut self,
16492        _: &FoldSelectedRanges,
16493        window: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) {
16496        let selections = self.selections.all_adjusted(cx);
16497        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16498        let ranges = selections
16499            .into_iter()
16500            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16501            .collect::<Vec<_>>();
16502        self.fold_creases(ranges, true, window, cx);
16503    }
16504
16505    pub fn fold_ranges<T: ToOffset + Clone>(
16506        &mut self,
16507        ranges: Vec<Range<T>>,
16508        auto_scroll: bool,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) {
16512        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16513        let ranges = ranges
16514            .into_iter()
16515            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16516            .collect::<Vec<_>>();
16517        self.fold_creases(ranges, auto_scroll, window, cx);
16518    }
16519
16520    pub fn fold_creases<T: ToOffset + Clone>(
16521        &mut self,
16522        creases: Vec<Crease<T>>,
16523        auto_scroll: bool,
16524        _window: &mut Window,
16525        cx: &mut Context<Self>,
16526    ) {
16527        if creases.is_empty() {
16528            return;
16529        }
16530
16531        let mut buffers_affected = HashSet::default();
16532        let multi_buffer = self.buffer().read(cx);
16533        for crease in &creases {
16534            if let Some((_, buffer, _)) =
16535                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16536            {
16537                buffers_affected.insert(buffer.read(cx).remote_id());
16538            };
16539        }
16540
16541        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16542
16543        if auto_scroll {
16544            self.request_autoscroll(Autoscroll::fit(), cx);
16545        }
16546
16547        cx.notify();
16548
16549        self.scrollbar_marker_state.dirty = true;
16550        self.folds_did_change(cx);
16551    }
16552
16553    /// Removes any folds whose ranges intersect any of the given ranges.
16554    pub fn unfold_ranges<T: ToOffset + Clone>(
16555        &mut self,
16556        ranges: &[Range<T>],
16557        inclusive: bool,
16558        auto_scroll: bool,
16559        cx: &mut Context<Self>,
16560    ) {
16561        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16562            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16563        });
16564        self.folds_did_change(cx);
16565    }
16566
16567    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16568        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16569            return;
16570        }
16571        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16572        self.display_map.update(cx, |display_map, cx| {
16573            display_map.fold_buffers([buffer_id], cx)
16574        });
16575        cx.emit(EditorEvent::BufferFoldToggled {
16576            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16577            folded: true,
16578        });
16579        cx.notify();
16580    }
16581
16582    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16583        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16584            return;
16585        }
16586        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16587        self.display_map.update(cx, |display_map, cx| {
16588            display_map.unfold_buffers([buffer_id], cx);
16589        });
16590        cx.emit(EditorEvent::BufferFoldToggled {
16591            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16592            folded: false,
16593        });
16594        cx.notify();
16595    }
16596
16597    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16598        self.display_map.read(cx).is_buffer_folded(buffer)
16599    }
16600
16601    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16602        self.display_map.read(cx).folded_buffers()
16603    }
16604
16605    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16606        self.display_map.update(cx, |display_map, cx| {
16607            display_map.disable_header_for_buffer(buffer_id, cx);
16608        });
16609        cx.notify();
16610    }
16611
16612    /// Removes any folds with the given ranges.
16613    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16614        &mut self,
16615        ranges: &[Range<T>],
16616        type_id: TypeId,
16617        auto_scroll: bool,
16618        cx: &mut Context<Self>,
16619    ) {
16620        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16621            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16622        });
16623        self.folds_did_change(cx);
16624    }
16625
16626    fn remove_folds_with<T: ToOffset + Clone>(
16627        &mut self,
16628        ranges: &[Range<T>],
16629        auto_scroll: bool,
16630        cx: &mut Context<Self>,
16631        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16632    ) {
16633        if ranges.is_empty() {
16634            return;
16635        }
16636
16637        let mut buffers_affected = HashSet::default();
16638        let multi_buffer = self.buffer().read(cx);
16639        for range in ranges {
16640            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16641                buffers_affected.insert(buffer.read(cx).remote_id());
16642            };
16643        }
16644
16645        self.display_map.update(cx, update);
16646
16647        if auto_scroll {
16648            self.request_autoscroll(Autoscroll::fit(), cx);
16649        }
16650
16651        cx.notify();
16652        self.scrollbar_marker_state.dirty = true;
16653        self.active_indent_guides_state.dirty = true;
16654    }
16655
16656    pub fn update_fold_widths(
16657        &mut self,
16658        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16659        cx: &mut Context<Self>,
16660    ) -> bool {
16661        self.display_map
16662            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16663    }
16664
16665    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16666        self.display_map.read(cx).fold_placeholder.clone()
16667    }
16668
16669    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16670        self.buffer.update(cx, |buffer, cx| {
16671            buffer.set_all_diff_hunks_expanded(cx);
16672        });
16673    }
16674
16675    pub fn expand_all_diff_hunks(
16676        &mut self,
16677        _: &ExpandAllDiffHunks,
16678        _window: &mut Window,
16679        cx: &mut Context<Self>,
16680    ) {
16681        self.buffer.update(cx, |buffer, cx| {
16682            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16683        });
16684    }
16685
16686    pub fn toggle_selected_diff_hunks(
16687        &mut self,
16688        _: &ToggleSelectedDiffHunks,
16689        _window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) {
16692        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16693        self.toggle_diff_hunks_in_ranges(ranges, cx);
16694    }
16695
16696    pub fn diff_hunks_in_ranges<'a>(
16697        &'a self,
16698        ranges: &'a [Range<Anchor>],
16699        buffer: &'a MultiBufferSnapshot,
16700    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16701        ranges.iter().flat_map(move |range| {
16702            let end_excerpt_id = range.end.excerpt_id;
16703            let range = range.to_point(buffer);
16704            let mut peek_end = range.end;
16705            if range.end.row < buffer.max_row().0 {
16706                peek_end = Point::new(range.end.row + 1, 0);
16707            }
16708            buffer
16709                .diff_hunks_in_range(range.start..peek_end)
16710                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16711        })
16712    }
16713
16714    pub fn has_stageable_diff_hunks_in_ranges(
16715        &self,
16716        ranges: &[Range<Anchor>],
16717        snapshot: &MultiBufferSnapshot,
16718    ) -> bool {
16719        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16720        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16721    }
16722
16723    pub fn toggle_staged_selected_diff_hunks(
16724        &mut self,
16725        _: &::git::ToggleStaged,
16726        _: &mut Window,
16727        cx: &mut Context<Self>,
16728    ) {
16729        let snapshot = self.buffer.read(cx).snapshot(cx);
16730        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16731        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16732        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16733    }
16734
16735    pub fn set_render_diff_hunk_controls(
16736        &mut self,
16737        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16738        cx: &mut Context<Self>,
16739    ) {
16740        self.render_diff_hunk_controls = render_diff_hunk_controls;
16741        cx.notify();
16742    }
16743
16744    pub fn stage_and_next(
16745        &mut self,
16746        _: &::git::StageAndNext,
16747        window: &mut Window,
16748        cx: &mut Context<Self>,
16749    ) {
16750        self.do_stage_or_unstage_and_next(true, window, cx);
16751    }
16752
16753    pub fn unstage_and_next(
16754        &mut self,
16755        _: &::git::UnstageAndNext,
16756        window: &mut Window,
16757        cx: &mut Context<Self>,
16758    ) {
16759        self.do_stage_or_unstage_and_next(false, window, cx);
16760    }
16761
16762    pub fn stage_or_unstage_diff_hunks(
16763        &mut self,
16764        stage: bool,
16765        ranges: Vec<Range<Anchor>>,
16766        cx: &mut Context<Self>,
16767    ) {
16768        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16769        cx.spawn(async move |this, cx| {
16770            task.await?;
16771            this.update(cx, |this, cx| {
16772                let snapshot = this.buffer.read(cx).snapshot(cx);
16773                let chunk_by = this
16774                    .diff_hunks_in_ranges(&ranges, &snapshot)
16775                    .chunk_by(|hunk| hunk.buffer_id);
16776                for (buffer_id, hunks) in &chunk_by {
16777                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16778                }
16779            })
16780        })
16781        .detach_and_log_err(cx);
16782    }
16783
16784    fn save_buffers_for_ranges_if_needed(
16785        &mut self,
16786        ranges: &[Range<Anchor>],
16787        cx: &mut Context<Editor>,
16788    ) -> Task<Result<()>> {
16789        let multibuffer = self.buffer.read(cx);
16790        let snapshot = multibuffer.read(cx);
16791        let buffer_ids: HashSet<_> = ranges
16792            .iter()
16793            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16794            .collect();
16795        drop(snapshot);
16796
16797        let mut buffers = HashSet::default();
16798        for buffer_id in buffer_ids {
16799            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16800                let buffer = buffer_entity.read(cx);
16801                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16802                {
16803                    buffers.insert(buffer_entity);
16804                }
16805            }
16806        }
16807
16808        if let Some(project) = &self.project {
16809            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16810        } else {
16811            Task::ready(Ok(()))
16812        }
16813    }
16814
16815    fn do_stage_or_unstage_and_next(
16816        &mut self,
16817        stage: bool,
16818        window: &mut Window,
16819        cx: &mut Context<Self>,
16820    ) {
16821        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16822
16823        if ranges.iter().any(|range| range.start != range.end) {
16824            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16825            return;
16826        }
16827
16828        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16829        let snapshot = self.snapshot(window, cx);
16830        let position = self.selections.newest::<Point>(cx).head();
16831        let mut row = snapshot
16832            .buffer_snapshot
16833            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16834            .find(|hunk| hunk.row_range.start.0 > position.row)
16835            .map(|hunk| hunk.row_range.start);
16836
16837        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16838        // Outside of the project diff editor, wrap around to the beginning.
16839        if !all_diff_hunks_expanded {
16840            row = row.or_else(|| {
16841                snapshot
16842                    .buffer_snapshot
16843                    .diff_hunks_in_range(Point::zero()..position)
16844                    .find(|hunk| hunk.row_range.end.0 < position.row)
16845                    .map(|hunk| hunk.row_range.start)
16846            });
16847        }
16848
16849        if let Some(row) = row {
16850            let destination = Point::new(row.0, 0);
16851            let autoscroll = Autoscroll::center();
16852
16853            self.unfold_ranges(&[destination..destination], false, false, cx);
16854            self.change_selections(Some(autoscroll), window, cx, |s| {
16855                s.select_ranges([destination..destination]);
16856            });
16857        }
16858    }
16859
16860    fn do_stage_or_unstage(
16861        &self,
16862        stage: bool,
16863        buffer_id: BufferId,
16864        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16865        cx: &mut App,
16866    ) -> Option<()> {
16867        let project = self.project.as_ref()?;
16868        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16869        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16870        let buffer_snapshot = buffer.read(cx).snapshot();
16871        let file_exists = buffer_snapshot
16872            .file()
16873            .is_some_and(|file| file.disk_state().exists());
16874        diff.update(cx, |diff, cx| {
16875            diff.stage_or_unstage_hunks(
16876                stage,
16877                &hunks
16878                    .map(|hunk| buffer_diff::DiffHunk {
16879                        buffer_range: hunk.buffer_range,
16880                        diff_base_byte_range: hunk.diff_base_byte_range,
16881                        secondary_status: hunk.secondary_status,
16882                        range: Point::zero()..Point::zero(), // unused
16883                    })
16884                    .collect::<Vec<_>>(),
16885                &buffer_snapshot,
16886                file_exists,
16887                cx,
16888            )
16889        });
16890        None
16891    }
16892
16893    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16894        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16895        self.buffer
16896            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16897    }
16898
16899    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16900        self.buffer.update(cx, |buffer, cx| {
16901            let ranges = vec![Anchor::min()..Anchor::max()];
16902            if !buffer.all_diff_hunks_expanded()
16903                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16904            {
16905                buffer.collapse_diff_hunks(ranges, cx);
16906                true
16907            } else {
16908                false
16909            }
16910        })
16911    }
16912
16913    fn toggle_diff_hunks_in_ranges(
16914        &mut self,
16915        ranges: Vec<Range<Anchor>>,
16916        cx: &mut Context<Editor>,
16917    ) {
16918        self.buffer.update(cx, |buffer, cx| {
16919            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16920            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16921        })
16922    }
16923
16924    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16925        self.buffer.update(cx, |buffer, cx| {
16926            let snapshot = buffer.snapshot(cx);
16927            let excerpt_id = range.end.excerpt_id;
16928            let point_range = range.to_point(&snapshot);
16929            let expand = !buffer.single_hunk_is_expanded(range, cx);
16930            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16931        })
16932    }
16933
16934    pub(crate) fn apply_all_diff_hunks(
16935        &mut self,
16936        _: &ApplyAllDiffHunks,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939    ) {
16940        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16941
16942        let buffers = self.buffer.read(cx).all_buffers();
16943        for branch_buffer in buffers {
16944            branch_buffer.update(cx, |branch_buffer, cx| {
16945                branch_buffer.merge_into_base(Vec::new(), cx);
16946            });
16947        }
16948
16949        if let Some(project) = self.project.clone() {
16950            self.save(true, project, window, cx).detach_and_log_err(cx);
16951        }
16952    }
16953
16954    pub(crate) fn apply_selected_diff_hunks(
16955        &mut self,
16956        _: &ApplyDiffHunk,
16957        window: &mut Window,
16958        cx: &mut Context<Self>,
16959    ) {
16960        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16961        let snapshot = self.snapshot(window, cx);
16962        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16963        let mut ranges_by_buffer = HashMap::default();
16964        self.transact(window, cx, |editor, _window, cx| {
16965            for hunk in hunks {
16966                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16967                    ranges_by_buffer
16968                        .entry(buffer.clone())
16969                        .or_insert_with(Vec::new)
16970                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16971                }
16972            }
16973
16974            for (buffer, ranges) in ranges_by_buffer {
16975                buffer.update(cx, |buffer, cx| {
16976                    buffer.merge_into_base(ranges, cx);
16977                });
16978            }
16979        });
16980
16981        if let Some(project) = self.project.clone() {
16982            self.save(true, project, window, cx).detach_and_log_err(cx);
16983        }
16984    }
16985
16986    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16987        if hovered != self.gutter_hovered {
16988            self.gutter_hovered = hovered;
16989            cx.notify();
16990        }
16991    }
16992
16993    pub fn insert_blocks(
16994        &mut self,
16995        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16996        autoscroll: Option<Autoscroll>,
16997        cx: &mut Context<Self>,
16998    ) -> Vec<CustomBlockId> {
16999        let blocks = self
17000            .display_map
17001            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17002        if let Some(autoscroll) = autoscroll {
17003            self.request_autoscroll(autoscroll, cx);
17004        }
17005        cx.notify();
17006        blocks
17007    }
17008
17009    pub fn resize_blocks(
17010        &mut self,
17011        heights: HashMap<CustomBlockId, u32>,
17012        autoscroll: Option<Autoscroll>,
17013        cx: &mut Context<Self>,
17014    ) {
17015        self.display_map
17016            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17017        if let Some(autoscroll) = autoscroll {
17018            self.request_autoscroll(autoscroll, cx);
17019        }
17020        cx.notify();
17021    }
17022
17023    pub fn replace_blocks(
17024        &mut self,
17025        renderers: HashMap<CustomBlockId, RenderBlock>,
17026        autoscroll: Option<Autoscroll>,
17027        cx: &mut Context<Self>,
17028    ) {
17029        self.display_map
17030            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17031        if let Some(autoscroll) = autoscroll {
17032            self.request_autoscroll(autoscroll, cx);
17033        }
17034        cx.notify();
17035    }
17036
17037    pub fn remove_blocks(
17038        &mut self,
17039        block_ids: HashSet<CustomBlockId>,
17040        autoscroll: Option<Autoscroll>,
17041        cx: &mut Context<Self>,
17042    ) {
17043        self.display_map.update(cx, |display_map, cx| {
17044            display_map.remove_blocks(block_ids, cx)
17045        });
17046        if let Some(autoscroll) = autoscroll {
17047            self.request_autoscroll(autoscroll, cx);
17048        }
17049        cx.notify();
17050    }
17051
17052    pub fn row_for_block(
17053        &self,
17054        block_id: CustomBlockId,
17055        cx: &mut Context<Self>,
17056    ) -> Option<DisplayRow> {
17057        self.display_map
17058            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17059    }
17060
17061    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17062        self.focused_block = Some(focused_block);
17063    }
17064
17065    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17066        self.focused_block.take()
17067    }
17068
17069    pub fn insert_creases(
17070        &mut self,
17071        creases: impl IntoIterator<Item = Crease<Anchor>>,
17072        cx: &mut Context<Self>,
17073    ) -> Vec<CreaseId> {
17074        self.display_map
17075            .update(cx, |map, cx| map.insert_creases(creases, cx))
17076    }
17077
17078    pub fn remove_creases(
17079        &mut self,
17080        ids: impl IntoIterator<Item = CreaseId>,
17081        cx: &mut Context<Self>,
17082    ) -> Vec<(CreaseId, Range<Anchor>)> {
17083        self.display_map
17084            .update(cx, |map, cx| map.remove_creases(ids, cx))
17085    }
17086
17087    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17088        self.display_map
17089            .update(cx, |map, cx| map.snapshot(cx))
17090            .longest_row()
17091    }
17092
17093    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17094        self.display_map
17095            .update(cx, |map, cx| map.snapshot(cx))
17096            .max_point()
17097    }
17098
17099    pub fn text(&self, cx: &App) -> String {
17100        self.buffer.read(cx).read(cx).text()
17101    }
17102
17103    pub fn is_empty(&self, cx: &App) -> bool {
17104        self.buffer.read(cx).read(cx).is_empty()
17105    }
17106
17107    pub fn text_option(&self, cx: &App) -> Option<String> {
17108        let text = self.text(cx);
17109        let text = text.trim();
17110
17111        if text.is_empty() {
17112            return None;
17113        }
17114
17115        Some(text.to_string())
17116    }
17117
17118    pub fn set_text(
17119        &mut self,
17120        text: impl Into<Arc<str>>,
17121        window: &mut Window,
17122        cx: &mut Context<Self>,
17123    ) {
17124        self.transact(window, cx, |this, _, cx| {
17125            this.buffer
17126                .read(cx)
17127                .as_singleton()
17128                .expect("you can only call set_text on editors for singleton buffers")
17129                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17130        });
17131    }
17132
17133    pub fn display_text(&self, cx: &mut App) -> String {
17134        self.display_map
17135            .update(cx, |map, cx| map.snapshot(cx))
17136            .text()
17137    }
17138
17139    fn create_minimap(
17140        &self,
17141        minimap_settings: MinimapSettings,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) -> Option<Entity<Self>> {
17145        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17146            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17147    }
17148
17149    fn initialize_new_minimap(
17150        &self,
17151        minimap_settings: MinimapSettings,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) -> Entity<Self> {
17155        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17156
17157        let mut minimap = Editor::new_internal(
17158            EditorMode::Minimap {
17159                parent: cx.weak_entity(),
17160            },
17161            self.buffer.clone(),
17162            self.project.clone(),
17163            Some(self.display_map.clone()),
17164            window,
17165            cx,
17166        );
17167        minimap.scroll_manager.clone_state(&self.scroll_manager);
17168        minimap.set_text_style_refinement(TextStyleRefinement {
17169            font_size: Some(MINIMAP_FONT_SIZE),
17170            font_weight: Some(MINIMAP_FONT_WEIGHT),
17171            ..Default::default()
17172        });
17173        minimap.update_minimap_configuration(minimap_settings, cx);
17174        cx.new(|_| minimap)
17175    }
17176
17177    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17178        let current_line_highlight = minimap_settings
17179            .current_line_highlight
17180            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17181        self.set_current_line_highlight(Some(current_line_highlight));
17182    }
17183
17184    pub fn minimap(&self) -> Option<&Entity<Self>> {
17185        self.minimap
17186            .as_ref()
17187            .filter(|_| self.minimap_visibility.visible())
17188    }
17189
17190    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17191        let mut wrap_guides = smallvec![];
17192
17193        if self.show_wrap_guides == Some(false) {
17194            return wrap_guides;
17195        }
17196
17197        let settings = self.buffer.read(cx).language_settings(cx);
17198        if settings.show_wrap_guides {
17199            match self.soft_wrap_mode(cx) {
17200                SoftWrap::Column(soft_wrap) => {
17201                    wrap_guides.push((soft_wrap as usize, true));
17202                }
17203                SoftWrap::Bounded(soft_wrap) => {
17204                    wrap_guides.push((soft_wrap as usize, true));
17205                }
17206                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17207            }
17208            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17209        }
17210
17211        wrap_guides
17212    }
17213
17214    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17215        let settings = self.buffer.read(cx).language_settings(cx);
17216        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17217        match mode {
17218            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17219                SoftWrap::None
17220            }
17221            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17222            language_settings::SoftWrap::PreferredLineLength => {
17223                SoftWrap::Column(settings.preferred_line_length)
17224            }
17225            language_settings::SoftWrap::Bounded => {
17226                SoftWrap::Bounded(settings.preferred_line_length)
17227            }
17228        }
17229    }
17230
17231    pub fn set_soft_wrap_mode(
17232        &mut self,
17233        mode: language_settings::SoftWrap,
17234
17235        cx: &mut Context<Self>,
17236    ) {
17237        self.soft_wrap_mode_override = Some(mode);
17238        cx.notify();
17239    }
17240
17241    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17242        self.hard_wrap = hard_wrap;
17243        cx.notify();
17244    }
17245
17246    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17247        self.text_style_refinement = Some(style);
17248    }
17249
17250    /// called by the Element so we know what style we were most recently rendered with.
17251    pub(crate) fn set_style(
17252        &mut self,
17253        style: EditorStyle,
17254        window: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) {
17257        // We intentionally do not inform the display map about the minimap style
17258        // so that wrapping is not recalculated and stays consistent for the editor
17259        // and its linked minimap.
17260        if !self.mode.is_minimap() {
17261            let rem_size = window.rem_size();
17262            self.display_map.update(cx, |map, cx| {
17263                map.set_font(
17264                    style.text.font(),
17265                    style.text.font_size.to_pixels(rem_size),
17266                    cx,
17267                )
17268            });
17269        }
17270        self.style = Some(style);
17271    }
17272
17273    pub fn style(&self) -> Option<&EditorStyle> {
17274        self.style.as_ref()
17275    }
17276
17277    // Called by the element. This method is not designed to be called outside of the editor
17278    // element's layout code because it does not notify when rewrapping is computed synchronously.
17279    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17280        self.display_map
17281            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17282    }
17283
17284    pub fn set_soft_wrap(&mut self) {
17285        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17286    }
17287
17288    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17289        if self.soft_wrap_mode_override.is_some() {
17290            self.soft_wrap_mode_override.take();
17291        } else {
17292            let soft_wrap = match self.soft_wrap_mode(cx) {
17293                SoftWrap::GitDiff => return,
17294                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17295                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17296                    language_settings::SoftWrap::None
17297                }
17298            };
17299            self.soft_wrap_mode_override = Some(soft_wrap);
17300        }
17301        cx.notify();
17302    }
17303
17304    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17305        let Some(workspace) = self.workspace() else {
17306            return;
17307        };
17308        let fs = workspace.read(cx).app_state().fs.clone();
17309        let current_show = TabBarSettings::get_global(cx).show;
17310        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17311            setting.show = Some(!current_show);
17312        });
17313    }
17314
17315    pub fn toggle_indent_guides(
17316        &mut self,
17317        _: &ToggleIndentGuides,
17318        _: &mut Window,
17319        cx: &mut Context<Self>,
17320    ) {
17321        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17322            self.buffer
17323                .read(cx)
17324                .language_settings(cx)
17325                .indent_guides
17326                .enabled
17327        });
17328        self.show_indent_guides = Some(!currently_enabled);
17329        cx.notify();
17330    }
17331
17332    fn should_show_indent_guides(&self) -> Option<bool> {
17333        self.show_indent_guides
17334    }
17335
17336    pub fn toggle_line_numbers(
17337        &mut self,
17338        _: &ToggleLineNumbers,
17339        _: &mut Window,
17340        cx: &mut Context<Self>,
17341    ) {
17342        let mut editor_settings = EditorSettings::get_global(cx).clone();
17343        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17344        EditorSettings::override_global(editor_settings, cx);
17345    }
17346
17347    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17348        if let Some(show_line_numbers) = self.show_line_numbers {
17349            return show_line_numbers;
17350        }
17351        EditorSettings::get_global(cx).gutter.line_numbers
17352    }
17353
17354    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17355        self.use_relative_line_numbers
17356            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17357    }
17358
17359    pub fn toggle_relative_line_numbers(
17360        &mut self,
17361        _: &ToggleRelativeLineNumbers,
17362        _: &mut Window,
17363        cx: &mut Context<Self>,
17364    ) {
17365        let is_relative = self.should_use_relative_line_numbers(cx);
17366        self.set_relative_line_number(Some(!is_relative), cx)
17367    }
17368
17369    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17370        self.use_relative_line_numbers = is_relative;
17371        cx.notify();
17372    }
17373
17374    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17375        self.show_gutter = show_gutter;
17376        cx.notify();
17377    }
17378
17379    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17380        self.show_scrollbars = ScrollbarAxes {
17381            horizontal: show,
17382            vertical: show,
17383        };
17384        cx.notify();
17385    }
17386
17387    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17388        self.show_scrollbars.vertical = show;
17389        cx.notify();
17390    }
17391
17392    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17393        self.show_scrollbars.horizontal = show;
17394        cx.notify();
17395    }
17396
17397    pub fn set_minimap_visibility(
17398        &mut self,
17399        minimap_visibility: MinimapVisibility,
17400        window: &mut Window,
17401        cx: &mut Context<Self>,
17402    ) {
17403        if self.minimap_visibility != minimap_visibility {
17404            if minimap_visibility.visible() && self.minimap.is_none() {
17405                let minimap_settings = EditorSettings::get_global(cx).minimap;
17406                self.minimap =
17407                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17408            }
17409            self.minimap_visibility = minimap_visibility;
17410            cx.notify();
17411        }
17412    }
17413
17414    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17415        self.set_show_scrollbars(false, cx);
17416        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17417    }
17418
17419    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17420        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17421    }
17422
17423    /// Normally the text in full mode and auto height editors is padded on the
17424    /// left side by roughly half a character width for improved hit testing.
17425    ///
17426    /// Use this method to disable this for cases where this is not wanted (e.g.
17427    /// if you want to align the editor text with some other text above or below)
17428    /// or if you want to add this padding to single-line editors.
17429    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17430        self.offset_content = offset_content;
17431        cx.notify();
17432    }
17433
17434    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17435        self.show_line_numbers = Some(show_line_numbers);
17436        cx.notify();
17437    }
17438
17439    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17440        self.disable_expand_excerpt_buttons = true;
17441        cx.notify();
17442    }
17443
17444    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17445        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17446        cx.notify();
17447    }
17448
17449    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17450        self.show_code_actions = Some(show_code_actions);
17451        cx.notify();
17452    }
17453
17454    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17455        self.show_runnables = Some(show_runnables);
17456        cx.notify();
17457    }
17458
17459    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17460        self.show_breakpoints = Some(show_breakpoints);
17461        cx.notify();
17462    }
17463
17464    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17465        if self.display_map.read(cx).masked != masked {
17466            self.display_map.update(cx, |map, _| map.masked = masked);
17467        }
17468        cx.notify()
17469    }
17470
17471    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17472        self.show_wrap_guides = Some(show_wrap_guides);
17473        cx.notify();
17474    }
17475
17476    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17477        self.show_indent_guides = Some(show_indent_guides);
17478        cx.notify();
17479    }
17480
17481    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17482        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17483            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17484                if let Some(dir) = file.abs_path(cx).parent() {
17485                    return Some(dir.to_owned());
17486                }
17487            }
17488
17489            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17490                return Some(project_path.path.to_path_buf());
17491            }
17492        }
17493
17494        None
17495    }
17496
17497    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17498        self.active_excerpt(cx)?
17499            .1
17500            .read(cx)
17501            .file()
17502            .and_then(|f| f.as_local())
17503    }
17504
17505    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17506        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17507            let buffer = buffer.read(cx);
17508            if let Some(project_path) = buffer.project_path(cx) {
17509                let project = self.project.as_ref()?.read(cx);
17510                project.absolute_path(&project_path, cx)
17511            } else {
17512                buffer
17513                    .file()
17514                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17515            }
17516        })
17517    }
17518
17519    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17520        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17521            let project_path = buffer.read(cx).project_path(cx)?;
17522            let project = self.project.as_ref()?.read(cx);
17523            let entry = project.entry_for_path(&project_path, cx)?;
17524            let path = entry.path.to_path_buf();
17525            Some(path)
17526        })
17527    }
17528
17529    pub fn reveal_in_finder(
17530        &mut self,
17531        _: &RevealInFileManager,
17532        _window: &mut Window,
17533        cx: &mut Context<Self>,
17534    ) {
17535        if let Some(target) = self.target_file(cx) {
17536            cx.reveal_path(&target.abs_path(cx));
17537        }
17538    }
17539
17540    pub fn copy_path(
17541        &mut self,
17542        _: &zed_actions::workspace::CopyPath,
17543        _window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        if let Some(path) = self.target_file_abs_path(cx) {
17547            if let Some(path) = path.to_str() {
17548                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17549            }
17550        }
17551    }
17552
17553    pub fn copy_relative_path(
17554        &mut self,
17555        _: &zed_actions::workspace::CopyRelativePath,
17556        _window: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) {
17559        if let Some(path) = self.target_file_path(cx) {
17560            if let Some(path) = path.to_str() {
17561                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17562            }
17563        }
17564    }
17565
17566    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17567        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17568            buffer.read(cx).project_path(cx)
17569        } else {
17570            None
17571        }
17572    }
17573
17574    // Returns true if the editor handled a go-to-line request
17575    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17576        maybe!({
17577            let breakpoint_store = self.breakpoint_store.as_ref()?;
17578
17579            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17580            else {
17581                self.clear_row_highlights::<ActiveDebugLine>();
17582                return None;
17583            };
17584
17585            let position = active_stack_frame.position;
17586            let buffer_id = position.buffer_id?;
17587            let snapshot = self
17588                .project
17589                .as_ref()?
17590                .read(cx)
17591                .buffer_for_id(buffer_id, cx)?
17592                .read(cx)
17593                .snapshot();
17594
17595            let mut handled = false;
17596            for (id, ExcerptRange { context, .. }) in
17597                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17598            {
17599                if context.start.cmp(&position, &snapshot).is_ge()
17600                    || context.end.cmp(&position, &snapshot).is_lt()
17601                {
17602                    continue;
17603                }
17604                let snapshot = self.buffer.read(cx).snapshot(cx);
17605                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17606
17607                handled = true;
17608                self.clear_row_highlights::<ActiveDebugLine>();
17609
17610                self.go_to_line::<ActiveDebugLine>(
17611                    multibuffer_anchor,
17612                    Some(cx.theme().colors().editor_debugger_active_line_background),
17613                    window,
17614                    cx,
17615                );
17616
17617                cx.notify();
17618            }
17619
17620            handled.then_some(())
17621        })
17622        .is_some()
17623    }
17624
17625    pub fn copy_file_name_without_extension(
17626        &mut self,
17627        _: &CopyFileNameWithoutExtension,
17628        _: &mut Window,
17629        cx: &mut Context<Self>,
17630    ) {
17631        if let Some(file) = self.target_file(cx) {
17632            if let Some(file_stem) = file.path().file_stem() {
17633                if let Some(name) = file_stem.to_str() {
17634                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17635                }
17636            }
17637        }
17638    }
17639
17640    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17641        if let Some(file) = self.target_file(cx) {
17642            if let Some(file_name) = file.path().file_name() {
17643                if let Some(name) = file_name.to_str() {
17644                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17645                }
17646            }
17647        }
17648    }
17649
17650    pub fn toggle_git_blame(
17651        &mut self,
17652        _: &::git::Blame,
17653        window: &mut Window,
17654        cx: &mut Context<Self>,
17655    ) {
17656        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17657
17658        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17659            self.start_git_blame(true, window, cx);
17660        }
17661
17662        cx.notify();
17663    }
17664
17665    pub fn toggle_git_blame_inline(
17666        &mut self,
17667        _: &ToggleGitBlameInline,
17668        window: &mut Window,
17669        cx: &mut Context<Self>,
17670    ) {
17671        self.toggle_git_blame_inline_internal(true, window, cx);
17672        cx.notify();
17673    }
17674
17675    pub fn open_git_blame_commit(
17676        &mut self,
17677        _: &OpenGitBlameCommit,
17678        window: &mut Window,
17679        cx: &mut Context<Self>,
17680    ) {
17681        self.open_git_blame_commit_internal(window, cx);
17682    }
17683
17684    fn open_git_blame_commit_internal(
17685        &mut self,
17686        window: &mut Window,
17687        cx: &mut Context<Self>,
17688    ) -> Option<()> {
17689        let blame = self.blame.as_ref()?;
17690        let snapshot = self.snapshot(window, cx);
17691        let cursor = self.selections.newest::<Point>(cx).head();
17692        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17693        let blame_entry = blame
17694            .update(cx, |blame, cx| {
17695                blame
17696                    .blame_for_rows(
17697                        &[RowInfo {
17698                            buffer_id: Some(buffer.remote_id()),
17699                            buffer_row: Some(point.row),
17700                            ..Default::default()
17701                        }],
17702                        cx,
17703                    )
17704                    .next()
17705            })
17706            .flatten()?;
17707        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17708        let repo = blame.read(cx).repository(cx)?;
17709        let workspace = self.workspace()?.downgrade();
17710        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17711        None
17712    }
17713
17714    pub fn git_blame_inline_enabled(&self) -> bool {
17715        self.git_blame_inline_enabled
17716    }
17717
17718    pub fn toggle_selection_menu(
17719        &mut self,
17720        _: &ToggleSelectionMenu,
17721        _: &mut Window,
17722        cx: &mut Context<Self>,
17723    ) {
17724        self.show_selection_menu = self
17725            .show_selection_menu
17726            .map(|show_selections_menu| !show_selections_menu)
17727            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17728
17729        cx.notify();
17730    }
17731
17732    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17733        self.show_selection_menu
17734            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17735    }
17736
17737    fn start_git_blame(
17738        &mut self,
17739        user_triggered: bool,
17740        window: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) {
17743        if let Some(project) = self.project.as_ref() {
17744            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17745                return;
17746            };
17747
17748            if buffer.read(cx).file().is_none() {
17749                return;
17750            }
17751
17752            let focused = self.focus_handle(cx).contains_focused(window, cx);
17753
17754            let project = project.clone();
17755            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17756            self.blame_subscription =
17757                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17758            self.blame = Some(blame);
17759        }
17760    }
17761
17762    fn toggle_git_blame_inline_internal(
17763        &mut self,
17764        user_triggered: bool,
17765        window: &mut Window,
17766        cx: &mut Context<Self>,
17767    ) {
17768        if self.git_blame_inline_enabled {
17769            self.git_blame_inline_enabled = false;
17770            self.show_git_blame_inline = false;
17771            self.show_git_blame_inline_delay_task.take();
17772        } else {
17773            self.git_blame_inline_enabled = true;
17774            self.start_git_blame_inline(user_triggered, window, cx);
17775        }
17776
17777        cx.notify();
17778    }
17779
17780    fn start_git_blame_inline(
17781        &mut self,
17782        user_triggered: bool,
17783        window: &mut Window,
17784        cx: &mut Context<Self>,
17785    ) {
17786        self.start_git_blame(user_triggered, window, cx);
17787
17788        if ProjectSettings::get_global(cx)
17789            .git
17790            .inline_blame_delay()
17791            .is_some()
17792        {
17793            self.start_inline_blame_timer(window, cx);
17794        } else {
17795            self.show_git_blame_inline = true
17796        }
17797    }
17798
17799    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17800        self.blame.as_ref()
17801    }
17802
17803    pub fn show_git_blame_gutter(&self) -> bool {
17804        self.show_git_blame_gutter
17805    }
17806
17807    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17808        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17809    }
17810
17811    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17812        self.show_git_blame_inline
17813            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17814            && !self.newest_selection_head_on_empty_line(cx)
17815            && self.has_blame_entries(cx)
17816    }
17817
17818    fn has_blame_entries(&self, cx: &App) -> bool {
17819        self.blame()
17820            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17821    }
17822
17823    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17824        let cursor_anchor = self.selections.newest_anchor().head();
17825
17826        let snapshot = self.buffer.read(cx).snapshot(cx);
17827        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17828
17829        snapshot.line_len(buffer_row) == 0
17830    }
17831
17832    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17833        let buffer_and_selection = maybe!({
17834            let selection = self.selections.newest::<Point>(cx);
17835            let selection_range = selection.range();
17836
17837            let multi_buffer = self.buffer().read(cx);
17838            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17839            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17840
17841            let (buffer, range, _) = if selection.reversed {
17842                buffer_ranges.first()
17843            } else {
17844                buffer_ranges.last()
17845            }?;
17846
17847            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17848                ..text::ToPoint::to_point(&range.end, &buffer).row;
17849            Some((
17850                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17851                selection,
17852            ))
17853        });
17854
17855        let Some((buffer, selection)) = buffer_and_selection else {
17856            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17857        };
17858
17859        let Some(project) = self.project.as_ref() else {
17860            return Task::ready(Err(anyhow!("editor does not have project")));
17861        };
17862
17863        project.update(cx, |project, cx| {
17864            project.get_permalink_to_line(&buffer, selection, cx)
17865        })
17866    }
17867
17868    pub fn copy_permalink_to_line(
17869        &mut self,
17870        _: &CopyPermalinkToLine,
17871        window: &mut Window,
17872        cx: &mut Context<Self>,
17873    ) {
17874        let permalink_task = self.get_permalink_to_line(cx);
17875        let workspace = self.workspace();
17876
17877        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17878            Ok(permalink) => {
17879                cx.update(|_, cx| {
17880                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17881                })
17882                .ok();
17883            }
17884            Err(err) => {
17885                let message = format!("Failed to copy permalink: {err}");
17886
17887                anyhow::Result::<()>::Err(err).log_err();
17888
17889                if let Some(workspace) = workspace {
17890                    workspace
17891                        .update_in(cx, |workspace, _, cx| {
17892                            struct CopyPermalinkToLine;
17893
17894                            workspace.show_toast(
17895                                Toast::new(
17896                                    NotificationId::unique::<CopyPermalinkToLine>(),
17897                                    message,
17898                                ),
17899                                cx,
17900                            )
17901                        })
17902                        .ok();
17903                }
17904            }
17905        })
17906        .detach();
17907    }
17908
17909    pub fn copy_file_location(
17910        &mut self,
17911        _: &CopyFileLocation,
17912        _: &mut Window,
17913        cx: &mut Context<Self>,
17914    ) {
17915        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17916        if let Some(file) = self.target_file(cx) {
17917            if let Some(path) = file.path().to_str() {
17918                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17919            }
17920        }
17921    }
17922
17923    pub fn open_permalink_to_line(
17924        &mut self,
17925        _: &OpenPermalinkToLine,
17926        window: &mut Window,
17927        cx: &mut Context<Self>,
17928    ) {
17929        let permalink_task = self.get_permalink_to_line(cx);
17930        let workspace = self.workspace();
17931
17932        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17933            Ok(permalink) => {
17934                cx.update(|_, cx| {
17935                    cx.open_url(permalink.as_ref());
17936                })
17937                .ok();
17938            }
17939            Err(err) => {
17940                let message = format!("Failed to open permalink: {err}");
17941
17942                anyhow::Result::<()>::Err(err).log_err();
17943
17944                if let Some(workspace) = workspace {
17945                    workspace
17946                        .update(cx, |workspace, cx| {
17947                            struct OpenPermalinkToLine;
17948
17949                            workspace.show_toast(
17950                                Toast::new(
17951                                    NotificationId::unique::<OpenPermalinkToLine>(),
17952                                    message,
17953                                ),
17954                                cx,
17955                            )
17956                        })
17957                        .ok();
17958                }
17959            }
17960        })
17961        .detach();
17962    }
17963
17964    pub fn insert_uuid_v4(
17965        &mut self,
17966        _: &InsertUuidV4,
17967        window: &mut Window,
17968        cx: &mut Context<Self>,
17969    ) {
17970        self.insert_uuid(UuidVersion::V4, window, cx);
17971    }
17972
17973    pub fn insert_uuid_v7(
17974        &mut self,
17975        _: &InsertUuidV7,
17976        window: &mut Window,
17977        cx: &mut Context<Self>,
17978    ) {
17979        self.insert_uuid(UuidVersion::V7, window, cx);
17980    }
17981
17982    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17983        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17984        self.transact(window, cx, |this, window, cx| {
17985            let edits = this
17986                .selections
17987                .all::<Point>(cx)
17988                .into_iter()
17989                .map(|selection| {
17990                    let uuid = match version {
17991                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17992                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17993                    };
17994
17995                    (selection.range(), uuid.to_string())
17996                });
17997            this.edit(edits, cx);
17998            this.refresh_inline_completion(true, false, window, cx);
17999        });
18000    }
18001
18002    pub fn open_selections_in_multibuffer(
18003        &mut self,
18004        _: &OpenSelectionsInMultibuffer,
18005        window: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        let multibuffer = self.buffer.read(cx);
18009
18010        let Some(buffer) = multibuffer.as_singleton() else {
18011            return;
18012        };
18013
18014        let Some(workspace) = self.workspace() else {
18015            return;
18016        };
18017
18018        let locations = self
18019            .selections
18020            .disjoint_anchors()
18021            .iter()
18022            .map(|selection| {
18023                let range = if selection.reversed {
18024                    selection.end.text_anchor..selection.start.text_anchor
18025                } else {
18026                    selection.start.text_anchor..selection.end.text_anchor
18027                };
18028                Location {
18029                    buffer: buffer.clone(),
18030                    range,
18031                }
18032            })
18033            .collect::<Vec<_>>();
18034
18035        let title = multibuffer.title(cx).to_string();
18036
18037        cx.spawn_in(window, async move |_, cx| {
18038            workspace.update_in(cx, |workspace, window, cx| {
18039                Self::open_locations_in_multibuffer(
18040                    workspace,
18041                    locations,
18042                    format!("Selections for '{title}'"),
18043                    false,
18044                    MultibufferSelectionMode::All,
18045                    window,
18046                    cx,
18047                );
18048            })
18049        })
18050        .detach();
18051    }
18052
18053    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18054    /// last highlight added will be used.
18055    ///
18056    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18057    pub fn highlight_rows<T: 'static>(
18058        &mut self,
18059        range: Range<Anchor>,
18060        color: Hsla,
18061        options: RowHighlightOptions,
18062        cx: &mut Context<Self>,
18063    ) {
18064        let snapshot = self.buffer().read(cx).snapshot(cx);
18065        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18066        let ix = row_highlights.binary_search_by(|highlight| {
18067            Ordering::Equal
18068                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18069                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18070        });
18071
18072        if let Err(mut ix) = ix {
18073            let index = post_inc(&mut self.highlight_order);
18074
18075            // If this range intersects with the preceding highlight, then merge it with
18076            // the preceding highlight. Otherwise insert a new highlight.
18077            let mut merged = false;
18078            if ix > 0 {
18079                let prev_highlight = &mut row_highlights[ix - 1];
18080                if prev_highlight
18081                    .range
18082                    .end
18083                    .cmp(&range.start, &snapshot)
18084                    .is_ge()
18085                {
18086                    ix -= 1;
18087                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18088                        prev_highlight.range.end = range.end;
18089                    }
18090                    merged = true;
18091                    prev_highlight.index = index;
18092                    prev_highlight.color = color;
18093                    prev_highlight.options = options;
18094                }
18095            }
18096
18097            if !merged {
18098                row_highlights.insert(
18099                    ix,
18100                    RowHighlight {
18101                        range: range.clone(),
18102                        index,
18103                        color,
18104                        options,
18105                        type_id: TypeId::of::<T>(),
18106                    },
18107                );
18108            }
18109
18110            // If any of the following highlights intersect with this one, merge them.
18111            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18112                let highlight = &row_highlights[ix];
18113                if next_highlight
18114                    .range
18115                    .start
18116                    .cmp(&highlight.range.end, &snapshot)
18117                    .is_le()
18118                {
18119                    if next_highlight
18120                        .range
18121                        .end
18122                        .cmp(&highlight.range.end, &snapshot)
18123                        .is_gt()
18124                    {
18125                        row_highlights[ix].range.end = next_highlight.range.end;
18126                    }
18127                    row_highlights.remove(ix + 1);
18128                } else {
18129                    break;
18130                }
18131            }
18132        }
18133    }
18134
18135    /// Remove any highlighted row ranges of the given type that intersect the
18136    /// given ranges.
18137    pub fn remove_highlighted_rows<T: 'static>(
18138        &mut self,
18139        ranges_to_remove: Vec<Range<Anchor>>,
18140        cx: &mut Context<Self>,
18141    ) {
18142        let snapshot = self.buffer().read(cx).snapshot(cx);
18143        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18144        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18145        row_highlights.retain(|highlight| {
18146            while let Some(range_to_remove) = ranges_to_remove.peek() {
18147                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18148                    Ordering::Less | Ordering::Equal => {
18149                        ranges_to_remove.next();
18150                    }
18151                    Ordering::Greater => {
18152                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18153                            Ordering::Less | Ordering::Equal => {
18154                                return false;
18155                            }
18156                            Ordering::Greater => break,
18157                        }
18158                    }
18159                }
18160            }
18161
18162            true
18163        })
18164    }
18165
18166    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18167    pub fn clear_row_highlights<T: 'static>(&mut self) {
18168        self.highlighted_rows.remove(&TypeId::of::<T>());
18169    }
18170
18171    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18172    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18173        self.highlighted_rows
18174            .get(&TypeId::of::<T>())
18175            .map_or(&[] as &[_], |vec| vec.as_slice())
18176            .iter()
18177            .map(|highlight| (highlight.range.clone(), highlight.color))
18178    }
18179
18180    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18181    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18182    /// Allows to ignore certain kinds of highlights.
18183    pub fn highlighted_display_rows(
18184        &self,
18185        window: &mut Window,
18186        cx: &mut App,
18187    ) -> BTreeMap<DisplayRow, LineHighlight> {
18188        let snapshot = self.snapshot(window, cx);
18189        let mut used_highlight_orders = HashMap::default();
18190        self.highlighted_rows
18191            .iter()
18192            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18193            .fold(
18194                BTreeMap::<DisplayRow, LineHighlight>::new(),
18195                |mut unique_rows, highlight| {
18196                    let start = highlight.range.start.to_display_point(&snapshot);
18197                    let end = highlight.range.end.to_display_point(&snapshot);
18198                    let start_row = start.row().0;
18199                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18200                        && end.column() == 0
18201                    {
18202                        end.row().0.saturating_sub(1)
18203                    } else {
18204                        end.row().0
18205                    };
18206                    for row in start_row..=end_row {
18207                        let used_index =
18208                            used_highlight_orders.entry(row).or_insert(highlight.index);
18209                        if highlight.index >= *used_index {
18210                            *used_index = highlight.index;
18211                            unique_rows.insert(
18212                                DisplayRow(row),
18213                                LineHighlight {
18214                                    include_gutter: highlight.options.include_gutter,
18215                                    border: None,
18216                                    background: highlight.color.into(),
18217                                    type_id: Some(highlight.type_id),
18218                                },
18219                            );
18220                        }
18221                    }
18222                    unique_rows
18223                },
18224            )
18225    }
18226
18227    pub fn highlighted_display_row_for_autoscroll(
18228        &self,
18229        snapshot: &DisplaySnapshot,
18230    ) -> Option<DisplayRow> {
18231        self.highlighted_rows
18232            .values()
18233            .flat_map(|highlighted_rows| highlighted_rows.iter())
18234            .filter_map(|highlight| {
18235                if highlight.options.autoscroll {
18236                    Some(highlight.range.start.to_display_point(snapshot).row())
18237                } else {
18238                    None
18239                }
18240            })
18241            .min()
18242    }
18243
18244    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18245        self.highlight_background::<SearchWithinRange>(
18246            ranges,
18247            |colors| colors.editor_document_highlight_read_background,
18248            cx,
18249        )
18250    }
18251
18252    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18253        self.breadcrumb_header = Some(new_header);
18254    }
18255
18256    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18257        self.clear_background_highlights::<SearchWithinRange>(cx);
18258    }
18259
18260    pub fn highlight_background<T: 'static>(
18261        &mut self,
18262        ranges: &[Range<Anchor>],
18263        color_fetcher: fn(&ThemeColors) -> Hsla,
18264        cx: &mut Context<Self>,
18265    ) {
18266        self.background_highlights
18267            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18268        self.scrollbar_marker_state.dirty = true;
18269        cx.notify();
18270    }
18271
18272    pub fn clear_background_highlights<T: 'static>(
18273        &mut self,
18274        cx: &mut Context<Self>,
18275    ) -> Option<BackgroundHighlight> {
18276        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18277        if !text_highlights.1.is_empty() {
18278            self.scrollbar_marker_state.dirty = true;
18279            cx.notify();
18280        }
18281        Some(text_highlights)
18282    }
18283
18284    pub fn highlight_gutter<T: 'static>(
18285        &mut self,
18286        ranges: &[Range<Anchor>],
18287        color_fetcher: fn(&App) -> Hsla,
18288        cx: &mut Context<Self>,
18289    ) {
18290        self.gutter_highlights
18291            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18292        cx.notify();
18293    }
18294
18295    pub fn clear_gutter_highlights<T: 'static>(
18296        &mut self,
18297        cx: &mut Context<Self>,
18298    ) -> Option<GutterHighlight> {
18299        cx.notify();
18300        self.gutter_highlights.remove(&TypeId::of::<T>())
18301    }
18302
18303    #[cfg(feature = "test-support")]
18304    pub fn all_text_background_highlights(
18305        &self,
18306        window: &mut Window,
18307        cx: &mut Context<Self>,
18308    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18309        let snapshot = self.snapshot(window, cx);
18310        let buffer = &snapshot.buffer_snapshot;
18311        let start = buffer.anchor_before(0);
18312        let end = buffer.anchor_after(buffer.len());
18313        let theme = cx.theme().colors();
18314        self.background_highlights_in_range(start..end, &snapshot, theme)
18315    }
18316
18317    #[cfg(feature = "test-support")]
18318    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18319        let snapshot = self.buffer().read(cx).snapshot(cx);
18320
18321        let highlights = self
18322            .background_highlights
18323            .get(&TypeId::of::<items::BufferSearchHighlights>());
18324
18325        if let Some((_color, ranges)) = highlights {
18326            ranges
18327                .iter()
18328                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18329                .collect_vec()
18330        } else {
18331            vec![]
18332        }
18333    }
18334
18335    fn document_highlights_for_position<'a>(
18336        &'a self,
18337        position: Anchor,
18338        buffer: &'a MultiBufferSnapshot,
18339    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18340        let read_highlights = self
18341            .background_highlights
18342            .get(&TypeId::of::<DocumentHighlightRead>())
18343            .map(|h| &h.1);
18344        let write_highlights = self
18345            .background_highlights
18346            .get(&TypeId::of::<DocumentHighlightWrite>())
18347            .map(|h| &h.1);
18348        let left_position = position.bias_left(buffer);
18349        let right_position = position.bias_right(buffer);
18350        read_highlights
18351            .into_iter()
18352            .chain(write_highlights)
18353            .flat_map(move |ranges| {
18354                let start_ix = match ranges.binary_search_by(|probe| {
18355                    let cmp = probe.end.cmp(&left_position, buffer);
18356                    if cmp.is_ge() {
18357                        Ordering::Greater
18358                    } else {
18359                        Ordering::Less
18360                    }
18361                }) {
18362                    Ok(i) | Err(i) => i,
18363                };
18364
18365                ranges[start_ix..]
18366                    .iter()
18367                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18368            })
18369    }
18370
18371    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18372        self.background_highlights
18373            .get(&TypeId::of::<T>())
18374            .map_or(false, |(_, highlights)| !highlights.is_empty())
18375    }
18376
18377    pub fn background_highlights_in_range(
18378        &self,
18379        search_range: Range<Anchor>,
18380        display_snapshot: &DisplaySnapshot,
18381        theme: &ThemeColors,
18382    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18383        let mut results = Vec::new();
18384        for (color_fetcher, ranges) in self.background_highlights.values() {
18385            let color = color_fetcher(theme);
18386            let start_ix = match ranges.binary_search_by(|probe| {
18387                let cmp = probe
18388                    .end
18389                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18390                if cmp.is_gt() {
18391                    Ordering::Greater
18392                } else {
18393                    Ordering::Less
18394                }
18395            }) {
18396                Ok(i) | Err(i) => i,
18397            };
18398            for range in &ranges[start_ix..] {
18399                if range
18400                    .start
18401                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18402                    .is_ge()
18403                {
18404                    break;
18405                }
18406
18407                let start = range.start.to_display_point(display_snapshot);
18408                let end = range.end.to_display_point(display_snapshot);
18409                results.push((start..end, color))
18410            }
18411        }
18412        results
18413    }
18414
18415    pub fn background_highlight_row_ranges<T: 'static>(
18416        &self,
18417        search_range: Range<Anchor>,
18418        display_snapshot: &DisplaySnapshot,
18419        count: usize,
18420    ) -> Vec<RangeInclusive<DisplayPoint>> {
18421        let mut results = Vec::new();
18422        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18423            return vec![];
18424        };
18425
18426        let start_ix = match ranges.binary_search_by(|probe| {
18427            let cmp = probe
18428                .end
18429                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18430            if cmp.is_gt() {
18431                Ordering::Greater
18432            } else {
18433                Ordering::Less
18434            }
18435        }) {
18436            Ok(i) | Err(i) => i,
18437        };
18438        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18439            if let (Some(start_display), Some(end_display)) = (start, end) {
18440                results.push(
18441                    start_display.to_display_point(display_snapshot)
18442                        ..=end_display.to_display_point(display_snapshot),
18443                );
18444            }
18445        };
18446        let mut start_row: Option<Point> = None;
18447        let mut end_row: Option<Point> = None;
18448        if ranges.len() > count {
18449            return Vec::new();
18450        }
18451        for range in &ranges[start_ix..] {
18452            if range
18453                .start
18454                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18455                .is_ge()
18456            {
18457                break;
18458            }
18459            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18460            if let Some(current_row) = &end_row {
18461                if end.row == current_row.row {
18462                    continue;
18463                }
18464            }
18465            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18466            if start_row.is_none() {
18467                assert_eq!(end_row, None);
18468                start_row = Some(start);
18469                end_row = Some(end);
18470                continue;
18471            }
18472            if let Some(current_end) = end_row.as_mut() {
18473                if start.row > current_end.row + 1 {
18474                    push_region(start_row, end_row);
18475                    start_row = Some(start);
18476                    end_row = Some(end);
18477                } else {
18478                    // Merge two hunks.
18479                    *current_end = end;
18480                }
18481            } else {
18482                unreachable!();
18483            }
18484        }
18485        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18486        push_region(start_row, end_row);
18487        results
18488    }
18489
18490    pub fn gutter_highlights_in_range(
18491        &self,
18492        search_range: Range<Anchor>,
18493        display_snapshot: &DisplaySnapshot,
18494        cx: &App,
18495    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18496        let mut results = Vec::new();
18497        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18498            let color = color_fetcher(cx);
18499            let start_ix = match ranges.binary_search_by(|probe| {
18500                let cmp = probe
18501                    .end
18502                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18503                if cmp.is_gt() {
18504                    Ordering::Greater
18505                } else {
18506                    Ordering::Less
18507                }
18508            }) {
18509                Ok(i) | Err(i) => i,
18510            };
18511            for range in &ranges[start_ix..] {
18512                if range
18513                    .start
18514                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18515                    .is_ge()
18516                {
18517                    break;
18518                }
18519
18520                let start = range.start.to_display_point(display_snapshot);
18521                let end = range.end.to_display_point(display_snapshot);
18522                results.push((start..end, color))
18523            }
18524        }
18525        results
18526    }
18527
18528    /// Get the text ranges corresponding to the redaction query
18529    pub fn redacted_ranges(
18530        &self,
18531        search_range: Range<Anchor>,
18532        display_snapshot: &DisplaySnapshot,
18533        cx: &App,
18534    ) -> Vec<Range<DisplayPoint>> {
18535        display_snapshot
18536            .buffer_snapshot
18537            .redacted_ranges(search_range, |file| {
18538                if let Some(file) = file {
18539                    file.is_private()
18540                        && EditorSettings::get(
18541                            Some(SettingsLocation {
18542                                worktree_id: file.worktree_id(cx),
18543                                path: file.path().as_ref(),
18544                            }),
18545                            cx,
18546                        )
18547                        .redact_private_values
18548                } else {
18549                    false
18550                }
18551            })
18552            .map(|range| {
18553                range.start.to_display_point(display_snapshot)
18554                    ..range.end.to_display_point(display_snapshot)
18555            })
18556            .collect()
18557    }
18558
18559    pub fn highlight_text<T: 'static>(
18560        &mut self,
18561        ranges: Vec<Range<Anchor>>,
18562        style: HighlightStyle,
18563        cx: &mut Context<Self>,
18564    ) {
18565        self.display_map.update(cx, |map, _| {
18566            map.highlight_text(TypeId::of::<T>(), ranges, style)
18567        });
18568        cx.notify();
18569    }
18570
18571    pub(crate) fn highlight_inlays<T: 'static>(
18572        &mut self,
18573        highlights: Vec<InlayHighlight>,
18574        style: HighlightStyle,
18575        cx: &mut Context<Self>,
18576    ) {
18577        self.display_map.update(cx, |map, _| {
18578            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18579        });
18580        cx.notify();
18581    }
18582
18583    pub fn text_highlights<'a, T: 'static>(
18584        &'a self,
18585        cx: &'a App,
18586    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18587        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18588    }
18589
18590    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18591        let cleared = self
18592            .display_map
18593            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18594        if cleared {
18595            cx.notify();
18596        }
18597    }
18598
18599    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18600        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18601            && self.focus_handle.is_focused(window)
18602    }
18603
18604    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18605        self.show_cursor_when_unfocused = is_enabled;
18606        cx.notify();
18607    }
18608
18609    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18610        cx.notify();
18611    }
18612
18613    fn on_debug_session_event(
18614        &mut self,
18615        _session: Entity<Session>,
18616        event: &SessionEvent,
18617        cx: &mut Context<Self>,
18618    ) {
18619        match event {
18620            SessionEvent::InvalidateInlineValue => {
18621                self.refresh_inline_values(cx);
18622            }
18623            _ => {}
18624        }
18625    }
18626
18627    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18628        let Some(project) = self.project.clone() else {
18629            return;
18630        };
18631
18632        if !self.inline_value_cache.enabled {
18633            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18634            self.splice_inlays(&inlays, Vec::new(), cx);
18635            return;
18636        }
18637
18638        let current_execution_position = self
18639            .highlighted_rows
18640            .get(&TypeId::of::<ActiveDebugLine>())
18641            .and_then(|lines| lines.last().map(|line| line.range.start));
18642
18643        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18644            let inline_values = editor
18645                .update(cx, |editor, cx| {
18646                    let Some(current_execution_position) = current_execution_position else {
18647                        return Some(Task::ready(Ok(Vec::new())));
18648                    };
18649
18650                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18651                        let snapshot = buffer.snapshot(cx);
18652
18653                        let excerpt = snapshot.excerpt_containing(
18654                            current_execution_position..current_execution_position,
18655                        )?;
18656
18657                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18658                    })?;
18659
18660                    let range =
18661                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18662
18663                    project.inline_values(buffer, range, cx)
18664                })
18665                .ok()
18666                .flatten()?
18667                .await
18668                .context("refreshing debugger inlays")
18669                .log_err()?;
18670
18671            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18672
18673            for (buffer_id, inline_value) in inline_values
18674                .into_iter()
18675                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18676            {
18677                buffer_inline_values
18678                    .entry(buffer_id)
18679                    .or_default()
18680                    .push(inline_value);
18681            }
18682
18683            editor
18684                .update(cx, |editor, cx| {
18685                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18686                    let mut new_inlays = Vec::default();
18687
18688                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18689                        let buffer_id = buffer_snapshot.remote_id();
18690                        buffer_inline_values
18691                            .get(&buffer_id)
18692                            .into_iter()
18693                            .flatten()
18694                            .for_each(|hint| {
18695                                let inlay = Inlay::debugger_hint(
18696                                    post_inc(&mut editor.next_inlay_id),
18697                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18698                                    hint.text(),
18699                                );
18700
18701                                new_inlays.push(inlay);
18702                            });
18703                    }
18704
18705                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18706                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18707
18708                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18709                })
18710                .ok()?;
18711            Some(())
18712        });
18713    }
18714
18715    fn on_buffer_event(
18716        &mut self,
18717        multibuffer: &Entity<MultiBuffer>,
18718        event: &multi_buffer::Event,
18719        window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        match event {
18723            multi_buffer::Event::Edited {
18724                singleton_buffer_edited,
18725                edited_buffer,
18726            } => {
18727                self.scrollbar_marker_state.dirty = true;
18728                self.active_indent_guides_state.dirty = true;
18729                self.refresh_active_diagnostics(cx);
18730                self.refresh_code_actions(window, cx);
18731                self.refresh_selected_text_highlights(true, window, cx);
18732                refresh_matching_bracket_highlights(self, window, cx);
18733                if self.has_active_inline_completion() {
18734                    self.update_visible_inline_completion(window, cx);
18735                }
18736                if let Some(project) = self.project.as_ref() {
18737                    project.update(cx, |project, cx| {
18738                        if edited_buffer
18739                            .as_ref()
18740                            .is_some_and(|buffer| buffer.read(cx).file().is_some())
18741                        {
18742                            // Diagnostics are not local: an edit within one file (`pub mod foo()` -> `pub mod bar()`), may cause errors in another files with `foo()`.
18743                            // Hence, emit a project-wide event to pull for every buffer's diagnostics that has an open editor.
18744                            // TODO: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh explains the flow how
18745                            // diagnostics should be pulled: instead of pulling every open editor's buffer's diagnostics (which happens effectively due to emitting this event),
18746                            // we should only pull for the current buffer's diagnostics and get the rest via the workspace diagnostics LSP request — this is not implemented yet.
18747                            cx.emit(project::Event::PullWorkspaceDiagnostics);
18748                        }
18749
18750                        if let Some(buffer) = edited_buffer {
18751                            self.registered_buffers
18752                                .entry(buffer.read(cx).remote_id())
18753                                .or_insert_with(|| {
18754                                    project.register_buffer_with_language_servers(&buffer, cx)
18755                                });
18756                        }
18757                    });
18758                }
18759                cx.emit(EditorEvent::BufferEdited);
18760                cx.emit(SearchEvent::MatchesInvalidated);
18761                if *singleton_buffer_edited {
18762                    if let Some(project) = &self.project {
18763                        #[allow(clippy::mutable_key_type)]
18764                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18765                            multibuffer
18766                                .all_buffers()
18767                                .into_iter()
18768                                .filter_map(|buffer| {
18769                                    buffer.update(cx, |buffer, cx| {
18770                                        let language = buffer.language()?;
18771                                        let should_discard = project.update(cx, |project, cx| {
18772                                            project.is_local()
18773                                                && !project.has_language_servers_for(buffer, cx)
18774                                        });
18775                                        should_discard.not().then_some(language.clone())
18776                                    })
18777                                })
18778                                .collect::<HashSet<_>>()
18779                        });
18780                        if !languages_affected.is_empty() {
18781                            self.refresh_inlay_hints(
18782                                InlayHintRefreshReason::BufferEdited(languages_affected),
18783                                cx,
18784                            );
18785                        }
18786                    }
18787                }
18788
18789                let Some(project) = &self.project else { return };
18790                let (telemetry, is_via_ssh) = {
18791                    let project = project.read(cx);
18792                    let telemetry = project.client().telemetry().clone();
18793                    let is_via_ssh = project.is_via_ssh();
18794                    (telemetry, is_via_ssh)
18795                };
18796                refresh_linked_ranges(self, window, cx);
18797                telemetry.log_edit_event("editor", is_via_ssh);
18798            }
18799            multi_buffer::Event::ExcerptsAdded {
18800                buffer,
18801                predecessor,
18802                excerpts,
18803            } => {
18804                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18805                let buffer_id = buffer.read(cx).remote_id();
18806                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18807                    if let Some(project) = &self.project {
18808                        update_uncommitted_diff_for_buffer(
18809                            cx.entity(),
18810                            project,
18811                            [buffer.clone()],
18812                            self.buffer.clone(),
18813                            cx,
18814                        )
18815                        .detach();
18816                    }
18817                }
18818                cx.emit(EditorEvent::ExcerptsAdded {
18819                    buffer: buffer.clone(),
18820                    predecessor: *predecessor,
18821                    excerpts: excerpts.clone(),
18822                });
18823                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18824            }
18825            multi_buffer::Event::ExcerptsRemoved {
18826                ids,
18827                removed_buffer_ids,
18828            } => {
18829                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18830                let buffer = self.buffer.read(cx);
18831                self.registered_buffers
18832                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18833                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18834                cx.emit(EditorEvent::ExcerptsRemoved {
18835                    ids: ids.clone(),
18836                    removed_buffer_ids: removed_buffer_ids.clone(),
18837                })
18838            }
18839            multi_buffer::Event::ExcerptsEdited {
18840                excerpt_ids,
18841                buffer_ids,
18842            } => {
18843                self.display_map.update(cx, |map, cx| {
18844                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18845                });
18846                cx.emit(EditorEvent::ExcerptsEdited {
18847                    ids: excerpt_ids.clone(),
18848                })
18849            }
18850            multi_buffer::Event::ExcerptsExpanded { ids } => {
18851                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18852                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18853            }
18854            multi_buffer::Event::Reparsed(buffer_id) => {
18855                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18856                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18857
18858                cx.emit(EditorEvent::Reparsed(*buffer_id));
18859            }
18860            multi_buffer::Event::DiffHunksToggled => {
18861                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18862            }
18863            multi_buffer::Event::LanguageChanged(buffer_id) => {
18864                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18865                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18866                cx.emit(EditorEvent::Reparsed(*buffer_id));
18867                cx.notify();
18868            }
18869            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18870            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18871            multi_buffer::Event::FileHandleChanged
18872            | multi_buffer::Event::Reloaded
18873            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18874            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18875            multi_buffer::Event::DiagnosticsUpdated => {
18876                self.update_diagnostics_state(window, cx);
18877            }
18878            _ => {}
18879        };
18880    }
18881
18882    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
18883        self.refresh_active_diagnostics(cx);
18884        self.refresh_inline_diagnostics(true, window, cx);
18885        self.scrollbar_marker_state.dirty = true;
18886        cx.notify();
18887    }
18888
18889    pub fn start_temporary_diff_override(&mut self) {
18890        self.load_diff_task.take();
18891        self.temporary_diff_override = true;
18892    }
18893
18894    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18895        self.temporary_diff_override = false;
18896        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18897        self.buffer.update(cx, |buffer, cx| {
18898            buffer.set_all_diff_hunks_collapsed(cx);
18899        });
18900
18901        if let Some(project) = self.project.clone() {
18902            self.load_diff_task = Some(
18903                update_uncommitted_diff_for_buffer(
18904                    cx.entity(),
18905                    &project,
18906                    self.buffer.read(cx).all_buffers(),
18907                    self.buffer.clone(),
18908                    cx,
18909                )
18910                .shared(),
18911            );
18912        }
18913    }
18914
18915    fn on_display_map_changed(
18916        &mut self,
18917        _: Entity<DisplayMap>,
18918        _: &mut Window,
18919        cx: &mut Context<Self>,
18920    ) {
18921        cx.notify();
18922    }
18923
18924    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18925        let new_severity = if self.diagnostics_enabled() {
18926            EditorSettings::get_global(cx)
18927                .diagnostics_max_severity
18928                .unwrap_or(DiagnosticSeverity::Hint)
18929        } else {
18930            DiagnosticSeverity::Off
18931        };
18932        self.set_max_diagnostics_severity(new_severity, cx);
18933        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18934        self.update_edit_prediction_settings(cx);
18935        self.refresh_inline_completion(true, false, window, cx);
18936        self.refresh_inlay_hints(
18937            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18938                self.selections.newest_anchor().head(),
18939                &self.buffer.read(cx).snapshot(cx),
18940                cx,
18941            )),
18942            cx,
18943        );
18944
18945        let old_cursor_shape = self.cursor_shape;
18946
18947        {
18948            let editor_settings = EditorSettings::get_global(cx);
18949            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18950            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18951            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18952            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18953        }
18954
18955        if old_cursor_shape != self.cursor_shape {
18956            cx.emit(EditorEvent::CursorShapeChanged);
18957        }
18958
18959        let project_settings = ProjectSettings::get_global(cx);
18960        self.serialize_dirty_buffers =
18961            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18962
18963        if self.mode.is_full() {
18964            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18965            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18966            if self.show_inline_diagnostics != show_inline_diagnostics {
18967                self.show_inline_diagnostics = show_inline_diagnostics;
18968                self.refresh_inline_diagnostics(false, window, cx);
18969            }
18970
18971            if self.git_blame_inline_enabled != inline_blame_enabled {
18972                self.toggle_git_blame_inline_internal(false, window, cx);
18973            }
18974
18975            let minimap_settings = EditorSettings::get_global(cx).minimap;
18976            if self.minimap_visibility != MinimapVisibility::Disabled {
18977                if self.minimap_visibility.settings_visibility()
18978                    != minimap_settings.minimap_enabled()
18979                {
18980                    self.set_minimap_visibility(
18981                        MinimapVisibility::for_mode(self.mode(), cx),
18982                        window,
18983                        cx,
18984                    );
18985                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18986                    minimap_entity.update(cx, |minimap_editor, cx| {
18987                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18988                    })
18989                }
18990            }
18991        }
18992
18993        cx.notify();
18994    }
18995
18996    pub fn set_searchable(&mut self, searchable: bool) {
18997        self.searchable = searchable;
18998    }
18999
19000    pub fn searchable(&self) -> bool {
19001        self.searchable
19002    }
19003
19004    fn open_proposed_changes_editor(
19005        &mut self,
19006        _: &OpenProposedChangesEditor,
19007        window: &mut Window,
19008        cx: &mut Context<Self>,
19009    ) {
19010        let Some(workspace) = self.workspace() else {
19011            cx.propagate();
19012            return;
19013        };
19014
19015        let selections = self.selections.all::<usize>(cx);
19016        let multi_buffer = self.buffer.read(cx);
19017        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19018        let mut new_selections_by_buffer = HashMap::default();
19019        for selection in selections {
19020            for (buffer, range, _) in
19021                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19022            {
19023                let mut range = range.to_point(buffer);
19024                range.start.column = 0;
19025                range.end.column = buffer.line_len(range.end.row);
19026                new_selections_by_buffer
19027                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19028                    .or_insert(Vec::new())
19029                    .push(range)
19030            }
19031        }
19032
19033        let proposed_changes_buffers = new_selections_by_buffer
19034            .into_iter()
19035            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19036            .collect::<Vec<_>>();
19037        let proposed_changes_editor = cx.new(|cx| {
19038            ProposedChangesEditor::new(
19039                "Proposed changes",
19040                proposed_changes_buffers,
19041                self.project.clone(),
19042                window,
19043                cx,
19044            )
19045        });
19046
19047        window.defer(cx, move |window, cx| {
19048            workspace.update(cx, |workspace, cx| {
19049                workspace.active_pane().update(cx, |pane, cx| {
19050                    pane.add_item(
19051                        Box::new(proposed_changes_editor),
19052                        true,
19053                        true,
19054                        None,
19055                        window,
19056                        cx,
19057                    );
19058                });
19059            });
19060        });
19061    }
19062
19063    pub fn open_excerpts_in_split(
19064        &mut self,
19065        _: &OpenExcerptsSplit,
19066        window: &mut Window,
19067        cx: &mut Context<Self>,
19068    ) {
19069        self.open_excerpts_common(None, true, window, cx)
19070    }
19071
19072    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19073        self.open_excerpts_common(None, false, window, cx)
19074    }
19075
19076    fn open_excerpts_common(
19077        &mut self,
19078        jump_data: Option<JumpData>,
19079        split: bool,
19080        window: &mut Window,
19081        cx: &mut Context<Self>,
19082    ) {
19083        let Some(workspace) = self.workspace() else {
19084            cx.propagate();
19085            return;
19086        };
19087
19088        if self.buffer.read(cx).is_singleton() {
19089            cx.propagate();
19090            return;
19091        }
19092
19093        let mut new_selections_by_buffer = HashMap::default();
19094        match &jump_data {
19095            Some(JumpData::MultiBufferPoint {
19096                excerpt_id,
19097                position,
19098                anchor,
19099                line_offset_from_top,
19100            }) => {
19101                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19102                if let Some(buffer) = multi_buffer_snapshot
19103                    .buffer_id_for_excerpt(*excerpt_id)
19104                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19105                {
19106                    let buffer_snapshot = buffer.read(cx).snapshot();
19107                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19108                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19109                    } else {
19110                        buffer_snapshot.clip_point(*position, Bias::Left)
19111                    };
19112                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19113                    new_selections_by_buffer.insert(
19114                        buffer,
19115                        (
19116                            vec![jump_to_offset..jump_to_offset],
19117                            Some(*line_offset_from_top),
19118                        ),
19119                    );
19120                }
19121            }
19122            Some(JumpData::MultiBufferRow {
19123                row,
19124                line_offset_from_top,
19125            }) => {
19126                let point = MultiBufferPoint::new(row.0, 0);
19127                if let Some((buffer, buffer_point, _)) =
19128                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19129                {
19130                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19131                    new_selections_by_buffer
19132                        .entry(buffer)
19133                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19134                        .0
19135                        .push(buffer_offset..buffer_offset)
19136                }
19137            }
19138            None => {
19139                let selections = self.selections.all::<usize>(cx);
19140                let multi_buffer = self.buffer.read(cx);
19141                for selection in selections {
19142                    for (snapshot, range, _, anchor) in multi_buffer
19143                        .snapshot(cx)
19144                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19145                    {
19146                        if let Some(anchor) = anchor {
19147                            // selection is in a deleted hunk
19148                            let Some(buffer_id) = anchor.buffer_id else {
19149                                continue;
19150                            };
19151                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19152                                continue;
19153                            };
19154                            let offset = text::ToOffset::to_offset(
19155                                &anchor.text_anchor,
19156                                &buffer_handle.read(cx).snapshot(),
19157                            );
19158                            let range = offset..offset;
19159                            new_selections_by_buffer
19160                                .entry(buffer_handle)
19161                                .or_insert((Vec::new(), None))
19162                                .0
19163                                .push(range)
19164                        } else {
19165                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19166                            else {
19167                                continue;
19168                            };
19169                            new_selections_by_buffer
19170                                .entry(buffer_handle)
19171                                .or_insert((Vec::new(), None))
19172                                .0
19173                                .push(range)
19174                        }
19175                    }
19176                }
19177            }
19178        }
19179
19180        new_selections_by_buffer
19181            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19182
19183        if new_selections_by_buffer.is_empty() {
19184            return;
19185        }
19186
19187        // We defer the pane interaction because we ourselves are a workspace item
19188        // and activating a new item causes the pane to call a method on us reentrantly,
19189        // which panics if we're on the stack.
19190        window.defer(cx, move |window, cx| {
19191            workspace.update(cx, |workspace, cx| {
19192                let pane = if split {
19193                    workspace.adjacent_pane(window, cx)
19194                } else {
19195                    workspace.active_pane().clone()
19196                };
19197
19198                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19199                    let editor = buffer
19200                        .read(cx)
19201                        .file()
19202                        .is_none()
19203                        .then(|| {
19204                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19205                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19206                            // Instead, we try to activate the existing editor in the pane first.
19207                            let (editor, pane_item_index) =
19208                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19209                                    let editor = item.downcast::<Editor>()?;
19210                                    let singleton_buffer =
19211                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19212                                    if singleton_buffer == buffer {
19213                                        Some((editor, i))
19214                                    } else {
19215                                        None
19216                                    }
19217                                })?;
19218                            pane.update(cx, |pane, cx| {
19219                                pane.activate_item(pane_item_index, true, true, window, cx)
19220                            });
19221                            Some(editor)
19222                        })
19223                        .flatten()
19224                        .unwrap_or_else(|| {
19225                            workspace.open_project_item::<Self>(
19226                                pane.clone(),
19227                                buffer,
19228                                true,
19229                                true,
19230                                window,
19231                                cx,
19232                            )
19233                        });
19234
19235                    editor.update(cx, |editor, cx| {
19236                        let autoscroll = match scroll_offset {
19237                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19238                            None => Autoscroll::newest(),
19239                        };
19240                        let nav_history = editor.nav_history.take();
19241                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19242                            s.select_ranges(ranges);
19243                        });
19244                        editor.nav_history = nav_history;
19245                    });
19246                }
19247            })
19248        });
19249    }
19250
19251    // For now, don't allow opening excerpts in buffers that aren't backed by
19252    // regular project files.
19253    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19254        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19255    }
19256
19257    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19258        let snapshot = self.buffer.read(cx).read(cx);
19259        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19260        Some(
19261            ranges
19262                .iter()
19263                .map(move |range| {
19264                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19265                })
19266                .collect(),
19267        )
19268    }
19269
19270    fn selection_replacement_ranges(
19271        &self,
19272        range: Range<OffsetUtf16>,
19273        cx: &mut App,
19274    ) -> Vec<Range<OffsetUtf16>> {
19275        let selections = self.selections.all::<OffsetUtf16>(cx);
19276        let newest_selection = selections
19277            .iter()
19278            .max_by_key(|selection| selection.id)
19279            .unwrap();
19280        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19281        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19282        let snapshot = self.buffer.read(cx).read(cx);
19283        selections
19284            .into_iter()
19285            .map(|mut selection| {
19286                selection.start.0 =
19287                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19288                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19289                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19290                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19291            })
19292            .collect()
19293    }
19294
19295    fn report_editor_event(
19296        &self,
19297        event_type: &'static str,
19298        file_extension: Option<String>,
19299        cx: &App,
19300    ) {
19301        if cfg!(any(test, feature = "test-support")) {
19302            return;
19303        }
19304
19305        let Some(project) = &self.project else { return };
19306
19307        // If None, we are in a file without an extension
19308        let file = self
19309            .buffer
19310            .read(cx)
19311            .as_singleton()
19312            .and_then(|b| b.read(cx).file());
19313        let file_extension = file_extension.or(file
19314            .as_ref()
19315            .and_then(|file| Path::new(file.file_name(cx)).extension())
19316            .and_then(|e| e.to_str())
19317            .map(|a| a.to_string()));
19318
19319        let vim_mode = vim_enabled(cx);
19320
19321        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19322        let copilot_enabled = edit_predictions_provider
19323            == language::language_settings::EditPredictionProvider::Copilot;
19324        let copilot_enabled_for_language = self
19325            .buffer
19326            .read(cx)
19327            .language_settings(cx)
19328            .show_edit_predictions;
19329
19330        let project = project.read(cx);
19331        telemetry::event!(
19332            event_type,
19333            file_extension,
19334            vim_mode,
19335            copilot_enabled,
19336            copilot_enabled_for_language,
19337            edit_predictions_provider,
19338            is_via_ssh = project.is_via_ssh(),
19339        );
19340    }
19341
19342    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19343    /// with each line being an array of {text, highlight} objects.
19344    fn copy_highlight_json(
19345        &mut self,
19346        _: &CopyHighlightJson,
19347        window: &mut Window,
19348        cx: &mut Context<Self>,
19349    ) {
19350        #[derive(Serialize)]
19351        struct Chunk<'a> {
19352            text: String,
19353            highlight: Option<&'a str>,
19354        }
19355
19356        let snapshot = self.buffer.read(cx).snapshot(cx);
19357        let range = self
19358            .selected_text_range(false, window, cx)
19359            .and_then(|selection| {
19360                if selection.range.is_empty() {
19361                    None
19362                } else {
19363                    Some(selection.range)
19364                }
19365            })
19366            .unwrap_or_else(|| 0..snapshot.len());
19367
19368        let chunks = snapshot.chunks(range, true);
19369        let mut lines = Vec::new();
19370        let mut line: VecDeque<Chunk> = VecDeque::new();
19371
19372        let Some(style) = self.style.as_ref() else {
19373            return;
19374        };
19375
19376        for chunk in chunks {
19377            let highlight = chunk
19378                .syntax_highlight_id
19379                .and_then(|id| id.name(&style.syntax));
19380            let mut chunk_lines = chunk.text.split('\n').peekable();
19381            while let Some(text) = chunk_lines.next() {
19382                let mut merged_with_last_token = false;
19383                if let Some(last_token) = line.back_mut() {
19384                    if last_token.highlight == highlight {
19385                        last_token.text.push_str(text);
19386                        merged_with_last_token = true;
19387                    }
19388                }
19389
19390                if !merged_with_last_token {
19391                    line.push_back(Chunk {
19392                        text: text.into(),
19393                        highlight,
19394                    });
19395                }
19396
19397                if chunk_lines.peek().is_some() {
19398                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19399                        line.pop_front();
19400                    }
19401                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19402                        line.pop_back();
19403                    }
19404
19405                    lines.push(mem::take(&mut line));
19406                }
19407            }
19408        }
19409
19410        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19411            return;
19412        };
19413        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19414    }
19415
19416    pub fn open_context_menu(
19417        &mut self,
19418        _: &OpenContextMenu,
19419        window: &mut Window,
19420        cx: &mut Context<Self>,
19421    ) {
19422        self.request_autoscroll(Autoscroll::newest(), cx);
19423        let position = self.selections.newest_display(cx).start;
19424        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19425    }
19426
19427    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19428        &self.inlay_hint_cache
19429    }
19430
19431    pub fn replay_insert_event(
19432        &mut self,
19433        text: &str,
19434        relative_utf16_range: Option<Range<isize>>,
19435        window: &mut Window,
19436        cx: &mut Context<Self>,
19437    ) {
19438        if !self.input_enabled {
19439            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19440            return;
19441        }
19442        if let Some(relative_utf16_range) = relative_utf16_range {
19443            let selections = self.selections.all::<OffsetUtf16>(cx);
19444            self.change_selections(None, window, cx, |s| {
19445                let new_ranges = selections.into_iter().map(|range| {
19446                    let start = OffsetUtf16(
19447                        range
19448                            .head()
19449                            .0
19450                            .saturating_add_signed(relative_utf16_range.start),
19451                    );
19452                    let end = OffsetUtf16(
19453                        range
19454                            .head()
19455                            .0
19456                            .saturating_add_signed(relative_utf16_range.end),
19457                    );
19458                    start..end
19459                });
19460                s.select_ranges(new_ranges);
19461            });
19462        }
19463
19464        self.handle_input(text, window, cx);
19465    }
19466
19467    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19468        let Some(provider) = self.semantics_provider.as_ref() else {
19469            return false;
19470        };
19471
19472        let mut supports = false;
19473        self.buffer().update(cx, |this, cx| {
19474            this.for_each_buffer(|buffer| {
19475                supports |= provider.supports_inlay_hints(buffer, cx);
19476            });
19477        });
19478
19479        supports
19480    }
19481
19482    pub fn is_focused(&self, window: &Window) -> bool {
19483        self.focus_handle.is_focused(window)
19484    }
19485
19486    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19487        cx.emit(EditorEvent::Focused);
19488
19489        if let Some(descendant) = self
19490            .last_focused_descendant
19491            .take()
19492            .and_then(|descendant| descendant.upgrade())
19493        {
19494            window.focus(&descendant);
19495        } else {
19496            if let Some(blame) = self.blame.as_ref() {
19497                blame.update(cx, GitBlame::focus)
19498            }
19499
19500            self.blink_manager.update(cx, BlinkManager::enable);
19501            self.show_cursor_names(window, cx);
19502            self.buffer.update(cx, |buffer, cx| {
19503                buffer.finalize_last_transaction(cx);
19504                if self.leader_id.is_none() {
19505                    buffer.set_active_selections(
19506                        &self.selections.disjoint_anchors(),
19507                        self.selections.line_mode,
19508                        self.cursor_shape,
19509                        cx,
19510                    );
19511                }
19512            });
19513        }
19514    }
19515
19516    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19517        cx.emit(EditorEvent::FocusedIn)
19518    }
19519
19520    fn handle_focus_out(
19521        &mut self,
19522        event: FocusOutEvent,
19523        _window: &mut Window,
19524        cx: &mut Context<Self>,
19525    ) {
19526        if event.blurred != self.focus_handle {
19527            self.last_focused_descendant = Some(event.blurred);
19528        }
19529        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19530    }
19531
19532    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19533        self.blink_manager.update(cx, BlinkManager::disable);
19534        self.buffer
19535            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19536
19537        if let Some(blame) = self.blame.as_ref() {
19538            blame.update(cx, GitBlame::blur)
19539        }
19540        if !self.hover_state.focused(window, cx) {
19541            hide_hover(self, cx);
19542        }
19543        if !self
19544            .context_menu
19545            .borrow()
19546            .as_ref()
19547            .is_some_and(|context_menu| context_menu.focused(window, cx))
19548        {
19549            self.hide_context_menu(window, cx);
19550        }
19551        self.discard_inline_completion(false, cx);
19552        cx.emit(EditorEvent::Blurred);
19553        cx.notify();
19554    }
19555
19556    pub fn register_action<A: Action>(
19557        &mut self,
19558        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19559    ) -> Subscription {
19560        let id = self.next_editor_action_id.post_inc();
19561        let listener = Arc::new(listener);
19562        self.editor_actions.borrow_mut().insert(
19563            id,
19564            Box::new(move |window, _| {
19565                let listener = listener.clone();
19566                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19567                    let action = action.downcast_ref().unwrap();
19568                    if phase == DispatchPhase::Bubble {
19569                        listener(action, window, cx)
19570                    }
19571                })
19572            }),
19573        );
19574
19575        let editor_actions = self.editor_actions.clone();
19576        Subscription::new(move || {
19577            editor_actions.borrow_mut().remove(&id);
19578        })
19579    }
19580
19581    pub fn file_header_size(&self) -> u32 {
19582        FILE_HEADER_HEIGHT
19583    }
19584
19585    pub fn restore(
19586        &mut self,
19587        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19588        window: &mut Window,
19589        cx: &mut Context<Self>,
19590    ) {
19591        let workspace = self.workspace();
19592        let project = self.project.as_ref();
19593        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19594            let mut tasks = Vec::new();
19595            for (buffer_id, changes) in revert_changes {
19596                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19597                    buffer.update(cx, |buffer, cx| {
19598                        buffer.edit(
19599                            changes
19600                                .into_iter()
19601                                .map(|(range, text)| (range, text.to_string())),
19602                            None,
19603                            cx,
19604                        );
19605                    });
19606
19607                    if let Some(project) =
19608                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19609                    {
19610                        project.update(cx, |project, cx| {
19611                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19612                        })
19613                    }
19614                }
19615            }
19616            tasks
19617        });
19618        cx.spawn_in(window, async move |_, cx| {
19619            for (buffer, task) in save_tasks {
19620                let result = task.await;
19621                if result.is_err() {
19622                    let Some(path) = buffer
19623                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19624                        .ok()
19625                    else {
19626                        continue;
19627                    };
19628                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19629                        let Some(task) = cx
19630                            .update_window_entity(&workspace, |workspace, window, cx| {
19631                                workspace
19632                                    .open_path_preview(path, None, false, false, false, window, cx)
19633                            })
19634                            .ok()
19635                        else {
19636                            continue;
19637                        };
19638                        task.await.log_err();
19639                    }
19640                }
19641            }
19642        })
19643        .detach();
19644        self.change_selections(None, window, cx, |selections| selections.refresh());
19645    }
19646
19647    pub fn to_pixel_point(
19648        &self,
19649        source: multi_buffer::Anchor,
19650        editor_snapshot: &EditorSnapshot,
19651        window: &mut Window,
19652    ) -> Option<gpui::Point<Pixels>> {
19653        let source_point = source.to_display_point(editor_snapshot);
19654        self.display_to_pixel_point(source_point, editor_snapshot, window)
19655    }
19656
19657    pub fn display_to_pixel_point(
19658        &self,
19659        source: DisplayPoint,
19660        editor_snapshot: &EditorSnapshot,
19661        window: &mut Window,
19662    ) -> Option<gpui::Point<Pixels>> {
19663        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19664        let text_layout_details = self.text_layout_details(window);
19665        let scroll_top = text_layout_details
19666            .scroll_anchor
19667            .scroll_position(editor_snapshot)
19668            .y;
19669
19670        if source.row().as_f32() < scroll_top.floor() {
19671            return None;
19672        }
19673        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19674        let source_y = line_height * (source.row().as_f32() - scroll_top);
19675        Some(gpui::Point::new(source_x, source_y))
19676    }
19677
19678    pub fn has_visible_completions_menu(&self) -> bool {
19679        !self.edit_prediction_preview_is_active()
19680            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19681                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19682            })
19683    }
19684
19685    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19686        if self.mode.is_minimap() {
19687            return;
19688        }
19689        self.addons
19690            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19691    }
19692
19693    pub fn unregister_addon<T: Addon>(&mut self) {
19694        self.addons.remove(&std::any::TypeId::of::<T>());
19695    }
19696
19697    pub fn addon<T: Addon>(&self) -> Option<&T> {
19698        let type_id = std::any::TypeId::of::<T>();
19699        self.addons
19700            .get(&type_id)
19701            .and_then(|item| item.to_any().downcast_ref::<T>())
19702    }
19703
19704    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19705        let type_id = std::any::TypeId::of::<T>();
19706        self.addons
19707            .get_mut(&type_id)
19708            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19709    }
19710
19711    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19712        let text_layout_details = self.text_layout_details(window);
19713        let style = &text_layout_details.editor_style;
19714        let font_id = window.text_system().resolve_font(&style.text.font());
19715        let font_size = style.text.font_size.to_pixels(window.rem_size());
19716        let line_height = style.text.line_height_in_pixels(window.rem_size());
19717        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19718
19719        gpui::Size::new(em_width, line_height)
19720    }
19721
19722    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19723        self.load_diff_task.clone()
19724    }
19725
19726    fn read_metadata_from_db(
19727        &mut self,
19728        item_id: u64,
19729        workspace_id: WorkspaceId,
19730        window: &mut Window,
19731        cx: &mut Context<Editor>,
19732    ) {
19733        if self.is_singleton(cx)
19734            && !self.mode.is_minimap()
19735            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19736        {
19737            let buffer_snapshot = OnceCell::new();
19738
19739            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19740                if !folds.is_empty() {
19741                    let snapshot =
19742                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19743                    self.fold_ranges(
19744                        folds
19745                            .into_iter()
19746                            .map(|(start, end)| {
19747                                snapshot.clip_offset(start, Bias::Left)
19748                                    ..snapshot.clip_offset(end, Bias::Right)
19749                            })
19750                            .collect(),
19751                        false,
19752                        window,
19753                        cx,
19754                    );
19755                }
19756            }
19757
19758            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19759                if !selections.is_empty() {
19760                    let snapshot =
19761                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19762                    self.change_selections(None, window, cx, |s| {
19763                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19764                            snapshot.clip_offset(start, Bias::Left)
19765                                ..snapshot.clip_offset(end, Bias::Right)
19766                        }));
19767                    });
19768                }
19769            };
19770        }
19771
19772        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19773    }
19774}
19775
19776fn vim_enabled(cx: &App) -> bool {
19777    cx.global::<SettingsStore>()
19778        .raw_user_settings()
19779        .get("vim_mode")
19780        == Some(&serde_json::Value::Bool(true))
19781}
19782
19783fn process_completion_for_edit(
19784    completion: &Completion,
19785    intent: CompletionIntent,
19786    buffer: &Entity<Buffer>,
19787    cursor_position: &text::Anchor,
19788    cx: &mut Context<Editor>,
19789) -> CompletionEdit {
19790    let buffer = buffer.read(cx);
19791    let buffer_snapshot = buffer.snapshot();
19792    let (snippet, new_text) = if completion.is_snippet() {
19793        let mut snippet_source = completion.new_text.clone();
19794        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19795            if scope.prefers_label_for_snippet_in_completion() {
19796                if let Some(label) = completion.label() {
19797                    if matches!(
19798                        completion.kind(),
19799                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19800                    ) {
19801                        snippet_source = label;
19802                    }
19803                }
19804            }
19805        }
19806        match Snippet::parse(&snippet_source).log_err() {
19807            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19808            None => (None, completion.new_text.clone()),
19809        }
19810    } else {
19811        (None, completion.new_text.clone())
19812    };
19813
19814    let mut range_to_replace = {
19815        let replace_range = &completion.replace_range;
19816        if let CompletionSource::Lsp {
19817            insert_range: Some(insert_range),
19818            ..
19819        } = &completion.source
19820        {
19821            debug_assert_eq!(
19822                insert_range.start, replace_range.start,
19823                "insert_range and replace_range should start at the same position"
19824            );
19825            debug_assert!(
19826                insert_range
19827                    .start
19828                    .cmp(&cursor_position, &buffer_snapshot)
19829                    .is_le(),
19830                "insert_range should start before or at cursor position"
19831            );
19832            debug_assert!(
19833                replace_range
19834                    .start
19835                    .cmp(&cursor_position, &buffer_snapshot)
19836                    .is_le(),
19837                "replace_range should start before or at cursor position"
19838            );
19839            debug_assert!(
19840                insert_range
19841                    .end
19842                    .cmp(&cursor_position, &buffer_snapshot)
19843                    .is_le(),
19844                "insert_range should end before or at cursor position"
19845            );
19846
19847            let should_replace = match intent {
19848                CompletionIntent::CompleteWithInsert => false,
19849                CompletionIntent::CompleteWithReplace => true,
19850                CompletionIntent::Complete | CompletionIntent::Compose => {
19851                    let insert_mode =
19852                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19853                            .completions
19854                            .lsp_insert_mode;
19855                    match insert_mode {
19856                        LspInsertMode::Insert => false,
19857                        LspInsertMode::Replace => true,
19858                        LspInsertMode::ReplaceSubsequence => {
19859                            let mut text_to_replace = buffer.chars_for_range(
19860                                buffer.anchor_before(replace_range.start)
19861                                    ..buffer.anchor_after(replace_range.end),
19862                            );
19863                            let mut current_needle = text_to_replace.next();
19864                            for haystack_ch in completion.label.text.chars() {
19865                                if let Some(needle_ch) = current_needle {
19866                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19867                                        current_needle = text_to_replace.next();
19868                                    }
19869                                }
19870                            }
19871                            current_needle.is_none()
19872                        }
19873                        LspInsertMode::ReplaceSuffix => {
19874                            if replace_range
19875                                .end
19876                                .cmp(&cursor_position, &buffer_snapshot)
19877                                .is_gt()
19878                            {
19879                                let range_after_cursor = *cursor_position..replace_range.end;
19880                                let text_after_cursor = buffer
19881                                    .text_for_range(
19882                                        buffer.anchor_before(range_after_cursor.start)
19883                                            ..buffer.anchor_after(range_after_cursor.end),
19884                                    )
19885                                    .collect::<String>()
19886                                    .to_ascii_lowercase();
19887                                completion
19888                                    .label
19889                                    .text
19890                                    .to_ascii_lowercase()
19891                                    .ends_with(&text_after_cursor)
19892                            } else {
19893                                true
19894                            }
19895                        }
19896                    }
19897                }
19898            };
19899
19900            if should_replace {
19901                replace_range.clone()
19902            } else {
19903                insert_range.clone()
19904            }
19905        } else {
19906            replace_range.clone()
19907        }
19908    };
19909
19910    if range_to_replace
19911        .end
19912        .cmp(&cursor_position, &buffer_snapshot)
19913        .is_lt()
19914    {
19915        range_to_replace.end = *cursor_position;
19916    }
19917
19918    CompletionEdit {
19919        new_text,
19920        replace_range: range_to_replace.to_offset(&buffer),
19921        snippet,
19922    }
19923}
19924
19925struct CompletionEdit {
19926    new_text: String,
19927    replace_range: Range<usize>,
19928    snippet: Option<Snippet>,
19929}
19930
19931fn insert_extra_newline_brackets(
19932    buffer: &MultiBufferSnapshot,
19933    range: Range<usize>,
19934    language: &language::LanguageScope,
19935) -> bool {
19936    let leading_whitespace_len = buffer
19937        .reversed_chars_at(range.start)
19938        .take_while(|c| c.is_whitespace() && *c != '\n')
19939        .map(|c| c.len_utf8())
19940        .sum::<usize>();
19941    let trailing_whitespace_len = buffer
19942        .chars_at(range.end)
19943        .take_while(|c| c.is_whitespace() && *c != '\n')
19944        .map(|c| c.len_utf8())
19945        .sum::<usize>();
19946    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19947
19948    language.brackets().any(|(pair, enabled)| {
19949        let pair_start = pair.start.trim_end();
19950        let pair_end = pair.end.trim_start();
19951
19952        enabled
19953            && pair.newline
19954            && buffer.contains_str_at(range.end, pair_end)
19955            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19956    })
19957}
19958
19959fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19960    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19961        [(buffer, range, _)] => (*buffer, range.clone()),
19962        _ => return false,
19963    };
19964    let pair = {
19965        let mut result: Option<BracketMatch> = None;
19966
19967        for pair in buffer
19968            .all_bracket_ranges(range.clone())
19969            .filter(move |pair| {
19970                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19971            })
19972        {
19973            let len = pair.close_range.end - pair.open_range.start;
19974
19975            if let Some(existing) = &result {
19976                let existing_len = existing.close_range.end - existing.open_range.start;
19977                if len > existing_len {
19978                    continue;
19979                }
19980            }
19981
19982            result = Some(pair);
19983        }
19984
19985        result
19986    };
19987    let Some(pair) = pair else {
19988        return false;
19989    };
19990    pair.newline_only
19991        && buffer
19992            .chars_for_range(pair.open_range.end..range.start)
19993            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19994            .all(|c| c.is_whitespace() && c != '\n')
19995}
19996
19997fn update_uncommitted_diff_for_buffer(
19998    editor: Entity<Editor>,
19999    project: &Entity<Project>,
20000    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20001    buffer: Entity<MultiBuffer>,
20002    cx: &mut App,
20003) -> Task<()> {
20004    let mut tasks = Vec::new();
20005    project.update(cx, |project, cx| {
20006        for buffer in buffers {
20007            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20008                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20009            }
20010        }
20011    });
20012    cx.spawn(async move |cx| {
20013        let diffs = future::join_all(tasks).await;
20014        if editor
20015            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20016            .unwrap_or(false)
20017        {
20018            return;
20019        }
20020
20021        buffer
20022            .update(cx, |buffer, cx| {
20023                for diff in diffs.into_iter().flatten() {
20024                    buffer.add_diff(diff, cx);
20025                }
20026            })
20027            .ok();
20028    })
20029}
20030
20031fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20032    let tab_size = tab_size.get() as usize;
20033    let mut width = offset;
20034
20035    for ch in text.chars() {
20036        width += if ch == '\t' {
20037            tab_size - (width % tab_size)
20038        } else {
20039            1
20040        };
20041    }
20042
20043    width - offset
20044}
20045
20046#[cfg(test)]
20047mod tests {
20048    use super::*;
20049
20050    #[test]
20051    fn test_string_size_with_expanded_tabs() {
20052        let nz = |val| NonZeroU32::new(val).unwrap();
20053        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20054        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20055        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20056        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20057        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20058        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20059        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20060        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20061    }
20062}
20063
20064/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20065struct WordBreakingTokenizer<'a> {
20066    input: &'a str,
20067}
20068
20069impl<'a> WordBreakingTokenizer<'a> {
20070    fn new(input: &'a str) -> Self {
20071        Self { input }
20072    }
20073}
20074
20075fn is_char_ideographic(ch: char) -> bool {
20076    use unicode_script::Script::*;
20077    use unicode_script::UnicodeScript;
20078    matches!(ch.script(), Han | Tangut | Yi)
20079}
20080
20081fn is_grapheme_ideographic(text: &str) -> bool {
20082    text.chars().any(is_char_ideographic)
20083}
20084
20085fn is_grapheme_whitespace(text: &str) -> bool {
20086    text.chars().any(|x| x.is_whitespace())
20087}
20088
20089fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20090    text.chars().next().map_or(false, |ch| {
20091        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20092    })
20093}
20094
20095#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20096enum WordBreakToken<'a> {
20097    Word { token: &'a str, grapheme_len: usize },
20098    InlineWhitespace { token: &'a str, grapheme_len: usize },
20099    Newline,
20100}
20101
20102impl<'a> Iterator for WordBreakingTokenizer<'a> {
20103    /// Yields a span, the count of graphemes in the token, and whether it was
20104    /// whitespace. Note that it also breaks at word boundaries.
20105    type Item = WordBreakToken<'a>;
20106
20107    fn next(&mut self) -> Option<Self::Item> {
20108        use unicode_segmentation::UnicodeSegmentation;
20109        if self.input.is_empty() {
20110            return None;
20111        }
20112
20113        let mut iter = self.input.graphemes(true).peekable();
20114        let mut offset = 0;
20115        let mut grapheme_len = 0;
20116        if let Some(first_grapheme) = iter.next() {
20117            let is_newline = first_grapheme == "\n";
20118            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20119            offset += first_grapheme.len();
20120            grapheme_len += 1;
20121            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20122                if let Some(grapheme) = iter.peek().copied() {
20123                    if should_stay_with_preceding_ideograph(grapheme) {
20124                        offset += grapheme.len();
20125                        grapheme_len += 1;
20126                    }
20127                }
20128            } else {
20129                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20130                let mut next_word_bound = words.peek().copied();
20131                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20132                    next_word_bound = words.next();
20133                }
20134                while let Some(grapheme) = iter.peek().copied() {
20135                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20136                        break;
20137                    };
20138                    if is_grapheme_whitespace(grapheme) != is_whitespace
20139                        || (grapheme == "\n") != is_newline
20140                    {
20141                        break;
20142                    };
20143                    offset += grapheme.len();
20144                    grapheme_len += 1;
20145                    iter.next();
20146                }
20147            }
20148            let token = &self.input[..offset];
20149            self.input = &self.input[offset..];
20150            if token == "\n" {
20151                Some(WordBreakToken::Newline)
20152            } else if is_whitespace {
20153                Some(WordBreakToken::InlineWhitespace {
20154                    token,
20155                    grapheme_len,
20156                })
20157            } else {
20158                Some(WordBreakToken::Word {
20159                    token,
20160                    grapheme_len,
20161                })
20162            }
20163        } else {
20164            None
20165        }
20166    }
20167}
20168
20169#[test]
20170fn test_word_breaking_tokenizer() {
20171    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20172        ("", &[]),
20173        ("  ", &[whitespace("  ", 2)]),
20174        ("Ʒ", &[word("Ʒ", 1)]),
20175        ("Ǽ", &[word("Ǽ", 1)]),
20176        ("", &[word("", 1)]),
20177        ("⋑⋑", &[word("⋑⋑", 2)]),
20178        (
20179            "原理,进而",
20180            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20181        ),
20182        (
20183            "hello world",
20184            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20185        ),
20186        (
20187            "hello, world",
20188            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20189        ),
20190        (
20191            "  hello world",
20192            &[
20193                whitespace("  ", 2),
20194                word("hello", 5),
20195                whitespace(" ", 1),
20196                word("world", 5),
20197            ],
20198        ),
20199        (
20200            "这是什么 \n 钢笔",
20201            &[
20202                word("", 1),
20203                word("", 1),
20204                word("", 1),
20205                word("", 1),
20206                whitespace(" ", 1),
20207                newline(),
20208                whitespace(" ", 1),
20209                word("", 1),
20210                word("", 1),
20211            ],
20212        ),
20213        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20214    ];
20215
20216    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20217        WordBreakToken::Word {
20218            token,
20219            grapheme_len,
20220        }
20221    }
20222
20223    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20224        WordBreakToken::InlineWhitespace {
20225            token,
20226            grapheme_len,
20227        }
20228    }
20229
20230    fn newline() -> WordBreakToken<'static> {
20231        WordBreakToken::Newline
20232    }
20233
20234    for (input, result) in tests {
20235        assert_eq!(
20236            WordBreakingTokenizer::new(input)
20237                .collect::<Vec<_>>()
20238                .as_slice(),
20239            *result,
20240        );
20241    }
20242}
20243
20244fn wrap_with_prefix(
20245    line_prefix: String,
20246    unwrapped_text: String,
20247    wrap_column: usize,
20248    tab_size: NonZeroU32,
20249    preserve_existing_whitespace: bool,
20250) -> String {
20251    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20252    let mut wrapped_text = String::new();
20253    let mut current_line = line_prefix.clone();
20254
20255    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20256    let mut current_line_len = line_prefix_len;
20257    let mut in_whitespace = false;
20258    for token in tokenizer {
20259        let have_preceding_whitespace = in_whitespace;
20260        match token {
20261            WordBreakToken::Word {
20262                token,
20263                grapheme_len,
20264            } => {
20265                in_whitespace = false;
20266                if current_line_len + grapheme_len > wrap_column
20267                    && current_line_len != line_prefix_len
20268                {
20269                    wrapped_text.push_str(current_line.trim_end());
20270                    wrapped_text.push('\n');
20271                    current_line.truncate(line_prefix.len());
20272                    current_line_len = line_prefix_len;
20273                }
20274                current_line.push_str(token);
20275                current_line_len += grapheme_len;
20276            }
20277            WordBreakToken::InlineWhitespace {
20278                mut token,
20279                mut grapheme_len,
20280            } => {
20281                in_whitespace = true;
20282                if have_preceding_whitespace && !preserve_existing_whitespace {
20283                    continue;
20284                }
20285                if !preserve_existing_whitespace {
20286                    token = " ";
20287                    grapheme_len = 1;
20288                }
20289                if current_line_len + grapheme_len > wrap_column {
20290                    wrapped_text.push_str(current_line.trim_end());
20291                    wrapped_text.push('\n');
20292                    current_line.truncate(line_prefix.len());
20293                    current_line_len = line_prefix_len;
20294                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20295                    current_line.push_str(token);
20296                    current_line_len += grapheme_len;
20297                }
20298            }
20299            WordBreakToken::Newline => {
20300                in_whitespace = true;
20301                if preserve_existing_whitespace {
20302                    wrapped_text.push_str(current_line.trim_end());
20303                    wrapped_text.push('\n');
20304                    current_line.truncate(line_prefix.len());
20305                    current_line_len = line_prefix_len;
20306                } else if have_preceding_whitespace {
20307                    continue;
20308                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20309                {
20310                    wrapped_text.push_str(current_line.trim_end());
20311                    wrapped_text.push('\n');
20312                    current_line.truncate(line_prefix.len());
20313                    current_line_len = line_prefix_len;
20314                } else if current_line_len != line_prefix_len {
20315                    current_line.push(' ');
20316                    current_line_len += 1;
20317                }
20318            }
20319        }
20320    }
20321
20322    if !current_line.is_empty() {
20323        wrapped_text.push_str(&current_line);
20324    }
20325    wrapped_text
20326}
20327
20328#[test]
20329fn test_wrap_with_prefix() {
20330    assert_eq!(
20331        wrap_with_prefix(
20332            "# ".to_string(),
20333            "abcdefg".to_string(),
20334            4,
20335            NonZeroU32::new(4).unwrap(),
20336            false,
20337        ),
20338        "# abcdefg"
20339    );
20340    assert_eq!(
20341        wrap_with_prefix(
20342            "".to_string(),
20343            "\thello world".to_string(),
20344            8,
20345            NonZeroU32::new(4).unwrap(),
20346            false,
20347        ),
20348        "hello\nworld"
20349    );
20350    assert_eq!(
20351        wrap_with_prefix(
20352            "// ".to_string(),
20353            "xx \nyy zz aa bb cc".to_string(),
20354            12,
20355            NonZeroU32::new(4).unwrap(),
20356            false,
20357        ),
20358        "// xx yy zz\n// aa bb cc"
20359    );
20360    assert_eq!(
20361        wrap_with_prefix(
20362            String::new(),
20363            "这是什么 \n 钢笔".to_string(),
20364            3,
20365            NonZeroU32::new(4).unwrap(),
20366            false,
20367        ),
20368        "这是什\n么 钢\n"
20369    );
20370}
20371
20372pub trait CollaborationHub {
20373    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20374    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20375    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20376}
20377
20378impl CollaborationHub for Entity<Project> {
20379    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20380        self.read(cx).collaborators()
20381    }
20382
20383    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20384        self.read(cx).user_store().read(cx).participant_indices()
20385    }
20386
20387    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20388        let this = self.read(cx);
20389        let user_ids = this.collaborators().values().map(|c| c.user_id);
20390        this.user_store().read(cx).participant_names(user_ids, cx)
20391    }
20392}
20393
20394pub trait SemanticsProvider {
20395    fn hover(
20396        &self,
20397        buffer: &Entity<Buffer>,
20398        position: text::Anchor,
20399        cx: &mut App,
20400    ) -> Option<Task<Vec<project::Hover>>>;
20401
20402    fn inline_values(
20403        &self,
20404        buffer_handle: Entity<Buffer>,
20405        range: Range<text::Anchor>,
20406        cx: &mut App,
20407    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20408
20409    fn inlay_hints(
20410        &self,
20411        buffer_handle: Entity<Buffer>,
20412        range: Range<text::Anchor>,
20413        cx: &mut App,
20414    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20415
20416    fn resolve_inlay_hint(
20417        &self,
20418        hint: InlayHint,
20419        buffer_handle: Entity<Buffer>,
20420        server_id: LanguageServerId,
20421        cx: &mut App,
20422    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20423
20424    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20425
20426    fn document_highlights(
20427        &self,
20428        buffer: &Entity<Buffer>,
20429        position: text::Anchor,
20430        cx: &mut App,
20431    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20432
20433    fn definitions(
20434        &self,
20435        buffer: &Entity<Buffer>,
20436        position: text::Anchor,
20437        kind: GotoDefinitionKind,
20438        cx: &mut App,
20439    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20440
20441    fn range_for_rename(
20442        &self,
20443        buffer: &Entity<Buffer>,
20444        position: text::Anchor,
20445        cx: &mut App,
20446    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20447
20448    fn perform_rename(
20449        &self,
20450        buffer: &Entity<Buffer>,
20451        position: text::Anchor,
20452        new_name: String,
20453        cx: &mut App,
20454    ) -> Option<Task<Result<ProjectTransaction>>>;
20455
20456    fn pull_diagnostics_for_buffer(
20457        &self,
20458        buffer: Entity<Buffer>,
20459        cx: &mut App,
20460    ) -> Task<anyhow::Result<()>>;
20461}
20462
20463pub trait CompletionProvider {
20464    fn completions(
20465        &self,
20466        excerpt_id: ExcerptId,
20467        buffer: &Entity<Buffer>,
20468        buffer_position: text::Anchor,
20469        trigger: CompletionContext,
20470        window: &mut Window,
20471        cx: &mut Context<Editor>,
20472    ) -> Task<Result<Vec<CompletionResponse>>>;
20473
20474    fn resolve_completions(
20475        &self,
20476        _buffer: Entity<Buffer>,
20477        _completion_indices: Vec<usize>,
20478        _completions: Rc<RefCell<Box<[Completion]>>>,
20479        _cx: &mut Context<Editor>,
20480    ) -> Task<Result<bool>> {
20481        Task::ready(Ok(false))
20482    }
20483
20484    fn apply_additional_edits_for_completion(
20485        &self,
20486        _buffer: Entity<Buffer>,
20487        _completions: Rc<RefCell<Box<[Completion]>>>,
20488        _completion_index: usize,
20489        _push_to_history: bool,
20490        _cx: &mut Context<Editor>,
20491    ) -> Task<Result<Option<language::Transaction>>> {
20492        Task::ready(Ok(None))
20493    }
20494
20495    fn is_completion_trigger(
20496        &self,
20497        buffer: &Entity<Buffer>,
20498        position: language::Anchor,
20499        text: &str,
20500        trigger_in_words: bool,
20501        menu_is_open: bool,
20502        cx: &mut Context<Editor>,
20503    ) -> bool;
20504
20505    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20506
20507    fn sort_completions(&self) -> bool {
20508        true
20509    }
20510
20511    fn filter_completions(&self) -> bool {
20512        true
20513    }
20514}
20515
20516pub trait CodeActionProvider {
20517    fn id(&self) -> Arc<str>;
20518
20519    fn code_actions(
20520        &self,
20521        buffer: &Entity<Buffer>,
20522        range: Range<text::Anchor>,
20523        window: &mut Window,
20524        cx: &mut App,
20525    ) -> Task<Result<Vec<CodeAction>>>;
20526
20527    fn apply_code_action(
20528        &self,
20529        buffer_handle: Entity<Buffer>,
20530        action: CodeAction,
20531        excerpt_id: ExcerptId,
20532        push_to_history: bool,
20533        window: &mut Window,
20534        cx: &mut App,
20535    ) -> Task<Result<ProjectTransaction>>;
20536}
20537
20538impl CodeActionProvider for Entity<Project> {
20539    fn id(&self) -> Arc<str> {
20540        "project".into()
20541    }
20542
20543    fn code_actions(
20544        &self,
20545        buffer: &Entity<Buffer>,
20546        range: Range<text::Anchor>,
20547        _window: &mut Window,
20548        cx: &mut App,
20549    ) -> Task<Result<Vec<CodeAction>>> {
20550        self.update(cx, |project, cx| {
20551            let code_lens = project.code_lens(buffer, range.clone(), cx);
20552            let code_actions = project.code_actions(buffer, range, None, cx);
20553            cx.background_spawn(async move {
20554                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20555                Ok(code_lens
20556                    .context("code lens fetch")?
20557                    .into_iter()
20558                    .chain(code_actions.context("code action fetch")?)
20559                    .collect())
20560            })
20561        })
20562    }
20563
20564    fn apply_code_action(
20565        &self,
20566        buffer_handle: Entity<Buffer>,
20567        action: CodeAction,
20568        _excerpt_id: ExcerptId,
20569        push_to_history: bool,
20570        _window: &mut Window,
20571        cx: &mut App,
20572    ) -> Task<Result<ProjectTransaction>> {
20573        self.update(cx, |project, cx| {
20574            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20575        })
20576    }
20577}
20578
20579fn snippet_completions(
20580    project: &Project,
20581    buffer: &Entity<Buffer>,
20582    buffer_position: text::Anchor,
20583    cx: &mut App,
20584) -> Task<Result<CompletionResponse>> {
20585    let languages = buffer.read(cx).languages_at(buffer_position);
20586    let snippet_store = project.snippets().read(cx);
20587
20588    let scopes: Vec<_> = languages
20589        .iter()
20590        .filter_map(|language| {
20591            let language_name = language.lsp_id();
20592            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20593
20594            if snippets.is_empty() {
20595                None
20596            } else {
20597                Some((language.default_scope(), snippets))
20598            }
20599        })
20600        .collect();
20601
20602    if scopes.is_empty() {
20603        return Task::ready(Ok(CompletionResponse {
20604            completions: vec![],
20605            is_incomplete: false,
20606        }));
20607    }
20608
20609    let snapshot = buffer.read(cx).text_snapshot();
20610    let chars: String = snapshot
20611        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20612        .collect();
20613    let executor = cx.background_executor().clone();
20614
20615    cx.background_spawn(async move {
20616        let mut is_incomplete = false;
20617        let mut completions: Vec<Completion> = Vec::new();
20618        for (scope, snippets) in scopes.into_iter() {
20619            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20620            let mut last_word = chars
20621                .chars()
20622                .take_while(|c| classifier.is_word(*c))
20623                .collect::<String>();
20624            last_word = last_word.chars().rev().collect();
20625
20626            if last_word.is_empty() {
20627                return Ok(CompletionResponse {
20628                    completions: vec![],
20629                    is_incomplete: true,
20630                });
20631            }
20632
20633            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20634            let to_lsp = |point: &text::Anchor| {
20635                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20636                point_to_lsp(end)
20637            };
20638            let lsp_end = to_lsp(&buffer_position);
20639
20640            let candidates = snippets
20641                .iter()
20642                .enumerate()
20643                .flat_map(|(ix, snippet)| {
20644                    snippet
20645                        .prefix
20646                        .iter()
20647                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20648                })
20649                .collect::<Vec<StringMatchCandidate>>();
20650
20651            const MAX_RESULTS: usize = 100;
20652            let mut matches = fuzzy::match_strings(
20653                &candidates,
20654                &last_word,
20655                last_word.chars().any(|c| c.is_uppercase()),
20656                MAX_RESULTS,
20657                &Default::default(),
20658                executor.clone(),
20659            )
20660            .await;
20661
20662            if matches.len() >= MAX_RESULTS {
20663                is_incomplete = true;
20664            }
20665
20666            // Remove all candidates where the query's start does not match the start of any word in the candidate
20667            if let Some(query_start) = last_word.chars().next() {
20668                matches.retain(|string_match| {
20669                    split_words(&string_match.string).any(|word| {
20670                        // Check that the first codepoint of the word as lowercase matches the first
20671                        // codepoint of the query as lowercase
20672                        word.chars()
20673                            .flat_map(|codepoint| codepoint.to_lowercase())
20674                            .zip(query_start.to_lowercase())
20675                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20676                    })
20677                });
20678            }
20679
20680            let matched_strings = matches
20681                .into_iter()
20682                .map(|m| m.string)
20683                .collect::<HashSet<_>>();
20684
20685            completions.extend(snippets.iter().filter_map(|snippet| {
20686                let matching_prefix = snippet
20687                    .prefix
20688                    .iter()
20689                    .find(|prefix| matched_strings.contains(*prefix))?;
20690                let start = as_offset - last_word.len();
20691                let start = snapshot.anchor_before(start);
20692                let range = start..buffer_position;
20693                let lsp_start = to_lsp(&start);
20694                let lsp_range = lsp::Range {
20695                    start: lsp_start,
20696                    end: lsp_end,
20697                };
20698                Some(Completion {
20699                    replace_range: range,
20700                    new_text: snippet.body.clone(),
20701                    source: CompletionSource::Lsp {
20702                        insert_range: None,
20703                        server_id: LanguageServerId(usize::MAX),
20704                        resolved: true,
20705                        lsp_completion: Box::new(lsp::CompletionItem {
20706                            label: snippet.prefix.first().unwrap().clone(),
20707                            kind: Some(CompletionItemKind::SNIPPET),
20708                            label_details: snippet.description.as_ref().map(|description| {
20709                                lsp::CompletionItemLabelDetails {
20710                                    detail: Some(description.clone()),
20711                                    description: None,
20712                                }
20713                            }),
20714                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20715                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20716                                lsp::InsertReplaceEdit {
20717                                    new_text: snippet.body.clone(),
20718                                    insert: lsp_range,
20719                                    replace: lsp_range,
20720                                },
20721                            )),
20722                            filter_text: Some(snippet.body.clone()),
20723                            sort_text: Some(char::MAX.to_string()),
20724                            ..lsp::CompletionItem::default()
20725                        }),
20726                        lsp_defaults: None,
20727                    },
20728                    label: CodeLabel {
20729                        text: matching_prefix.clone(),
20730                        runs: Vec::new(),
20731                        filter_range: 0..matching_prefix.len(),
20732                    },
20733                    icon_path: None,
20734                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20735                        single_line: snippet.name.clone().into(),
20736                        plain_text: snippet
20737                            .description
20738                            .clone()
20739                            .map(|description| description.into()),
20740                    }),
20741                    insert_text_mode: None,
20742                    confirm: None,
20743                })
20744            }))
20745        }
20746
20747        Ok(CompletionResponse {
20748            completions,
20749            is_incomplete,
20750        })
20751    })
20752}
20753
20754impl CompletionProvider for Entity<Project> {
20755    fn completions(
20756        &self,
20757        _excerpt_id: ExcerptId,
20758        buffer: &Entity<Buffer>,
20759        buffer_position: text::Anchor,
20760        options: CompletionContext,
20761        _window: &mut Window,
20762        cx: &mut Context<Editor>,
20763    ) -> Task<Result<Vec<CompletionResponse>>> {
20764        self.update(cx, |project, cx| {
20765            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20766            let project_completions = project.completions(buffer, buffer_position, options, cx);
20767            cx.background_spawn(async move {
20768                let mut responses = project_completions.await?;
20769                let snippets = snippets.await?;
20770                if !snippets.completions.is_empty() {
20771                    responses.push(snippets);
20772                }
20773                Ok(responses)
20774            })
20775        })
20776    }
20777
20778    fn resolve_completions(
20779        &self,
20780        buffer: Entity<Buffer>,
20781        completion_indices: Vec<usize>,
20782        completions: Rc<RefCell<Box<[Completion]>>>,
20783        cx: &mut Context<Editor>,
20784    ) -> Task<Result<bool>> {
20785        self.update(cx, |project, cx| {
20786            project.lsp_store().update(cx, |lsp_store, cx| {
20787                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20788            })
20789        })
20790    }
20791
20792    fn apply_additional_edits_for_completion(
20793        &self,
20794        buffer: Entity<Buffer>,
20795        completions: Rc<RefCell<Box<[Completion]>>>,
20796        completion_index: usize,
20797        push_to_history: bool,
20798        cx: &mut Context<Editor>,
20799    ) -> Task<Result<Option<language::Transaction>>> {
20800        self.update(cx, |project, cx| {
20801            project.lsp_store().update(cx, |lsp_store, cx| {
20802                lsp_store.apply_additional_edits_for_completion(
20803                    buffer,
20804                    completions,
20805                    completion_index,
20806                    push_to_history,
20807                    cx,
20808                )
20809            })
20810        })
20811    }
20812
20813    fn is_completion_trigger(
20814        &self,
20815        buffer: &Entity<Buffer>,
20816        position: language::Anchor,
20817        text: &str,
20818        trigger_in_words: bool,
20819        menu_is_open: bool,
20820        cx: &mut Context<Editor>,
20821    ) -> bool {
20822        let mut chars = text.chars();
20823        let char = if let Some(char) = chars.next() {
20824            char
20825        } else {
20826            return false;
20827        };
20828        if chars.next().is_some() {
20829            return false;
20830        }
20831
20832        let buffer = buffer.read(cx);
20833        let snapshot = buffer.snapshot();
20834        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
20835            return false;
20836        }
20837        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20838        if trigger_in_words && classifier.is_word(char) {
20839            return true;
20840        }
20841
20842        buffer.completion_triggers().contains(text)
20843    }
20844}
20845
20846impl SemanticsProvider for Entity<Project> {
20847    fn hover(
20848        &self,
20849        buffer: &Entity<Buffer>,
20850        position: text::Anchor,
20851        cx: &mut App,
20852    ) -> Option<Task<Vec<project::Hover>>> {
20853        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20854    }
20855
20856    fn document_highlights(
20857        &self,
20858        buffer: &Entity<Buffer>,
20859        position: text::Anchor,
20860        cx: &mut App,
20861    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20862        Some(self.update(cx, |project, cx| {
20863            project.document_highlights(buffer, position, cx)
20864        }))
20865    }
20866
20867    fn definitions(
20868        &self,
20869        buffer: &Entity<Buffer>,
20870        position: text::Anchor,
20871        kind: GotoDefinitionKind,
20872        cx: &mut App,
20873    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20874        Some(self.update(cx, |project, cx| match kind {
20875            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20876            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20877            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20878            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20879        }))
20880    }
20881
20882    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20883        // TODO: make this work for remote projects
20884        self.update(cx, |project, cx| {
20885            if project
20886                .active_debug_session(cx)
20887                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20888            {
20889                return true;
20890            }
20891
20892            buffer.update(cx, |buffer, cx| {
20893                project.any_language_server_supports_inlay_hints(buffer, cx)
20894            })
20895        })
20896    }
20897
20898    fn inline_values(
20899        &self,
20900        buffer_handle: Entity<Buffer>,
20901
20902        range: Range<text::Anchor>,
20903        cx: &mut App,
20904    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20905        self.update(cx, |project, cx| {
20906            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20907
20908            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20909        })
20910    }
20911
20912    fn inlay_hints(
20913        &self,
20914        buffer_handle: Entity<Buffer>,
20915        range: Range<text::Anchor>,
20916        cx: &mut App,
20917    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20918        Some(self.update(cx, |project, cx| {
20919            project.inlay_hints(buffer_handle, range, cx)
20920        }))
20921    }
20922
20923    fn resolve_inlay_hint(
20924        &self,
20925        hint: InlayHint,
20926        buffer_handle: Entity<Buffer>,
20927        server_id: LanguageServerId,
20928        cx: &mut App,
20929    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20930        Some(self.update(cx, |project, cx| {
20931            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20932        }))
20933    }
20934
20935    fn range_for_rename(
20936        &self,
20937        buffer: &Entity<Buffer>,
20938        position: text::Anchor,
20939        cx: &mut App,
20940    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20941        Some(self.update(cx, |project, cx| {
20942            let buffer = buffer.clone();
20943            let task = project.prepare_rename(buffer.clone(), position, cx);
20944            cx.spawn(async move |_, cx| {
20945                Ok(match task.await? {
20946                    PrepareRenameResponse::Success(range) => Some(range),
20947                    PrepareRenameResponse::InvalidPosition => None,
20948                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20949                        // Fallback on using TreeSitter info to determine identifier range
20950                        buffer.read_with(cx, |buffer, _| {
20951                            let snapshot = buffer.snapshot();
20952                            let (range, kind) = snapshot.surrounding_word(position);
20953                            if kind != Some(CharKind::Word) {
20954                                return None;
20955                            }
20956                            Some(
20957                                snapshot.anchor_before(range.start)
20958                                    ..snapshot.anchor_after(range.end),
20959                            )
20960                        })?
20961                    }
20962                })
20963            })
20964        }))
20965    }
20966
20967    fn perform_rename(
20968        &self,
20969        buffer: &Entity<Buffer>,
20970        position: text::Anchor,
20971        new_name: String,
20972        cx: &mut App,
20973    ) -> Option<Task<Result<ProjectTransaction>>> {
20974        Some(self.update(cx, |project, cx| {
20975            project.perform_rename(buffer.clone(), position, new_name, cx)
20976        }))
20977    }
20978
20979    fn pull_diagnostics_for_buffer(
20980        &self,
20981        buffer: Entity<Buffer>,
20982        cx: &mut App,
20983    ) -> Task<anyhow::Result<()>> {
20984        let diagnostics = self.update(cx, |project, cx| {
20985            project
20986                .lsp_store()
20987                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
20988        });
20989        let project = self.clone();
20990        cx.spawn(async move |cx| {
20991            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
20992            project.update(cx, |project, cx| {
20993                project.lsp_store().update(cx, |lsp_store, cx| {
20994                    for diagnostics_set in diagnostics {
20995                        let LspPullDiagnostics::Response {
20996                            server_id,
20997                            uri,
20998                            diagnostics,
20999                        } = diagnostics_set
21000                        else {
21001                            continue;
21002                        };
21003
21004                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21005                        let disk_based_sources = adapter
21006                            .as_ref()
21007                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21008                            .unwrap_or(&[]);
21009                        match diagnostics {
21010                            PulledDiagnostics::Unchanged { result_id } => {
21011                                lsp_store
21012                                    .merge_diagnostics(
21013                                        server_id,
21014                                        lsp::PublishDiagnosticsParams {
21015                                            uri: uri.clone(),
21016                                            diagnostics: Vec::new(),
21017                                            version: None,
21018                                        },
21019                                        Some(result_id),
21020                                        DiagnosticSourceKind::Pulled,
21021                                        disk_based_sources,
21022                                        |_, _| true,
21023                                        cx,
21024                                    )
21025                                    .log_err();
21026                            }
21027                            PulledDiagnostics::Changed {
21028                                diagnostics,
21029                                result_id,
21030                            } => {
21031                                lsp_store
21032                                    .merge_diagnostics(
21033                                        server_id,
21034                                        lsp::PublishDiagnosticsParams {
21035                                            uri: uri.clone(),
21036                                            diagnostics,
21037                                            version: None,
21038                                        },
21039                                        result_id,
21040                                        DiagnosticSourceKind::Pulled,
21041                                        disk_based_sources,
21042                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21043                                            DiagnosticSourceKind::Pulled => false,
21044                                            DiagnosticSourceKind::Other
21045                                            | DiagnosticSourceKind::Pushed => true,
21046                                        },
21047                                        cx,
21048                                    )
21049                                    .log_err();
21050                            }
21051                        }
21052                    }
21053                })
21054            })
21055        })
21056    }
21057}
21058
21059fn inlay_hint_settings(
21060    location: Anchor,
21061    snapshot: &MultiBufferSnapshot,
21062    cx: &mut Context<Editor>,
21063) -> InlayHintSettings {
21064    let file = snapshot.file_at(location);
21065    let language = snapshot.language_at(location).map(|l| l.name());
21066    language_settings(language, file, cx).inlay_hints
21067}
21068
21069fn consume_contiguous_rows(
21070    contiguous_row_selections: &mut Vec<Selection<Point>>,
21071    selection: &Selection<Point>,
21072    display_map: &DisplaySnapshot,
21073    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21074) -> (MultiBufferRow, MultiBufferRow) {
21075    contiguous_row_selections.push(selection.clone());
21076    let start_row = MultiBufferRow(selection.start.row);
21077    let mut end_row = ending_row(selection, display_map);
21078
21079    while let Some(next_selection) = selections.peek() {
21080        if next_selection.start.row <= end_row.0 {
21081            end_row = ending_row(next_selection, display_map);
21082            contiguous_row_selections.push(selections.next().unwrap().clone());
21083        } else {
21084            break;
21085        }
21086    }
21087    (start_row, end_row)
21088}
21089
21090fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21091    if next_selection.end.column > 0 || next_selection.is_empty() {
21092        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21093    } else {
21094        MultiBufferRow(next_selection.end.row)
21095    }
21096}
21097
21098impl EditorSnapshot {
21099    pub fn remote_selections_in_range<'a>(
21100        &'a self,
21101        range: &'a Range<Anchor>,
21102        collaboration_hub: &dyn CollaborationHub,
21103        cx: &'a App,
21104    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21105        let participant_names = collaboration_hub.user_names(cx);
21106        let participant_indices = collaboration_hub.user_participant_indices(cx);
21107        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21108        let collaborators_by_replica_id = collaborators_by_peer_id
21109            .values()
21110            .map(|collaborator| (collaborator.replica_id, collaborator))
21111            .collect::<HashMap<_, _>>();
21112        self.buffer_snapshot
21113            .selections_in_range(range, false)
21114            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21115                if replica_id == AGENT_REPLICA_ID {
21116                    Some(RemoteSelection {
21117                        replica_id,
21118                        selection,
21119                        cursor_shape,
21120                        line_mode,
21121                        collaborator_id: CollaboratorId::Agent,
21122                        user_name: Some("Agent".into()),
21123                        color: cx.theme().players().agent(),
21124                    })
21125                } else {
21126                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21127                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21128                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21129                    Some(RemoteSelection {
21130                        replica_id,
21131                        selection,
21132                        cursor_shape,
21133                        line_mode,
21134                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21135                        user_name,
21136                        color: if let Some(index) = participant_index {
21137                            cx.theme().players().color_for_participant(index.0)
21138                        } else {
21139                            cx.theme().players().absent()
21140                        },
21141                    })
21142                }
21143            })
21144    }
21145
21146    pub fn hunks_for_ranges(
21147        &self,
21148        ranges: impl IntoIterator<Item = Range<Point>>,
21149    ) -> Vec<MultiBufferDiffHunk> {
21150        let mut hunks = Vec::new();
21151        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21152            HashMap::default();
21153        for query_range in ranges {
21154            let query_rows =
21155                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21156            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21157                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21158            ) {
21159                // Include deleted hunks that are adjacent to the query range, because
21160                // otherwise they would be missed.
21161                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21162                if hunk.status().is_deleted() {
21163                    intersects_range |= hunk.row_range.start == query_rows.end;
21164                    intersects_range |= hunk.row_range.end == query_rows.start;
21165                }
21166                if intersects_range {
21167                    if !processed_buffer_rows
21168                        .entry(hunk.buffer_id)
21169                        .or_default()
21170                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21171                    {
21172                        continue;
21173                    }
21174                    hunks.push(hunk);
21175                }
21176            }
21177        }
21178
21179        hunks
21180    }
21181
21182    fn display_diff_hunks_for_rows<'a>(
21183        &'a self,
21184        display_rows: Range<DisplayRow>,
21185        folded_buffers: &'a HashSet<BufferId>,
21186    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21187        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21188        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21189
21190        self.buffer_snapshot
21191            .diff_hunks_in_range(buffer_start..buffer_end)
21192            .filter_map(|hunk| {
21193                if folded_buffers.contains(&hunk.buffer_id) {
21194                    return None;
21195                }
21196
21197                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21198                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21199
21200                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21201                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21202
21203                let display_hunk = if hunk_display_start.column() != 0 {
21204                    DisplayDiffHunk::Folded {
21205                        display_row: hunk_display_start.row(),
21206                    }
21207                } else {
21208                    let mut end_row = hunk_display_end.row();
21209                    if hunk_display_end.column() > 0 {
21210                        end_row.0 += 1;
21211                    }
21212                    let is_created_file = hunk.is_created_file();
21213                    DisplayDiffHunk::Unfolded {
21214                        status: hunk.status(),
21215                        diff_base_byte_range: hunk.diff_base_byte_range,
21216                        display_row_range: hunk_display_start.row()..end_row,
21217                        multi_buffer_range: Anchor::range_in_buffer(
21218                            hunk.excerpt_id,
21219                            hunk.buffer_id,
21220                            hunk.buffer_range,
21221                        ),
21222                        is_created_file,
21223                    }
21224                };
21225
21226                Some(display_hunk)
21227            })
21228    }
21229
21230    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21231        self.display_snapshot.buffer_snapshot.language_at(position)
21232    }
21233
21234    pub fn is_focused(&self) -> bool {
21235        self.is_focused
21236    }
21237
21238    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21239        self.placeholder_text.as_ref()
21240    }
21241
21242    pub fn scroll_position(&self) -> gpui::Point<f32> {
21243        self.scroll_anchor.scroll_position(&self.display_snapshot)
21244    }
21245
21246    fn gutter_dimensions(
21247        &self,
21248        font_id: FontId,
21249        font_size: Pixels,
21250        max_line_number_width: Pixels,
21251        cx: &App,
21252    ) -> Option<GutterDimensions> {
21253        if !self.show_gutter {
21254            return None;
21255        }
21256
21257        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21258        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21259
21260        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21261            matches!(
21262                ProjectSettings::get_global(cx).git.git_gutter,
21263                Some(GitGutterSetting::TrackedFiles)
21264            )
21265        });
21266        let gutter_settings = EditorSettings::get_global(cx).gutter;
21267        let show_line_numbers = self
21268            .show_line_numbers
21269            .unwrap_or(gutter_settings.line_numbers);
21270        let line_gutter_width = if show_line_numbers {
21271            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21272            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21273            max_line_number_width.max(min_width_for_number_on_gutter)
21274        } else {
21275            0.0.into()
21276        };
21277
21278        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21279        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21280
21281        let git_blame_entries_width =
21282            self.git_blame_gutter_max_author_length
21283                .map(|max_author_length| {
21284                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21285                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21286
21287                    /// The number of characters to dedicate to gaps and margins.
21288                    const SPACING_WIDTH: usize = 4;
21289
21290                    let max_char_count = max_author_length.min(renderer.max_author_length())
21291                        + ::git::SHORT_SHA_LENGTH
21292                        + MAX_RELATIVE_TIMESTAMP.len()
21293                        + SPACING_WIDTH;
21294
21295                    em_advance * max_char_count
21296                });
21297
21298        let is_singleton = self.buffer_snapshot.is_singleton();
21299
21300        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21301        left_padding += if !is_singleton {
21302            em_width * 4.0
21303        } else if show_runnables || show_breakpoints {
21304            em_width * 3.0
21305        } else if show_git_gutter && show_line_numbers {
21306            em_width * 2.0
21307        } else if show_git_gutter || show_line_numbers {
21308            em_width
21309        } else {
21310            px(0.)
21311        };
21312
21313        let shows_folds = is_singleton && gutter_settings.folds;
21314
21315        let right_padding = if shows_folds && show_line_numbers {
21316            em_width * 4.0
21317        } else if shows_folds || (!is_singleton && show_line_numbers) {
21318            em_width * 3.0
21319        } else if show_line_numbers {
21320            em_width
21321        } else {
21322            px(0.)
21323        };
21324
21325        Some(GutterDimensions {
21326            left_padding,
21327            right_padding,
21328            width: line_gutter_width + left_padding + right_padding,
21329            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21330            git_blame_entries_width,
21331        })
21332    }
21333
21334    pub fn render_crease_toggle(
21335        &self,
21336        buffer_row: MultiBufferRow,
21337        row_contains_cursor: bool,
21338        editor: Entity<Editor>,
21339        window: &mut Window,
21340        cx: &mut App,
21341    ) -> Option<AnyElement> {
21342        let folded = self.is_line_folded(buffer_row);
21343        let mut is_foldable = false;
21344
21345        if let Some(crease) = self
21346            .crease_snapshot
21347            .query_row(buffer_row, &self.buffer_snapshot)
21348        {
21349            is_foldable = true;
21350            match crease {
21351                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21352                    if let Some(render_toggle) = render_toggle {
21353                        let toggle_callback =
21354                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21355                                if folded {
21356                                    editor.update(cx, |editor, cx| {
21357                                        editor.fold_at(buffer_row, window, cx)
21358                                    });
21359                                } else {
21360                                    editor.update(cx, |editor, cx| {
21361                                        editor.unfold_at(buffer_row, window, cx)
21362                                    });
21363                                }
21364                            });
21365                        return Some((render_toggle)(
21366                            buffer_row,
21367                            folded,
21368                            toggle_callback,
21369                            window,
21370                            cx,
21371                        ));
21372                    }
21373                }
21374            }
21375        }
21376
21377        is_foldable |= self.starts_indent(buffer_row);
21378
21379        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21380            Some(
21381                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21382                    .toggle_state(folded)
21383                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21384                        if folded {
21385                            this.unfold_at(buffer_row, window, cx);
21386                        } else {
21387                            this.fold_at(buffer_row, window, cx);
21388                        }
21389                    }))
21390                    .into_any_element(),
21391            )
21392        } else {
21393            None
21394        }
21395    }
21396
21397    pub fn render_crease_trailer(
21398        &self,
21399        buffer_row: MultiBufferRow,
21400        window: &mut Window,
21401        cx: &mut App,
21402    ) -> Option<AnyElement> {
21403        let folded = self.is_line_folded(buffer_row);
21404        if let Crease::Inline { render_trailer, .. } = self
21405            .crease_snapshot
21406            .query_row(buffer_row, &self.buffer_snapshot)?
21407        {
21408            let render_trailer = render_trailer.as_ref()?;
21409            Some(render_trailer(buffer_row, folded, window, cx))
21410        } else {
21411            None
21412        }
21413    }
21414}
21415
21416impl Deref for EditorSnapshot {
21417    type Target = DisplaySnapshot;
21418
21419    fn deref(&self) -> &Self::Target {
21420        &self.display_snapshot
21421    }
21422}
21423
21424#[derive(Clone, Debug, PartialEq, Eq)]
21425pub enum EditorEvent {
21426    InputIgnored {
21427        text: Arc<str>,
21428    },
21429    InputHandled {
21430        utf16_range_to_replace: Option<Range<isize>>,
21431        text: Arc<str>,
21432    },
21433    ExcerptsAdded {
21434        buffer: Entity<Buffer>,
21435        predecessor: ExcerptId,
21436        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21437    },
21438    ExcerptsRemoved {
21439        ids: Vec<ExcerptId>,
21440        removed_buffer_ids: Vec<BufferId>,
21441    },
21442    BufferFoldToggled {
21443        ids: Vec<ExcerptId>,
21444        folded: bool,
21445    },
21446    ExcerptsEdited {
21447        ids: Vec<ExcerptId>,
21448    },
21449    ExcerptsExpanded {
21450        ids: Vec<ExcerptId>,
21451    },
21452    BufferEdited,
21453    Edited {
21454        transaction_id: clock::Lamport,
21455    },
21456    Reparsed(BufferId),
21457    Focused,
21458    FocusedIn,
21459    Blurred,
21460    DirtyChanged,
21461    Saved,
21462    TitleChanged,
21463    DiffBaseChanged,
21464    SelectionsChanged {
21465        local: bool,
21466    },
21467    ScrollPositionChanged {
21468        local: bool,
21469        autoscroll: bool,
21470    },
21471    Closed,
21472    TransactionUndone {
21473        transaction_id: clock::Lamport,
21474    },
21475    TransactionBegun {
21476        transaction_id: clock::Lamport,
21477    },
21478    Reloaded,
21479    CursorShapeChanged,
21480    PushedToNavHistory {
21481        anchor: Anchor,
21482        is_deactivate: bool,
21483    },
21484}
21485
21486impl EventEmitter<EditorEvent> for Editor {}
21487
21488impl Focusable for Editor {
21489    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21490        self.focus_handle.clone()
21491    }
21492}
21493
21494impl Render for Editor {
21495    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21496        let settings = ThemeSettings::get_global(cx);
21497
21498        let mut text_style = match self.mode {
21499            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21500                color: cx.theme().colors().editor_foreground,
21501                font_family: settings.ui_font.family.clone(),
21502                font_features: settings.ui_font.features.clone(),
21503                font_fallbacks: settings.ui_font.fallbacks.clone(),
21504                font_size: rems(0.875).into(),
21505                font_weight: settings.ui_font.weight,
21506                line_height: relative(settings.buffer_line_height.value()),
21507                ..Default::default()
21508            },
21509            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21510                color: cx.theme().colors().editor_foreground,
21511                font_family: settings.buffer_font.family.clone(),
21512                font_features: settings.buffer_font.features.clone(),
21513                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21514                font_size: settings.buffer_font_size(cx).into(),
21515                font_weight: settings.buffer_font.weight,
21516                line_height: relative(settings.buffer_line_height.value()),
21517                ..Default::default()
21518            },
21519        };
21520        if let Some(text_style_refinement) = &self.text_style_refinement {
21521            text_style.refine(text_style_refinement)
21522        }
21523
21524        let background = match self.mode {
21525            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21526            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21527            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21528            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21529        };
21530
21531        EditorElement::new(
21532            &cx.entity(),
21533            EditorStyle {
21534                background,
21535                local_player: cx.theme().players().local(),
21536                text: text_style,
21537                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21538                syntax: cx.theme().syntax().clone(),
21539                status: cx.theme().status().clone(),
21540                inlay_hints_style: make_inlay_hints_style(cx),
21541                inline_completion_styles: make_suggestion_styles(cx),
21542                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21543                show_underlines: !self.mode.is_minimap(),
21544            },
21545        )
21546    }
21547}
21548
21549impl EntityInputHandler for Editor {
21550    fn text_for_range(
21551        &mut self,
21552        range_utf16: Range<usize>,
21553        adjusted_range: &mut Option<Range<usize>>,
21554        _: &mut Window,
21555        cx: &mut Context<Self>,
21556    ) -> Option<String> {
21557        let snapshot = self.buffer.read(cx).read(cx);
21558        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21559        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21560        if (start.0..end.0) != range_utf16 {
21561            adjusted_range.replace(start.0..end.0);
21562        }
21563        Some(snapshot.text_for_range(start..end).collect())
21564    }
21565
21566    fn selected_text_range(
21567        &mut self,
21568        ignore_disabled_input: bool,
21569        _: &mut Window,
21570        cx: &mut Context<Self>,
21571    ) -> Option<UTF16Selection> {
21572        // Prevent the IME menu from appearing when holding down an alphabetic key
21573        // while input is disabled.
21574        if !ignore_disabled_input && !self.input_enabled {
21575            return None;
21576        }
21577
21578        let selection = self.selections.newest::<OffsetUtf16>(cx);
21579        let range = selection.range();
21580
21581        Some(UTF16Selection {
21582            range: range.start.0..range.end.0,
21583            reversed: selection.reversed,
21584        })
21585    }
21586
21587    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21588        let snapshot = self.buffer.read(cx).read(cx);
21589        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21590        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21591    }
21592
21593    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21594        self.clear_highlights::<InputComposition>(cx);
21595        self.ime_transaction.take();
21596    }
21597
21598    fn replace_text_in_range(
21599        &mut self,
21600        range_utf16: Option<Range<usize>>,
21601        text: &str,
21602        window: &mut Window,
21603        cx: &mut Context<Self>,
21604    ) {
21605        if !self.input_enabled {
21606            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21607            return;
21608        }
21609
21610        self.transact(window, cx, |this, window, cx| {
21611            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21612                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21613                Some(this.selection_replacement_ranges(range_utf16, cx))
21614            } else {
21615                this.marked_text_ranges(cx)
21616            };
21617
21618            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21619                let newest_selection_id = this.selections.newest_anchor().id;
21620                this.selections
21621                    .all::<OffsetUtf16>(cx)
21622                    .iter()
21623                    .zip(ranges_to_replace.iter())
21624                    .find_map(|(selection, range)| {
21625                        if selection.id == newest_selection_id {
21626                            Some(
21627                                (range.start.0 as isize - selection.head().0 as isize)
21628                                    ..(range.end.0 as isize - selection.head().0 as isize),
21629                            )
21630                        } else {
21631                            None
21632                        }
21633                    })
21634            });
21635
21636            cx.emit(EditorEvent::InputHandled {
21637                utf16_range_to_replace: range_to_replace,
21638                text: text.into(),
21639            });
21640
21641            if let Some(new_selected_ranges) = new_selected_ranges {
21642                this.change_selections(None, window, cx, |selections| {
21643                    selections.select_ranges(new_selected_ranges)
21644                });
21645                this.backspace(&Default::default(), window, cx);
21646            }
21647
21648            this.handle_input(text, window, cx);
21649        });
21650
21651        if let Some(transaction) = self.ime_transaction {
21652            self.buffer.update(cx, |buffer, cx| {
21653                buffer.group_until_transaction(transaction, cx);
21654            });
21655        }
21656
21657        self.unmark_text(window, cx);
21658    }
21659
21660    fn replace_and_mark_text_in_range(
21661        &mut self,
21662        range_utf16: Option<Range<usize>>,
21663        text: &str,
21664        new_selected_range_utf16: Option<Range<usize>>,
21665        window: &mut Window,
21666        cx: &mut Context<Self>,
21667    ) {
21668        if !self.input_enabled {
21669            return;
21670        }
21671
21672        let transaction = self.transact(window, cx, |this, window, cx| {
21673            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21674                let snapshot = this.buffer.read(cx).read(cx);
21675                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21676                    for marked_range in &mut marked_ranges {
21677                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21678                        marked_range.start.0 += relative_range_utf16.start;
21679                        marked_range.start =
21680                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21681                        marked_range.end =
21682                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21683                    }
21684                }
21685                Some(marked_ranges)
21686            } else if let Some(range_utf16) = range_utf16 {
21687                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21688                Some(this.selection_replacement_ranges(range_utf16, cx))
21689            } else {
21690                None
21691            };
21692
21693            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21694                let newest_selection_id = this.selections.newest_anchor().id;
21695                this.selections
21696                    .all::<OffsetUtf16>(cx)
21697                    .iter()
21698                    .zip(ranges_to_replace.iter())
21699                    .find_map(|(selection, range)| {
21700                        if selection.id == newest_selection_id {
21701                            Some(
21702                                (range.start.0 as isize - selection.head().0 as isize)
21703                                    ..(range.end.0 as isize - selection.head().0 as isize),
21704                            )
21705                        } else {
21706                            None
21707                        }
21708                    })
21709            });
21710
21711            cx.emit(EditorEvent::InputHandled {
21712                utf16_range_to_replace: range_to_replace,
21713                text: text.into(),
21714            });
21715
21716            if let Some(ranges) = ranges_to_replace {
21717                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21718            }
21719
21720            let marked_ranges = {
21721                let snapshot = this.buffer.read(cx).read(cx);
21722                this.selections
21723                    .disjoint_anchors()
21724                    .iter()
21725                    .map(|selection| {
21726                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21727                    })
21728                    .collect::<Vec<_>>()
21729            };
21730
21731            if text.is_empty() {
21732                this.unmark_text(window, cx);
21733            } else {
21734                this.highlight_text::<InputComposition>(
21735                    marked_ranges.clone(),
21736                    HighlightStyle {
21737                        underline: Some(UnderlineStyle {
21738                            thickness: px(1.),
21739                            color: None,
21740                            wavy: false,
21741                        }),
21742                        ..Default::default()
21743                    },
21744                    cx,
21745                );
21746            }
21747
21748            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21749            let use_autoclose = this.use_autoclose;
21750            let use_auto_surround = this.use_auto_surround;
21751            this.set_use_autoclose(false);
21752            this.set_use_auto_surround(false);
21753            this.handle_input(text, window, cx);
21754            this.set_use_autoclose(use_autoclose);
21755            this.set_use_auto_surround(use_auto_surround);
21756
21757            if let Some(new_selected_range) = new_selected_range_utf16 {
21758                let snapshot = this.buffer.read(cx).read(cx);
21759                let new_selected_ranges = marked_ranges
21760                    .into_iter()
21761                    .map(|marked_range| {
21762                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21763                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21764                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21765                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21766                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21767                    })
21768                    .collect::<Vec<_>>();
21769
21770                drop(snapshot);
21771                this.change_selections(None, window, cx, |selections| {
21772                    selections.select_ranges(new_selected_ranges)
21773                });
21774            }
21775        });
21776
21777        self.ime_transaction = self.ime_transaction.or(transaction);
21778        if let Some(transaction) = self.ime_transaction {
21779            self.buffer.update(cx, |buffer, cx| {
21780                buffer.group_until_transaction(transaction, cx);
21781            });
21782        }
21783
21784        if self.text_highlights::<InputComposition>(cx).is_none() {
21785            self.ime_transaction.take();
21786        }
21787    }
21788
21789    fn bounds_for_range(
21790        &mut self,
21791        range_utf16: Range<usize>,
21792        element_bounds: gpui::Bounds<Pixels>,
21793        window: &mut Window,
21794        cx: &mut Context<Self>,
21795    ) -> Option<gpui::Bounds<Pixels>> {
21796        let text_layout_details = self.text_layout_details(window);
21797        let gpui::Size {
21798            width: em_width,
21799            height: line_height,
21800        } = self.character_size(window);
21801
21802        let snapshot = self.snapshot(window, cx);
21803        let scroll_position = snapshot.scroll_position();
21804        let scroll_left = scroll_position.x * em_width;
21805
21806        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21807        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21808            + self.gutter_dimensions.width
21809            + self.gutter_dimensions.margin;
21810        let y = line_height * (start.row().as_f32() - scroll_position.y);
21811
21812        Some(Bounds {
21813            origin: element_bounds.origin + point(x, y),
21814            size: size(em_width, line_height),
21815        })
21816    }
21817
21818    fn character_index_for_point(
21819        &mut self,
21820        point: gpui::Point<Pixels>,
21821        _window: &mut Window,
21822        _cx: &mut Context<Self>,
21823    ) -> Option<usize> {
21824        let position_map = self.last_position_map.as_ref()?;
21825        if !position_map.text_hitbox.contains(&point) {
21826            return None;
21827        }
21828        let display_point = position_map.point_for_position(point).previous_valid;
21829        let anchor = position_map
21830            .snapshot
21831            .display_point_to_anchor(display_point, Bias::Left);
21832        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21833        Some(utf16_offset.0)
21834    }
21835}
21836
21837trait SelectionExt {
21838    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21839    fn spanned_rows(
21840        &self,
21841        include_end_if_at_line_start: bool,
21842        map: &DisplaySnapshot,
21843    ) -> Range<MultiBufferRow>;
21844}
21845
21846impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21847    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21848        let start = self
21849            .start
21850            .to_point(&map.buffer_snapshot)
21851            .to_display_point(map);
21852        let end = self
21853            .end
21854            .to_point(&map.buffer_snapshot)
21855            .to_display_point(map);
21856        if self.reversed {
21857            end..start
21858        } else {
21859            start..end
21860        }
21861    }
21862
21863    fn spanned_rows(
21864        &self,
21865        include_end_if_at_line_start: bool,
21866        map: &DisplaySnapshot,
21867    ) -> Range<MultiBufferRow> {
21868        let start = self.start.to_point(&map.buffer_snapshot);
21869        let mut end = self.end.to_point(&map.buffer_snapshot);
21870        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21871            end.row -= 1;
21872        }
21873
21874        let buffer_start = map.prev_line_boundary(start).0;
21875        let buffer_end = map.next_line_boundary(end).0;
21876        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21877    }
21878}
21879
21880impl<T: InvalidationRegion> InvalidationStack<T> {
21881    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21882    where
21883        S: Clone + ToOffset,
21884    {
21885        while let Some(region) = self.last() {
21886            let all_selections_inside_invalidation_ranges =
21887                if selections.len() == region.ranges().len() {
21888                    selections
21889                        .iter()
21890                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21891                        .all(|(selection, invalidation_range)| {
21892                            let head = selection.head().to_offset(buffer);
21893                            invalidation_range.start <= head && invalidation_range.end >= head
21894                        })
21895                } else {
21896                    false
21897                };
21898
21899            if all_selections_inside_invalidation_ranges {
21900                break;
21901            } else {
21902                self.pop();
21903            }
21904        }
21905    }
21906}
21907
21908impl<T> Default for InvalidationStack<T> {
21909    fn default() -> Self {
21910        Self(Default::default())
21911    }
21912}
21913
21914impl<T> Deref for InvalidationStack<T> {
21915    type Target = Vec<T>;
21916
21917    fn deref(&self) -> &Self::Target {
21918        &self.0
21919    }
21920}
21921
21922impl<T> DerefMut for InvalidationStack<T> {
21923    fn deref_mut(&mut self) -> &mut Self::Target {
21924        &mut self.0
21925    }
21926}
21927
21928impl InvalidationRegion for SnippetState {
21929    fn ranges(&self) -> &[Range<Anchor>] {
21930        &self.ranges[self.active_index]
21931    }
21932}
21933
21934fn inline_completion_edit_text(
21935    current_snapshot: &BufferSnapshot,
21936    edits: &[(Range<Anchor>, String)],
21937    edit_preview: &EditPreview,
21938    include_deletions: bool,
21939    cx: &App,
21940) -> HighlightedText {
21941    let edits = edits
21942        .iter()
21943        .map(|(anchor, text)| {
21944            (
21945                anchor.start.text_anchor..anchor.end.text_anchor,
21946                text.clone(),
21947            )
21948        })
21949        .collect::<Vec<_>>();
21950
21951    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21952}
21953
21954pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21955    match severity {
21956        lsp::DiagnosticSeverity::ERROR => colors.error,
21957        lsp::DiagnosticSeverity::WARNING => colors.warning,
21958        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21959        lsp::DiagnosticSeverity::HINT => colors.info,
21960        _ => colors.ignored,
21961    }
21962}
21963
21964pub fn styled_runs_for_code_label<'a>(
21965    label: &'a CodeLabel,
21966    syntax_theme: &'a theme::SyntaxTheme,
21967) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21968    let fade_out = HighlightStyle {
21969        fade_out: Some(0.35),
21970        ..Default::default()
21971    };
21972
21973    let mut prev_end = label.filter_range.end;
21974    label
21975        .runs
21976        .iter()
21977        .enumerate()
21978        .flat_map(move |(ix, (range, highlight_id))| {
21979            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21980                style
21981            } else {
21982                return Default::default();
21983            };
21984            let mut muted_style = style;
21985            muted_style.highlight(fade_out);
21986
21987            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21988            if range.start >= label.filter_range.end {
21989                if range.start > prev_end {
21990                    runs.push((prev_end..range.start, fade_out));
21991                }
21992                runs.push((range.clone(), muted_style));
21993            } else if range.end <= label.filter_range.end {
21994                runs.push((range.clone(), style));
21995            } else {
21996                runs.push((range.start..label.filter_range.end, style));
21997                runs.push((label.filter_range.end..range.end, muted_style));
21998            }
21999            prev_end = cmp::max(prev_end, range.end);
22000
22001            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22002                runs.push((prev_end..label.text.len(), fade_out));
22003            }
22004
22005            runs
22006        })
22007}
22008
22009pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22010    let mut prev_index = 0;
22011    let mut prev_codepoint: Option<char> = None;
22012    text.char_indices()
22013        .chain([(text.len(), '\0')])
22014        .filter_map(move |(index, codepoint)| {
22015            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22016            let is_boundary = index == text.len()
22017                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22018                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22019            if is_boundary {
22020                let chunk = &text[prev_index..index];
22021                prev_index = index;
22022                Some(chunk)
22023            } else {
22024                None
22025            }
22026        })
22027}
22028
22029pub trait RangeToAnchorExt: Sized {
22030    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22031
22032    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22033        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22034        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22035    }
22036}
22037
22038impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22039    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22040        let start_offset = self.start.to_offset(snapshot);
22041        let end_offset = self.end.to_offset(snapshot);
22042        if start_offset == end_offset {
22043            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22044        } else {
22045            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22046        }
22047    }
22048}
22049
22050pub trait RowExt {
22051    fn as_f32(&self) -> f32;
22052
22053    fn next_row(&self) -> Self;
22054
22055    fn previous_row(&self) -> Self;
22056
22057    fn minus(&self, other: Self) -> u32;
22058}
22059
22060impl RowExt for DisplayRow {
22061    fn as_f32(&self) -> f32 {
22062        self.0 as f32
22063    }
22064
22065    fn next_row(&self) -> Self {
22066        Self(self.0 + 1)
22067    }
22068
22069    fn previous_row(&self) -> Self {
22070        Self(self.0.saturating_sub(1))
22071    }
22072
22073    fn minus(&self, other: Self) -> u32 {
22074        self.0 - other.0
22075    }
22076}
22077
22078impl RowExt for MultiBufferRow {
22079    fn as_f32(&self) -> f32 {
22080        self.0 as f32
22081    }
22082
22083    fn next_row(&self) -> Self {
22084        Self(self.0 + 1)
22085    }
22086
22087    fn previous_row(&self) -> Self {
22088        Self(self.0.saturating_sub(1))
22089    }
22090
22091    fn minus(&self, other: Self) -> u32 {
22092        self.0 - other.0
22093    }
22094}
22095
22096trait RowRangeExt {
22097    type Row;
22098
22099    fn len(&self) -> usize;
22100
22101    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22102}
22103
22104impl RowRangeExt for Range<MultiBufferRow> {
22105    type Row = MultiBufferRow;
22106
22107    fn len(&self) -> usize {
22108        (self.end.0 - self.start.0) as usize
22109    }
22110
22111    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22112        (self.start.0..self.end.0).map(MultiBufferRow)
22113    }
22114}
22115
22116impl RowRangeExt for Range<DisplayRow> {
22117    type Row = DisplayRow;
22118
22119    fn len(&self) -> usize {
22120        (self.end.0 - self.start.0) as usize
22121    }
22122
22123    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22124        (self.start.0..self.end.0).map(DisplayRow)
22125    }
22126}
22127
22128/// If select range has more than one line, we
22129/// just point the cursor to range.start.
22130fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22131    if range.start.row == range.end.row {
22132        range
22133    } else {
22134        range.start..range.start
22135    }
22136}
22137pub struct KillRing(ClipboardItem);
22138impl Global for KillRing {}
22139
22140const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22141
22142enum BreakpointPromptEditAction {
22143    Log,
22144    Condition,
22145    HitCondition,
22146}
22147
22148struct BreakpointPromptEditor {
22149    pub(crate) prompt: Entity<Editor>,
22150    editor: WeakEntity<Editor>,
22151    breakpoint_anchor: Anchor,
22152    breakpoint: Breakpoint,
22153    edit_action: BreakpointPromptEditAction,
22154    block_ids: HashSet<CustomBlockId>,
22155    editor_margins: Arc<Mutex<EditorMargins>>,
22156    _subscriptions: Vec<Subscription>,
22157}
22158
22159impl BreakpointPromptEditor {
22160    const MAX_LINES: u8 = 4;
22161
22162    fn new(
22163        editor: WeakEntity<Editor>,
22164        breakpoint_anchor: Anchor,
22165        breakpoint: Breakpoint,
22166        edit_action: BreakpointPromptEditAction,
22167        window: &mut Window,
22168        cx: &mut Context<Self>,
22169    ) -> Self {
22170        let base_text = match edit_action {
22171            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22172            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22173            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22174        }
22175        .map(|msg| msg.to_string())
22176        .unwrap_or_default();
22177
22178        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22179        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22180
22181        let prompt = cx.new(|cx| {
22182            let mut prompt = Editor::new(
22183                EditorMode::AutoHeight {
22184                    max_lines: Self::MAX_LINES as usize,
22185                },
22186                buffer,
22187                None,
22188                window,
22189                cx,
22190            );
22191            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22192            prompt.set_show_cursor_when_unfocused(false, cx);
22193            prompt.set_placeholder_text(
22194                match edit_action {
22195                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22196                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22197                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22198                },
22199                cx,
22200            );
22201
22202            prompt
22203        });
22204
22205        Self {
22206            prompt,
22207            editor,
22208            breakpoint_anchor,
22209            breakpoint,
22210            edit_action,
22211            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22212            block_ids: Default::default(),
22213            _subscriptions: vec![],
22214        }
22215    }
22216
22217    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22218        self.block_ids.extend(block_ids)
22219    }
22220
22221    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22222        if let Some(editor) = self.editor.upgrade() {
22223            let message = self
22224                .prompt
22225                .read(cx)
22226                .buffer
22227                .read(cx)
22228                .as_singleton()
22229                .expect("A multi buffer in breakpoint prompt isn't possible")
22230                .read(cx)
22231                .as_rope()
22232                .to_string();
22233
22234            editor.update(cx, |editor, cx| {
22235                editor.edit_breakpoint_at_anchor(
22236                    self.breakpoint_anchor,
22237                    self.breakpoint.clone(),
22238                    match self.edit_action {
22239                        BreakpointPromptEditAction::Log => {
22240                            BreakpointEditAction::EditLogMessage(message.into())
22241                        }
22242                        BreakpointPromptEditAction::Condition => {
22243                            BreakpointEditAction::EditCondition(message.into())
22244                        }
22245                        BreakpointPromptEditAction::HitCondition => {
22246                            BreakpointEditAction::EditHitCondition(message.into())
22247                        }
22248                    },
22249                    cx,
22250                );
22251
22252                editor.remove_blocks(self.block_ids.clone(), None, cx);
22253                cx.focus_self(window);
22254            });
22255        }
22256    }
22257
22258    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22259        self.editor
22260            .update(cx, |editor, cx| {
22261                editor.remove_blocks(self.block_ids.clone(), None, cx);
22262                window.focus(&editor.focus_handle);
22263            })
22264            .log_err();
22265    }
22266
22267    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22268        let settings = ThemeSettings::get_global(cx);
22269        let text_style = TextStyle {
22270            color: if self.prompt.read(cx).read_only(cx) {
22271                cx.theme().colors().text_disabled
22272            } else {
22273                cx.theme().colors().text
22274            },
22275            font_family: settings.buffer_font.family.clone(),
22276            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22277            font_size: settings.buffer_font_size(cx).into(),
22278            font_weight: settings.buffer_font.weight,
22279            line_height: relative(settings.buffer_line_height.value()),
22280            ..Default::default()
22281        };
22282        EditorElement::new(
22283            &self.prompt,
22284            EditorStyle {
22285                background: cx.theme().colors().editor_background,
22286                local_player: cx.theme().players().local(),
22287                text: text_style,
22288                ..Default::default()
22289            },
22290        )
22291    }
22292}
22293
22294impl Render for BreakpointPromptEditor {
22295    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22296        let editor_margins = *self.editor_margins.lock();
22297        let gutter_dimensions = editor_margins.gutter;
22298        h_flex()
22299            .key_context("Editor")
22300            .bg(cx.theme().colors().editor_background)
22301            .border_y_1()
22302            .border_color(cx.theme().status().info_border)
22303            .size_full()
22304            .py(window.line_height() / 2.5)
22305            .on_action(cx.listener(Self::confirm))
22306            .on_action(cx.listener(Self::cancel))
22307            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22308            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22309    }
22310}
22311
22312impl Focusable for BreakpointPromptEditor {
22313    fn focus_handle(&self, cx: &App) -> FocusHandle {
22314        self.prompt.focus_handle(cx)
22315    }
22316}
22317
22318fn all_edits_insertions_or_deletions(
22319    edits: &Vec<(Range<Anchor>, String)>,
22320    snapshot: &MultiBufferSnapshot,
22321) -> bool {
22322    let mut all_insertions = true;
22323    let mut all_deletions = true;
22324
22325    for (range, new_text) in edits.iter() {
22326        let range_is_empty = range.to_offset(&snapshot).is_empty();
22327        let text_is_empty = new_text.is_empty();
22328
22329        if range_is_empty != text_is_empty {
22330            if range_is_empty {
22331                all_deletions = false;
22332            } else {
22333                all_insertions = false;
22334            }
22335        } else {
22336            return false;
22337        }
22338
22339        if !all_insertions && !all_deletions {
22340            return false;
22341        }
22342    }
22343    all_insertions || all_deletions
22344}
22345
22346struct MissingEditPredictionKeybindingTooltip;
22347
22348impl Render for MissingEditPredictionKeybindingTooltip {
22349    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22350        ui::tooltip_container(window, cx, |container, _, cx| {
22351            container
22352                .flex_shrink_0()
22353                .max_w_80()
22354                .min_h(rems_from_px(124.))
22355                .justify_between()
22356                .child(
22357                    v_flex()
22358                        .flex_1()
22359                        .text_ui_sm(cx)
22360                        .child(Label::new("Conflict with Accept Keybinding"))
22361                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22362                )
22363                .child(
22364                    h_flex()
22365                        .pb_1()
22366                        .gap_1()
22367                        .items_end()
22368                        .w_full()
22369                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22370                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22371                        }))
22372                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22373                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22374                        })),
22375                )
22376        })
22377    }
22378}
22379
22380#[derive(Debug, Clone, Copy, PartialEq)]
22381pub struct LineHighlight {
22382    pub background: Background,
22383    pub border: Option<gpui::Hsla>,
22384    pub include_gutter: bool,
22385    pub type_id: Option<TypeId>,
22386}
22387
22388fn render_diff_hunk_controls(
22389    row: u32,
22390    status: &DiffHunkStatus,
22391    hunk_range: Range<Anchor>,
22392    is_created_file: bool,
22393    line_height: Pixels,
22394    editor: &Entity<Editor>,
22395    _window: &mut Window,
22396    cx: &mut App,
22397) -> AnyElement {
22398    h_flex()
22399        .h(line_height)
22400        .mr_1()
22401        .gap_1()
22402        .px_0p5()
22403        .pb_1()
22404        .border_x_1()
22405        .border_b_1()
22406        .border_color(cx.theme().colors().border_variant)
22407        .rounded_b_lg()
22408        .bg(cx.theme().colors().editor_background)
22409        .gap_1()
22410        .block_mouse_except_scroll()
22411        .shadow_md()
22412        .child(if status.has_secondary_hunk() {
22413            Button::new(("stage", row as u64), "Stage")
22414                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22415                .tooltip({
22416                    let focus_handle = editor.focus_handle(cx);
22417                    move |window, cx| {
22418                        Tooltip::for_action_in(
22419                            "Stage Hunk",
22420                            &::git::ToggleStaged,
22421                            &focus_handle,
22422                            window,
22423                            cx,
22424                        )
22425                    }
22426                })
22427                .on_click({
22428                    let editor = editor.clone();
22429                    move |_event, _window, cx| {
22430                        editor.update(cx, |editor, cx| {
22431                            editor.stage_or_unstage_diff_hunks(
22432                                true,
22433                                vec![hunk_range.start..hunk_range.start],
22434                                cx,
22435                            );
22436                        });
22437                    }
22438                })
22439        } else {
22440            Button::new(("unstage", row as u64), "Unstage")
22441                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22442                .tooltip({
22443                    let focus_handle = editor.focus_handle(cx);
22444                    move |window, cx| {
22445                        Tooltip::for_action_in(
22446                            "Unstage Hunk",
22447                            &::git::ToggleStaged,
22448                            &focus_handle,
22449                            window,
22450                            cx,
22451                        )
22452                    }
22453                })
22454                .on_click({
22455                    let editor = editor.clone();
22456                    move |_event, _window, cx| {
22457                        editor.update(cx, |editor, cx| {
22458                            editor.stage_or_unstage_diff_hunks(
22459                                false,
22460                                vec![hunk_range.start..hunk_range.start],
22461                                cx,
22462                            );
22463                        });
22464                    }
22465                })
22466        })
22467        .child(
22468            Button::new(("restore", row as u64), "Restore")
22469                .tooltip({
22470                    let focus_handle = editor.focus_handle(cx);
22471                    move |window, cx| {
22472                        Tooltip::for_action_in(
22473                            "Restore Hunk",
22474                            &::git::Restore,
22475                            &focus_handle,
22476                            window,
22477                            cx,
22478                        )
22479                    }
22480                })
22481                .on_click({
22482                    let editor = editor.clone();
22483                    move |_event, window, cx| {
22484                        editor.update(cx, |editor, cx| {
22485                            let snapshot = editor.snapshot(window, cx);
22486                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22487                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22488                        });
22489                    }
22490                })
22491                .disabled(is_created_file),
22492        )
22493        .when(
22494            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22495            |el| {
22496                el.child(
22497                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22498                        .shape(IconButtonShape::Square)
22499                        .icon_size(IconSize::Small)
22500                        // .disabled(!has_multiple_hunks)
22501                        .tooltip({
22502                            let focus_handle = editor.focus_handle(cx);
22503                            move |window, cx| {
22504                                Tooltip::for_action_in(
22505                                    "Next Hunk",
22506                                    &GoToHunk,
22507                                    &focus_handle,
22508                                    window,
22509                                    cx,
22510                                )
22511                            }
22512                        })
22513                        .on_click({
22514                            let editor = editor.clone();
22515                            move |_event, window, cx| {
22516                                editor.update(cx, |editor, cx| {
22517                                    let snapshot = editor.snapshot(window, cx);
22518                                    let position =
22519                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22520                                    editor.go_to_hunk_before_or_after_position(
22521                                        &snapshot,
22522                                        position,
22523                                        Direction::Next,
22524                                        window,
22525                                        cx,
22526                                    );
22527                                    editor.expand_selected_diff_hunks(cx);
22528                                });
22529                            }
22530                        }),
22531                )
22532                .child(
22533                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22534                        .shape(IconButtonShape::Square)
22535                        .icon_size(IconSize::Small)
22536                        // .disabled(!has_multiple_hunks)
22537                        .tooltip({
22538                            let focus_handle = editor.focus_handle(cx);
22539                            move |window, cx| {
22540                                Tooltip::for_action_in(
22541                                    "Previous Hunk",
22542                                    &GoToPreviousHunk,
22543                                    &focus_handle,
22544                                    window,
22545                                    cx,
22546                                )
22547                            }
22548                        })
22549                        .on_click({
22550                            let editor = editor.clone();
22551                            move |_event, window, cx| {
22552                                editor.update(cx, |editor, cx| {
22553                                    let snapshot = editor.snapshot(window, cx);
22554                                    let point =
22555                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22556                                    editor.go_to_hunk_before_or_after_position(
22557                                        &snapshot,
22558                                        point,
22559                                        Direction::Prev,
22560                                        window,
22561                                        cx,
22562                                    );
22563                                    editor.expand_selected_diff_hunks(cx);
22564                                });
22565                            }
22566                        }),
22567                )
22568            },
22569        )
22570        .into_any_element()
22571}