editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  113    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  114    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  115    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216
  217use crate::{
  218    code_context_menus::CompletionsMenuSource,
  219    hover_links::{find_url, find_url_from_range},
  220};
  221use crate::{
  222    editor_settings::MultiCursorModifier,
  223    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  224};
  225
  226pub const FILE_HEADER_HEIGHT: u32 = 2;
  227pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  228pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  229const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  230const MAX_LINE_LEN: usize = 1024;
  231const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  232const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  233pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  234#[doc(hidden)]
  235pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  236const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  237
  238pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  241
  242pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  243pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    DebuggerValue(usize),
  279    // LSP
  280    Hint(usize),
  281    Color(usize),
  282}
  283
  284impl InlayId {
  285    fn id(&self) -> usize {
  286        match self {
  287            Self::InlineCompletion(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::Color(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300pub enum PendingInput {}
  301enum SelectedTextHighlight {}
  302
  303pub enum ConflictsOuter {}
  304pub enum ConflictsOurs {}
  305pub enum ConflictsTheirs {}
  306pub enum ConflictsOursMarker {}
  307pub enum ConflictsTheirsMarker {}
  308
  309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  310pub enum Navigated {
  311    Yes,
  312    No,
  313}
  314
  315impl Navigated {
  316    pub fn from_bool(yes: bool) -> Navigated {
  317        if yes { Navigated::Yes } else { Navigated::No }
  318    }
  319}
  320
  321#[derive(Debug, Clone, PartialEq, Eq)]
  322enum DisplayDiffHunk {
  323    Folded {
  324        display_row: DisplayRow,
  325    },
  326    Unfolded {
  327        is_created_file: bool,
  328        diff_base_byte_range: Range<usize>,
  329        display_row_range: Range<DisplayRow>,
  330        multi_buffer_range: Range<Anchor>,
  331        status: DiffHunkStatus,
  332    },
  333}
  334
  335pub enum HideMouseCursorOrigin {
  336    TypingAction,
  337    MovementAction,
  338}
  339
  340pub fn init_settings(cx: &mut App) {
  341    EditorSettings::register(cx);
  342}
  343
  344pub fn init(cx: &mut App) {
  345    init_settings(cx);
  346
  347    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  348
  349    workspace::register_project_item::<Editor>(cx);
  350    workspace::FollowableViewRegistry::register::<Editor>(cx);
  351    workspace::register_serializable_item::<Editor>(cx);
  352
  353    cx.observe_new(
  354        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  355            workspace.register_action(Editor::new_file);
  356            workspace.register_action(Editor::new_file_vertical);
  357            workspace.register_action(Editor::new_file_horizontal);
  358            workspace.register_action(Editor::cancel_language_server_work);
  359            workspace.register_action(Editor::toggle_focus);
  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        mode: ColumnarMode,
  456        goal_column: u32,
  457    },
  458    Extend {
  459        position: DisplayPoint,
  460        click_count: usize,
  461    },
  462    Update {
  463        position: DisplayPoint,
  464        goal_column: u32,
  465        scroll_delta: gpui::Point<f32>,
  466    },
  467    End,
  468}
  469
  470#[derive(Clone, Debug, PartialEq)]
  471pub enum ColumnarMode {
  472    FromMouse,
  473    FromSelection,
  474}
  475
  476#[derive(Clone, Debug)]
  477pub enum SelectMode {
  478    Character,
  479    Word(Range<Anchor>),
  480    Line(Range<Anchor>),
  481    All,
  482}
  483
  484#[derive(Clone, PartialEq, Eq, Debug)]
  485pub enum EditorMode {
  486    SingleLine,
  487    AutoHeight {
  488        min_lines: usize,
  489        max_lines: Option<usize>,
  490    },
  491    Full {
  492        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  493        scale_ui_elements_with_buffer_font_size: bool,
  494        /// When set to `true`, the editor will render a background for the active line.
  495        show_active_line_background: bool,
  496        /// When set to `true`, the editor's height will be determined by its content.
  497        sized_by_content: bool,
  498    },
  499    Minimap {
  500        parent: WeakEntity<Editor>,
  501    },
  502}
  503
  504impl EditorMode {
  505    pub fn full() -> Self {
  506        Self::Full {
  507            scale_ui_elements_with_buffer_font_size: true,
  508            show_active_line_background: true,
  509            sized_by_content: false,
  510        }
  511    }
  512
  513    #[inline]
  514    pub fn is_full(&self) -> bool {
  515        matches!(self, Self::Full { .. })
  516    }
  517
  518    #[inline]
  519    pub fn is_single_line(&self) -> bool {
  520        matches!(self, Self::SingleLine { .. })
  521    }
  522
  523    #[inline]
  524    fn is_minimap(&self) -> bool {
  525        matches!(self, Self::Minimap { .. })
  526    }
  527}
  528
  529#[derive(Copy, Clone, Debug)]
  530pub enum SoftWrap {
  531    /// Prefer not to wrap at all.
  532    ///
  533    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  534    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  535    GitDiff,
  536    /// Prefer a single line generally, unless an overly long line is encountered.
  537    None,
  538    /// Soft wrap lines that exceed the editor width.
  539    EditorWidth,
  540    /// Soft wrap lines at the preferred line length.
  541    Column(u32),
  542    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  543    Bounded(u32),
  544}
  545
  546#[derive(Clone)]
  547pub struct EditorStyle {
  548    pub background: Hsla,
  549    pub border: Hsla,
  550    pub local_player: PlayerColor,
  551    pub text: TextStyle,
  552    pub scrollbar_width: Pixels,
  553    pub syntax: Arc<SyntaxTheme>,
  554    pub status: StatusColors,
  555    pub inlay_hints_style: HighlightStyle,
  556    pub inline_completion_styles: InlineCompletionStyles,
  557    pub unnecessary_code_fade: f32,
  558    pub show_underlines: bool,
  559}
  560
  561impl Default for EditorStyle {
  562    fn default() -> Self {
  563        Self {
  564            background: Hsla::default(),
  565            border: Hsla::default(),
  566            local_player: PlayerColor::default(),
  567            text: TextStyle::default(),
  568            scrollbar_width: Pixels::default(),
  569            syntax: Default::default(),
  570            // HACK: Status colors don't have a real default.
  571            // We should look into removing the status colors from the editor
  572            // style and retrieve them directly from the theme.
  573            status: StatusColors::dark(),
  574            inlay_hints_style: HighlightStyle::default(),
  575            inline_completion_styles: InlineCompletionStyles {
  576                insertion: HighlightStyle::default(),
  577                whitespace: HighlightStyle::default(),
  578            },
  579            unnecessary_code_fade: Default::default(),
  580            show_underlines: true,
  581        }
  582    }
  583}
  584
  585pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  586    let show_background = language_settings::language_settings(None, None, cx)
  587        .inlay_hints
  588        .show_background;
  589
  590    HighlightStyle {
  591        color: Some(cx.theme().status().hint),
  592        background_color: show_background.then(|| cx.theme().status().hint_background),
  593        ..HighlightStyle::default()
  594    }
  595}
  596
  597pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  598    InlineCompletionStyles {
  599        insertion: HighlightStyle {
  600            color: Some(cx.theme().status().predictive),
  601            ..HighlightStyle::default()
  602        },
  603        whitespace: HighlightStyle {
  604            background_color: Some(cx.theme().status().created_background),
  605            ..HighlightStyle::default()
  606        },
  607    }
  608}
  609
  610type CompletionId = usize;
  611
  612pub(crate) enum EditDisplayMode {
  613    TabAccept,
  614    DiffPopover,
  615    Inline,
  616}
  617
  618enum InlineCompletion {
  619    Edit {
  620        edits: Vec<(Range<Anchor>, String)>,
  621        edit_preview: Option<EditPreview>,
  622        display_mode: EditDisplayMode,
  623        snapshot: BufferSnapshot,
  624    },
  625    Move {
  626        target: Anchor,
  627        snapshot: BufferSnapshot,
  628    },
  629}
  630
  631struct InlineCompletionState {
  632    inlay_ids: Vec<InlayId>,
  633    completion: InlineCompletion,
  634    completion_id: Option<SharedString>,
  635    invalidation_range: Range<Anchor>,
  636}
  637
  638enum EditPredictionSettings {
  639    Disabled,
  640    Enabled {
  641        show_in_menu: bool,
  642        preview_requires_modifier: bool,
  643    },
  644}
  645
  646enum InlineCompletionHighlight {}
  647
  648#[derive(Debug, Clone)]
  649struct InlineDiagnostic {
  650    message: SharedString,
  651    group_id: usize,
  652    is_primary: bool,
  653    start: Point,
  654    severity: lsp::DiagnosticSeverity,
  655}
  656
  657pub enum MenuInlineCompletionsPolicy {
  658    Never,
  659    ByProvider,
  660}
  661
  662pub enum EditPredictionPreview {
  663    /// Modifier is not pressed
  664    Inactive { released_too_fast: bool },
  665    /// Modifier pressed
  666    Active {
  667        since: Instant,
  668        previous_scroll_position: Option<ScrollAnchor>,
  669    },
  670}
  671
  672impl EditPredictionPreview {
  673    pub fn released_too_fast(&self) -> bool {
  674        match self {
  675            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  676            EditPredictionPreview::Active { .. } => false,
  677        }
  678    }
  679
  680    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  681        if let EditPredictionPreview::Active {
  682            previous_scroll_position,
  683            ..
  684        } = self
  685        {
  686            *previous_scroll_position = scroll_position;
  687        }
  688    }
  689}
  690
  691pub struct ContextMenuOptions {
  692    pub min_entries_visible: usize,
  693    pub max_entries_visible: usize,
  694    pub placement: Option<ContextMenuPlacement>,
  695}
  696
  697#[derive(Debug, Clone, PartialEq, Eq)]
  698pub enum ContextMenuPlacement {
  699    Above,
  700    Below,
  701}
  702
  703#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  704struct EditorActionId(usize);
  705
  706impl EditorActionId {
  707    pub fn post_inc(&mut self) -> Self {
  708        let answer = self.0;
  709
  710        *self = Self(answer + 1);
  711
  712        Self(answer)
  713    }
  714}
  715
  716// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  717// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  718
  719type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  720type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  721
  722#[derive(Default)]
  723struct ScrollbarMarkerState {
  724    scrollbar_size: Size<Pixels>,
  725    dirty: bool,
  726    markers: Arc<[PaintQuad]>,
  727    pending_refresh: Option<Task<Result<()>>>,
  728}
  729
  730impl ScrollbarMarkerState {
  731    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  732        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  733    }
  734}
  735
  736#[derive(Clone, Copy, PartialEq, Eq)]
  737pub enum MinimapVisibility {
  738    Disabled,
  739    Enabled {
  740        /// The configuration currently present in the users settings.
  741        setting_configuration: bool,
  742        /// Whether to override the currently set visibility from the users setting.
  743        toggle_override: bool,
  744    },
  745}
  746
  747impl MinimapVisibility {
  748    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  749        if mode.is_full() {
  750            Self::Enabled {
  751                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  752                toggle_override: false,
  753            }
  754        } else {
  755            Self::Disabled
  756        }
  757    }
  758
  759    fn hidden(&self) -> Self {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => Self::Enabled {
  765                setting_configuration,
  766                toggle_override: setting_configuration,
  767            },
  768            Self::Disabled => Self::Disabled,
  769        }
  770    }
  771
  772    fn disabled(&self) -> bool {
  773        match *self {
  774            Self::Disabled => true,
  775            _ => false,
  776        }
  777    }
  778
  779    fn settings_visibility(&self) -> bool {
  780        match *self {
  781            Self::Enabled {
  782                setting_configuration,
  783                ..
  784            } => setting_configuration,
  785            _ => false,
  786        }
  787    }
  788
  789    fn visible(&self) -> bool {
  790        match *self {
  791            Self::Enabled {
  792                setting_configuration,
  793                toggle_override,
  794            } => setting_configuration ^ toggle_override,
  795            _ => false,
  796        }
  797    }
  798
  799    fn toggle_visibility(&self) -> Self {
  800        match *self {
  801            Self::Enabled {
  802                toggle_override,
  803                setting_configuration,
  804            } => Self::Enabled {
  805                setting_configuration,
  806                toggle_override: !toggle_override,
  807            },
  808            Self::Disabled => Self::Disabled,
  809        }
  810    }
  811}
  812
  813#[derive(Clone, Debug)]
  814struct RunnableTasks {
  815    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  816    offset: multi_buffer::Anchor,
  817    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  818    column: u32,
  819    // Values of all named captures, including those starting with '_'
  820    extra_variables: HashMap<String, String>,
  821    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  822    context_range: Range<BufferOffset>,
  823}
  824
  825impl RunnableTasks {
  826    fn resolve<'a>(
  827        &'a self,
  828        cx: &'a task::TaskContext,
  829    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  830        self.templates.iter().filter_map(|(kind, template)| {
  831            template
  832                .resolve_task(&kind.to_id_base(), cx)
  833                .map(|task| (kind.clone(), task))
  834        })
  835    }
  836}
  837
  838#[derive(Clone)]
  839pub struct ResolvedTasks {
  840    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  841    position: Anchor,
  842}
  843
  844#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  845struct BufferOffset(usize);
  846
  847// Addons allow storing per-editor state in other crates (e.g. Vim)
  848pub trait Addon: 'static {
  849    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  850
  851    fn render_buffer_header_controls(
  852        &self,
  853        _: &ExcerptInfo,
  854        _: &Window,
  855        _: &App,
  856    ) -> Option<AnyElement> {
  857        None
  858    }
  859
  860    fn to_any(&self) -> &dyn std::any::Any;
  861
  862    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  863        None
  864    }
  865}
  866
  867struct ChangeLocation {
  868    current: Option<Vec<Anchor>>,
  869    original: Vec<Anchor>,
  870}
  871impl ChangeLocation {
  872    fn locations(&self) -> &[Anchor] {
  873        self.current.as_ref().unwrap_or(&self.original)
  874    }
  875}
  876
  877/// A set of caret positions, registered when the editor was edited.
  878pub struct ChangeList {
  879    changes: Vec<ChangeLocation>,
  880    /// Currently "selected" change.
  881    position: Option<usize>,
  882}
  883
  884impl ChangeList {
  885    pub fn new() -> Self {
  886        Self {
  887            changes: Vec::new(),
  888            position: None,
  889        }
  890    }
  891
  892    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  893    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  894    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  895        if self.changes.is_empty() {
  896            return None;
  897        }
  898
  899        let prev = self.position.unwrap_or(self.changes.len());
  900        let next = if direction == Direction::Prev {
  901            prev.saturating_sub(count)
  902        } else {
  903            (prev + count).min(self.changes.len() - 1)
  904        };
  905        self.position = Some(next);
  906        self.changes.get(next).map(|change| change.locations())
  907    }
  908
  909    /// Adds a new change to the list, resetting the change list position.
  910    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  911        self.position.take();
  912        if let Some(last) = self.changes.last_mut()
  913            && group
  914        {
  915            last.current = Some(new_positions)
  916        } else {
  917            self.changes.push(ChangeLocation {
  918                original: new_positions,
  919                current: None,
  920            });
  921        }
  922    }
  923
  924    pub fn last(&self) -> Option<&[Anchor]> {
  925        self.changes.last().map(|change| change.locations())
  926    }
  927
  928    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  929        self.changes.last().map(|change| change.original.as_slice())
  930    }
  931
  932    pub fn invert_last_group(&mut self) {
  933        if let Some(last) = self.changes.last_mut() {
  934            if let Some(current) = last.current.as_mut() {
  935                mem::swap(&mut last.original, current);
  936            }
  937        }
  938    }
  939}
  940
  941#[derive(Clone)]
  942struct InlineBlamePopoverState {
  943    scroll_handle: ScrollHandle,
  944    commit_message: Option<ParsedCommitMessage>,
  945    markdown: Entity<Markdown>,
  946}
  947
  948struct InlineBlamePopover {
  949    position: gpui::Point<Pixels>,
  950    hide_task: Option<Task<()>>,
  951    popover_bounds: Option<Bounds<Pixels>>,
  952    popover_state: InlineBlamePopoverState,
  953}
  954
  955enum SelectionDragState {
  956    /// State when no drag related activity is detected.
  957    None,
  958    /// State when the mouse is down on a selection that is about to be dragged.
  959    ReadyToDrag {
  960        selection: Selection<Anchor>,
  961        click_position: gpui::Point<Pixels>,
  962        mouse_down_time: Instant,
  963    },
  964    /// State when the mouse is dragging the selection in the editor.
  965    Dragging {
  966        selection: Selection<Anchor>,
  967        drop_cursor: Selection<Anchor>,
  968        hide_drop_cursor: bool,
  969    },
  970}
  971
  972enum ColumnarSelectionState {
  973    FromMouse {
  974        selection_tail: Anchor,
  975        display_point: Option<DisplayPoint>,
  976    },
  977    FromSelection {
  978        selection_tail: Anchor,
  979    },
  980}
  981
  982/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  983/// a breakpoint on them.
  984#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  985struct PhantomBreakpointIndicator {
  986    display_row: DisplayRow,
  987    /// There's a small debounce between hovering over the line and showing the indicator.
  988    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  989    is_active: bool,
  990    collides_with_existing_breakpoint: bool,
  991}
  992
  993/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  994///
  995/// See the [module level documentation](self) for more information.
  996pub struct Editor {
  997    focus_handle: FocusHandle,
  998    last_focused_descendant: Option<WeakFocusHandle>,
  999    /// The text buffer being edited
 1000    buffer: Entity<MultiBuffer>,
 1001    /// Map of how text in the buffer should be displayed.
 1002    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1003    pub display_map: Entity<DisplayMap>,
 1004    pub selections: SelectionsCollection,
 1005    pub scroll_manager: ScrollManager,
 1006    /// When inline assist editors are linked, they all render cursors because
 1007    /// typing enters text into each of them, even the ones that aren't focused.
 1008    pub(crate) show_cursor_when_unfocused: bool,
 1009    columnar_selection_state: Option<ColumnarSelectionState>,
 1010    add_selections_state: Option<AddSelectionsState>,
 1011    select_next_state: Option<SelectNextState>,
 1012    select_prev_state: Option<SelectNextState>,
 1013    selection_history: SelectionHistory,
 1014    defer_selection_effects: bool,
 1015    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1016    autoclose_regions: Vec<AutocloseRegion>,
 1017    snippet_stack: InvalidationStack<SnippetState>,
 1018    select_syntax_node_history: SelectSyntaxNodeHistory,
 1019    ime_transaction: Option<TransactionId>,
 1020    pub diagnostics_max_severity: DiagnosticSeverity,
 1021    active_diagnostics: ActiveDiagnostic,
 1022    show_inline_diagnostics: bool,
 1023    inline_diagnostics_update: Task<()>,
 1024    inline_diagnostics_enabled: bool,
 1025    diagnostics_enabled: bool,
 1026    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1027    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1028    hard_wrap: Option<usize>,
 1029
 1030    // TODO: make this a access method
 1031    pub project: Option<Entity<Project>>,
 1032    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1033    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1034    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1035    blink_manager: Entity<BlinkManager>,
 1036    show_cursor_names: bool,
 1037    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1038    pub show_local_selections: bool,
 1039    mode: EditorMode,
 1040    show_breadcrumbs: bool,
 1041    show_gutter: bool,
 1042    show_scrollbars: ScrollbarAxes,
 1043    minimap_visibility: MinimapVisibility,
 1044    offset_content: bool,
 1045    disable_expand_excerpt_buttons: bool,
 1046    show_line_numbers: Option<bool>,
 1047    use_relative_line_numbers: Option<bool>,
 1048    show_git_diff_gutter: Option<bool>,
 1049    show_code_actions: Option<bool>,
 1050    show_runnables: Option<bool>,
 1051    show_breakpoints: Option<bool>,
 1052    show_wrap_guides: Option<bool>,
 1053    show_indent_guides: Option<bool>,
 1054    placeholder_text: Option<Arc<str>>,
 1055    highlight_order: usize,
 1056    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1057    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1058    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1059    scrollbar_marker_state: ScrollbarMarkerState,
 1060    active_indent_guides_state: ActiveIndentGuidesState,
 1061    nav_history: Option<ItemNavHistory>,
 1062    context_menu: RefCell<Option<CodeContextMenu>>,
 1063    context_menu_options: Option<ContextMenuOptions>,
 1064    mouse_context_menu: Option<MouseContextMenu>,
 1065    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1066    inline_blame_popover: Option<InlineBlamePopover>,
 1067    inline_blame_popover_show_task: Option<Task<()>>,
 1068    signature_help_state: SignatureHelpState,
 1069    auto_signature_help: Option<bool>,
 1070    find_all_references_task_sources: Vec<Anchor>,
 1071    next_completion_id: CompletionId,
 1072    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1073    code_actions_task: Option<Task<Result<()>>>,
 1074    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1075    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1076    document_highlights_task: Option<Task<()>>,
 1077    linked_editing_range_task: Option<Task<Option<()>>>,
 1078    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1079    pending_rename: Option<RenameState>,
 1080    searchable: bool,
 1081    cursor_shape: CursorShape,
 1082    current_line_highlight: Option<CurrentLineHighlight>,
 1083    collapse_matches: bool,
 1084    autoindent_mode: Option<AutoindentMode>,
 1085    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1086    input_enabled: bool,
 1087    use_modal_editing: bool,
 1088    read_only: bool,
 1089    leader_id: Option<CollaboratorId>,
 1090    remote_id: Option<ViewId>,
 1091    pub hover_state: HoverState,
 1092    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1093    gutter_hovered: bool,
 1094    hovered_link_state: Option<HoveredLinkState>,
 1095    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1096    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1097    active_inline_completion: Option<InlineCompletionState>,
 1098    /// Used to prevent flickering as the user types while the menu is open
 1099    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1100    edit_prediction_settings: EditPredictionSettings,
 1101    inline_completions_hidden_for_vim_mode: bool,
 1102    show_inline_completions_override: Option<bool>,
 1103    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1104    edit_prediction_preview: EditPredictionPreview,
 1105    edit_prediction_indent_conflict: bool,
 1106    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1107    inlay_hint_cache: InlayHintCache,
 1108    next_inlay_id: usize,
 1109    _subscriptions: Vec<Subscription>,
 1110    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1111    gutter_dimensions: GutterDimensions,
 1112    style: Option<EditorStyle>,
 1113    text_style_refinement: Option<TextStyleRefinement>,
 1114    next_editor_action_id: EditorActionId,
 1115    editor_actions: Rc<
 1116        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1117    >,
 1118    use_autoclose: bool,
 1119    use_auto_surround: bool,
 1120    auto_replace_emoji_shortcode: bool,
 1121    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1122    show_git_blame_gutter: bool,
 1123    show_git_blame_inline: bool,
 1124    show_git_blame_inline_delay_task: Option<Task<()>>,
 1125    git_blame_inline_enabled: bool,
 1126    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1127    serialize_dirty_buffers: bool,
 1128    show_selection_menu: Option<bool>,
 1129    blame: Option<Entity<GitBlame>>,
 1130    blame_subscription: Option<Subscription>,
 1131    custom_context_menu: Option<
 1132        Box<
 1133            dyn 'static
 1134                + Fn(
 1135                    &mut Self,
 1136                    DisplayPoint,
 1137                    &mut Window,
 1138                    &mut Context<Self>,
 1139                ) -> Option<Entity<ui::ContextMenu>>,
 1140        >,
 1141    >,
 1142    last_bounds: Option<Bounds<Pixels>>,
 1143    last_position_map: Option<Rc<PositionMap>>,
 1144    expect_bounds_change: Option<Bounds<Pixels>>,
 1145    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1146    tasks_update_task: Option<Task<()>>,
 1147    breakpoint_store: Option<Entity<BreakpointStore>>,
 1148    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1149    hovered_diff_hunk_row: Option<DisplayRow>,
 1150    pull_diagnostics_task: Task<()>,
 1151    in_project_search: bool,
 1152    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1153    breadcrumb_header: Option<String>,
 1154    focused_block: Option<FocusedBlock>,
 1155    next_scroll_position: NextScrollCursorCenterTopBottom,
 1156    addons: HashMap<TypeId, Box<dyn Addon>>,
 1157    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1158    load_diff_task: Option<Shared<Task<()>>>,
 1159    /// Whether we are temporarily displaying a diff other than git's
 1160    temporary_diff_override: bool,
 1161    selection_mark_mode: bool,
 1162    toggle_fold_multiple_buffers: Task<()>,
 1163    _scroll_cursor_center_top_bottom_task: Task<()>,
 1164    serialize_selections: Task<()>,
 1165    serialize_folds: Task<()>,
 1166    mouse_cursor_hidden: bool,
 1167    minimap: Option<Entity<Self>>,
 1168    hide_mouse_mode: HideMouseMode,
 1169    pub change_list: ChangeList,
 1170    inline_value_cache: InlineValueCache,
 1171    selection_drag_state: SelectionDragState,
 1172    next_color_inlay_id: usize,
 1173    colors: Option<LspColorData>,
 1174    folding_newlines: Task<()>,
 1175}
 1176
 1177#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1178enum NextScrollCursorCenterTopBottom {
 1179    #[default]
 1180    Center,
 1181    Top,
 1182    Bottom,
 1183}
 1184
 1185impl NextScrollCursorCenterTopBottom {
 1186    fn next(&self) -> Self {
 1187        match self {
 1188            Self::Center => Self::Top,
 1189            Self::Top => Self::Bottom,
 1190            Self::Bottom => Self::Center,
 1191        }
 1192    }
 1193}
 1194
 1195#[derive(Clone)]
 1196pub struct EditorSnapshot {
 1197    pub mode: EditorMode,
 1198    show_gutter: bool,
 1199    show_line_numbers: Option<bool>,
 1200    show_git_diff_gutter: Option<bool>,
 1201    show_code_actions: Option<bool>,
 1202    show_runnables: Option<bool>,
 1203    show_breakpoints: Option<bool>,
 1204    git_blame_gutter_max_author_length: Option<usize>,
 1205    pub display_snapshot: DisplaySnapshot,
 1206    pub placeholder_text: Option<Arc<str>>,
 1207    is_focused: bool,
 1208    scroll_anchor: ScrollAnchor,
 1209    ongoing_scroll: OngoingScroll,
 1210    current_line_highlight: CurrentLineHighlight,
 1211    gutter_hovered: bool,
 1212}
 1213
 1214#[derive(Default, Debug, Clone, Copy)]
 1215pub struct GutterDimensions {
 1216    pub left_padding: Pixels,
 1217    pub right_padding: Pixels,
 1218    pub width: Pixels,
 1219    pub margin: Pixels,
 1220    pub git_blame_entries_width: Option<Pixels>,
 1221}
 1222
 1223impl GutterDimensions {
 1224    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1225        Self {
 1226            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1227            ..Default::default()
 1228        }
 1229    }
 1230
 1231    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1232        -cx.text_system().descent(font_id, font_size)
 1233    }
 1234    /// The full width of the space taken up by the gutter.
 1235    pub fn full_width(&self) -> Pixels {
 1236        self.margin + self.width
 1237    }
 1238
 1239    /// The width of the space reserved for the fold indicators,
 1240    /// use alongside 'justify_end' and `gutter_width` to
 1241    /// right align content with the line numbers
 1242    pub fn fold_area_width(&self) -> Pixels {
 1243        self.margin + self.right_padding
 1244    }
 1245}
 1246
 1247struct CharacterDimensions {
 1248    em_width: Pixels,
 1249    em_advance: Pixels,
 1250    line_height: Pixels,
 1251}
 1252
 1253#[derive(Debug)]
 1254pub struct RemoteSelection {
 1255    pub replica_id: ReplicaId,
 1256    pub selection: Selection<Anchor>,
 1257    pub cursor_shape: CursorShape,
 1258    pub collaborator_id: CollaboratorId,
 1259    pub line_mode: bool,
 1260    pub user_name: Option<SharedString>,
 1261    pub color: PlayerColor,
 1262}
 1263
 1264#[derive(Clone, Debug)]
 1265struct SelectionHistoryEntry {
 1266    selections: Arc<[Selection<Anchor>]>,
 1267    select_next_state: Option<SelectNextState>,
 1268    select_prev_state: Option<SelectNextState>,
 1269    add_selections_state: Option<AddSelectionsState>,
 1270}
 1271
 1272#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1273enum SelectionHistoryMode {
 1274    Normal,
 1275    Undoing,
 1276    Redoing,
 1277    Skipping,
 1278}
 1279
 1280#[derive(Clone, PartialEq, Eq, Hash)]
 1281struct HoveredCursor {
 1282    replica_id: u16,
 1283    selection_id: usize,
 1284}
 1285
 1286impl Default for SelectionHistoryMode {
 1287    fn default() -> Self {
 1288        Self::Normal
 1289    }
 1290}
 1291
 1292#[derive(Debug)]
 1293/// SelectionEffects controls the side-effects of updating the selection.
 1294///
 1295/// The default behaviour does "what you mostly want":
 1296/// - it pushes to the nav history if the cursor moved by >10 lines
 1297/// - it re-triggers completion requests
 1298/// - it scrolls to fit
 1299///
 1300/// You might want to modify these behaviours. For example when doing a "jump"
 1301/// like go to definition, we always want to add to nav history; but when scrolling
 1302/// in vim mode we never do.
 1303///
 1304/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1305/// move.
 1306pub struct SelectionEffects {
 1307    nav_history: Option<bool>,
 1308    completions: bool,
 1309    scroll: Option<Autoscroll>,
 1310}
 1311
 1312impl Default for SelectionEffects {
 1313    fn default() -> Self {
 1314        Self {
 1315            nav_history: None,
 1316            completions: true,
 1317            scroll: Some(Autoscroll::fit()),
 1318        }
 1319    }
 1320}
 1321impl SelectionEffects {
 1322    pub fn scroll(scroll: Autoscroll) -> Self {
 1323        Self {
 1324            scroll: Some(scroll),
 1325            ..Default::default()
 1326        }
 1327    }
 1328
 1329    pub fn no_scroll() -> Self {
 1330        Self {
 1331            scroll: None,
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn completions(self, completions: bool) -> Self {
 1337        Self {
 1338            completions,
 1339            ..self
 1340        }
 1341    }
 1342
 1343    pub fn nav_history(self, nav_history: bool) -> Self {
 1344        Self {
 1345            nav_history: Some(nav_history),
 1346            ..self
 1347        }
 1348    }
 1349}
 1350
 1351struct DeferredSelectionEffectsState {
 1352    changed: bool,
 1353    effects: SelectionEffects,
 1354    old_cursor_position: Anchor,
 1355    history_entry: SelectionHistoryEntry,
 1356}
 1357
 1358#[derive(Default)]
 1359struct SelectionHistory {
 1360    #[allow(clippy::type_complexity)]
 1361    selections_by_transaction:
 1362        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1363    mode: SelectionHistoryMode,
 1364    undo_stack: VecDeque<SelectionHistoryEntry>,
 1365    redo_stack: VecDeque<SelectionHistoryEntry>,
 1366}
 1367
 1368impl SelectionHistory {
 1369    #[track_caller]
 1370    fn insert_transaction(
 1371        &mut self,
 1372        transaction_id: TransactionId,
 1373        selections: Arc<[Selection<Anchor>]>,
 1374    ) {
 1375        if selections.is_empty() {
 1376            log::error!(
 1377                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1378                std::panic::Location::caller()
 1379            );
 1380            return;
 1381        }
 1382        self.selections_by_transaction
 1383            .insert(transaction_id, (selections, None));
 1384    }
 1385
 1386    #[allow(clippy::type_complexity)]
 1387    fn transaction(
 1388        &self,
 1389        transaction_id: TransactionId,
 1390    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1391        self.selections_by_transaction.get(&transaction_id)
 1392    }
 1393
 1394    #[allow(clippy::type_complexity)]
 1395    fn transaction_mut(
 1396        &mut self,
 1397        transaction_id: TransactionId,
 1398    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1399        self.selections_by_transaction.get_mut(&transaction_id)
 1400    }
 1401
 1402    fn push(&mut self, entry: SelectionHistoryEntry) {
 1403        if !entry.selections.is_empty() {
 1404            match self.mode {
 1405                SelectionHistoryMode::Normal => {
 1406                    self.push_undo(entry);
 1407                    self.redo_stack.clear();
 1408                }
 1409                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1410                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1411                SelectionHistoryMode::Skipping => {}
 1412            }
 1413        }
 1414    }
 1415
 1416    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1417        if self
 1418            .undo_stack
 1419            .back()
 1420            .map_or(true, |e| e.selections != entry.selections)
 1421        {
 1422            self.undo_stack.push_back(entry);
 1423            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1424                self.undo_stack.pop_front();
 1425            }
 1426        }
 1427    }
 1428
 1429    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1430        if self
 1431            .redo_stack
 1432            .back()
 1433            .map_or(true, |e| e.selections != entry.selections)
 1434        {
 1435            self.redo_stack.push_back(entry);
 1436            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1437                self.redo_stack.pop_front();
 1438            }
 1439        }
 1440    }
 1441}
 1442
 1443#[derive(Clone, Copy)]
 1444pub struct RowHighlightOptions {
 1445    pub autoscroll: bool,
 1446    pub include_gutter: bool,
 1447}
 1448
 1449impl Default for RowHighlightOptions {
 1450    fn default() -> Self {
 1451        Self {
 1452            autoscroll: Default::default(),
 1453            include_gutter: true,
 1454        }
 1455    }
 1456}
 1457
 1458struct RowHighlight {
 1459    index: usize,
 1460    range: Range<Anchor>,
 1461    color: Hsla,
 1462    options: RowHighlightOptions,
 1463    type_id: TypeId,
 1464}
 1465
 1466#[derive(Clone, Debug)]
 1467struct AddSelectionsState {
 1468    groups: Vec<AddSelectionsGroup>,
 1469}
 1470
 1471#[derive(Clone, Debug)]
 1472struct AddSelectionsGroup {
 1473    above: bool,
 1474    stack: Vec<usize>,
 1475}
 1476
 1477#[derive(Clone)]
 1478struct SelectNextState {
 1479    query: AhoCorasick,
 1480    wordwise: bool,
 1481    done: bool,
 1482}
 1483
 1484impl std::fmt::Debug for SelectNextState {
 1485    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1486        f.debug_struct(std::any::type_name::<Self>())
 1487            .field("wordwise", &self.wordwise)
 1488            .field("done", &self.done)
 1489            .finish()
 1490    }
 1491}
 1492
 1493#[derive(Debug)]
 1494struct AutocloseRegion {
 1495    selection_id: usize,
 1496    range: Range<Anchor>,
 1497    pair: BracketPair,
 1498}
 1499
 1500#[derive(Debug)]
 1501struct SnippetState {
 1502    ranges: Vec<Vec<Range<Anchor>>>,
 1503    active_index: usize,
 1504    choices: Vec<Option<Vec<String>>>,
 1505}
 1506
 1507#[doc(hidden)]
 1508pub struct RenameState {
 1509    pub range: Range<Anchor>,
 1510    pub old_name: Arc<str>,
 1511    pub editor: Entity<Editor>,
 1512    block_id: CustomBlockId,
 1513}
 1514
 1515struct InvalidationStack<T>(Vec<T>);
 1516
 1517struct RegisteredInlineCompletionProvider {
 1518    provider: Arc<dyn InlineCompletionProviderHandle>,
 1519    _subscription: Subscription,
 1520}
 1521
 1522#[derive(Debug, PartialEq, Eq)]
 1523pub struct ActiveDiagnosticGroup {
 1524    pub active_range: Range<Anchor>,
 1525    pub active_message: String,
 1526    pub group_id: usize,
 1527    pub blocks: HashSet<CustomBlockId>,
 1528}
 1529
 1530#[derive(Debug, PartialEq, Eq)]
 1531
 1532pub(crate) enum ActiveDiagnostic {
 1533    None,
 1534    All,
 1535    Group(ActiveDiagnosticGroup),
 1536}
 1537
 1538#[derive(Serialize, Deserialize, Clone, Debug)]
 1539pub struct ClipboardSelection {
 1540    /// The number of bytes in this selection.
 1541    pub len: usize,
 1542    /// Whether this was a full-line selection.
 1543    pub is_entire_line: bool,
 1544    /// The indentation of the first line when this content was originally copied.
 1545    pub first_line_indent: u32,
 1546}
 1547
 1548// selections, scroll behavior, was newest selection reversed
 1549type SelectSyntaxNodeHistoryState = (
 1550    Box<[Selection<usize>]>,
 1551    SelectSyntaxNodeScrollBehavior,
 1552    bool,
 1553);
 1554
 1555#[derive(Default)]
 1556struct SelectSyntaxNodeHistory {
 1557    stack: Vec<SelectSyntaxNodeHistoryState>,
 1558    // disable temporarily to allow changing selections without losing the stack
 1559    pub disable_clearing: bool,
 1560}
 1561
 1562impl SelectSyntaxNodeHistory {
 1563    pub fn try_clear(&mut self) {
 1564        if !self.disable_clearing {
 1565            self.stack.clear();
 1566        }
 1567    }
 1568
 1569    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1570        self.stack.push(selection);
 1571    }
 1572
 1573    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1574        self.stack.pop()
 1575    }
 1576}
 1577
 1578enum SelectSyntaxNodeScrollBehavior {
 1579    CursorTop,
 1580    FitSelection,
 1581    CursorBottom,
 1582}
 1583
 1584#[derive(Debug)]
 1585pub(crate) struct NavigationData {
 1586    cursor_anchor: Anchor,
 1587    cursor_position: Point,
 1588    scroll_anchor: ScrollAnchor,
 1589    scroll_top_row: u32,
 1590}
 1591
 1592#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1593pub enum GotoDefinitionKind {
 1594    Symbol,
 1595    Declaration,
 1596    Type,
 1597    Implementation,
 1598}
 1599
 1600#[derive(Debug, Clone)]
 1601enum InlayHintRefreshReason {
 1602    ModifiersChanged(bool),
 1603    Toggle(bool),
 1604    SettingsChange(InlayHintSettings),
 1605    NewLinesShown,
 1606    BufferEdited(HashSet<Arc<Language>>),
 1607    RefreshRequested,
 1608    ExcerptsRemoved(Vec<ExcerptId>),
 1609}
 1610
 1611impl InlayHintRefreshReason {
 1612    fn description(&self) -> &'static str {
 1613        match self {
 1614            Self::ModifiersChanged(_) => "modifiers changed",
 1615            Self::Toggle(_) => "toggle",
 1616            Self::SettingsChange(_) => "settings change",
 1617            Self::NewLinesShown => "new lines shown",
 1618            Self::BufferEdited(_) => "buffer edited",
 1619            Self::RefreshRequested => "refresh requested",
 1620            Self::ExcerptsRemoved(_) => "excerpts removed",
 1621        }
 1622    }
 1623}
 1624
 1625pub enum FormatTarget {
 1626    Buffers(HashSet<Entity<Buffer>>),
 1627    Ranges(Vec<Range<MultiBufferPoint>>),
 1628}
 1629
 1630pub(crate) struct FocusedBlock {
 1631    id: BlockId,
 1632    focus_handle: WeakFocusHandle,
 1633}
 1634
 1635#[derive(Clone)]
 1636enum JumpData {
 1637    MultiBufferRow {
 1638        row: MultiBufferRow,
 1639        line_offset_from_top: u32,
 1640    },
 1641    MultiBufferPoint {
 1642        excerpt_id: ExcerptId,
 1643        position: Point,
 1644        anchor: text::Anchor,
 1645        line_offset_from_top: u32,
 1646    },
 1647}
 1648
 1649pub enum MultibufferSelectionMode {
 1650    First,
 1651    All,
 1652}
 1653
 1654#[derive(Clone, Copy, Debug, Default)]
 1655pub struct RewrapOptions {
 1656    pub override_language_settings: bool,
 1657    pub preserve_existing_whitespace: bool,
 1658}
 1659
 1660impl Editor {
 1661    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1662        let buffer = cx.new(|cx| Buffer::local("", cx));
 1663        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1664        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1665    }
 1666
 1667    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(EditorMode::full(), buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn auto_height(
 1674        min_lines: usize,
 1675        max_lines: usize,
 1676        window: &mut Window,
 1677        cx: &mut Context<Self>,
 1678    ) -> Self {
 1679        let buffer = cx.new(|cx| Buffer::local("", cx));
 1680        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1681        Self::new(
 1682            EditorMode::AutoHeight {
 1683                min_lines,
 1684                max_lines: Some(max_lines),
 1685            },
 1686            buffer,
 1687            None,
 1688            window,
 1689            cx,
 1690        )
 1691    }
 1692
 1693    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1694    /// The editor grows as tall as needed to fit its content.
 1695    pub fn auto_height_unbounded(
 1696        min_lines: usize,
 1697        window: &mut Window,
 1698        cx: &mut Context<Self>,
 1699    ) -> Self {
 1700        let buffer = cx.new(|cx| Buffer::local("", cx));
 1701        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1702        Self::new(
 1703            EditorMode::AutoHeight {
 1704                min_lines,
 1705                max_lines: None,
 1706            },
 1707            buffer,
 1708            None,
 1709            window,
 1710            cx,
 1711        )
 1712    }
 1713
 1714    pub fn for_buffer(
 1715        buffer: Entity<Buffer>,
 1716        project: Option<Entity<Project>>,
 1717        window: &mut Window,
 1718        cx: &mut Context<Self>,
 1719    ) -> Self {
 1720        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1721        Self::new(EditorMode::full(), buffer, project, window, cx)
 1722    }
 1723
 1724    pub fn for_multibuffer(
 1725        buffer: Entity<MultiBuffer>,
 1726        project: Option<Entity<Project>>,
 1727        window: &mut Window,
 1728        cx: &mut Context<Self>,
 1729    ) -> Self {
 1730        Self::new(EditorMode::full(), buffer, project, window, cx)
 1731    }
 1732
 1733    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1734        let mut clone = Self::new(
 1735            self.mode.clone(),
 1736            self.buffer.clone(),
 1737            self.project.clone(),
 1738            window,
 1739            cx,
 1740        );
 1741        self.display_map.update(cx, |display_map, cx| {
 1742            let snapshot = display_map.snapshot(cx);
 1743            clone.display_map.update(cx, |display_map, cx| {
 1744                display_map.set_state(&snapshot, cx);
 1745            });
 1746        });
 1747        clone.folds_did_change(cx);
 1748        clone.selections.clone_state(&self.selections);
 1749        clone.scroll_manager.clone_state(&self.scroll_manager);
 1750        clone.searchable = self.searchable;
 1751        clone.read_only = self.read_only;
 1752        clone
 1753    }
 1754
 1755    pub fn new(
 1756        mode: EditorMode,
 1757        buffer: Entity<MultiBuffer>,
 1758        project: Option<Entity<Project>>,
 1759        window: &mut Window,
 1760        cx: &mut Context<Self>,
 1761    ) -> Self {
 1762        Editor::new_internal(mode, buffer, project, None, window, cx)
 1763    }
 1764
 1765    fn new_internal(
 1766        mode: EditorMode,
 1767        buffer: Entity<MultiBuffer>,
 1768        project: Option<Entity<Project>>,
 1769        display_map: Option<Entity<DisplayMap>>,
 1770        window: &mut Window,
 1771        cx: &mut Context<Self>,
 1772    ) -> Self {
 1773        debug_assert!(
 1774            display_map.is_none() || mode.is_minimap(),
 1775            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1776        );
 1777
 1778        let full_mode = mode.is_full();
 1779        let is_minimap = mode.is_minimap();
 1780        let diagnostics_max_severity = if full_mode {
 1781            EditorSettings::get_global(cx)
 1782                .diagnostics_max_severity
 1783                .unwrap_or(DiagnosticSeverity::Hint)
 1784        } else {
 1785            DiagnosticSeverity::Off
 1786        };
 1787        let style = window.text_style();
 1788        let font_size = style.font_size.to_pixels(window.rem_size());
 1789        let editor = cx.entity().downgrade();
 1790        let fold_placeholder = FoldPlaceholder {
 1791            constrain_width: true,
 1792            render: Arc::new(move |fold_id, fold_range, cx| {
 1793                let editor = editor.clone();
 1794                div()
 1795                    .id(fold_id)
 1796                    .bg(cx.theme().colors().ghost_element_background)
 1797                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1798                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1799                    .rounded_xs()
 1800                    .size_full()
 1801                    .cursor_pointer()
 1802                    .child("")
 1803                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1804                    .on_click(move |_, _window, cx| {
 1805                        editor
 1806                            .update(cx, |editor, cx| {
 1807                                editor.unfold_ranges(
 1808                                    &[fold_range.start..fold_range.end],
 1809                                    true,
 1810                                    false,
 1811                                    cx,
 1812                                );
 1813                                cx.stop_propagation();
 1814                            })
 1815                            .ok();
 1816                    })
 1817                    .into_any()
 1818            }),
 1819            merge_adjacent: true,
 1820            ..FoldPlaceholder::default()
 1821        };
 1822        let display_map = display_map.unwrap_or_else(|| {
 1823            cx.new(|cx| {
 1824                DisplayMap::new(
 1825                    buffer.clone(),
 1826                    style.font(),
 1827                    font_size,
 1828                    None,
 1829                    FILE_HEADER_HEIGHT,
 1830                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1831                    fold_placeholder,
 1832                    diagnostics_max_severity,
 1833                    cx,
 1834                )
 1835            })
 1836        });
 1837
 1838        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1839
 1840        let blink_manager = cx.new(|cx| {
 1841            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1842            if is_minimap {
 1843                blink_manager.disable(cx);
 1844            }
 1845            blink_manager
 1846        });
 1847
 1848        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1849            .then(|| language_settings::SoftWrap::None);
 1850
 1851        let mut project_subscriptions = Vec::new();
 1852        if full_mode {
 1853            if let Some(project) = project.as_ref() {
 1854                project_subscriptions.push(cx.subscribe_in(
 1855                    project,
 1856                    window,
 1857                    |editor, _, event, window, cx| match event {
 1858                        project::Event::RefreshCodeLens => {
 1859                            // we always query lens with actions, without storing them, always refreshing them
 1860                        }
 1861                        project::Event::RefreshInlayHints => {
 1862                            editor
 1863                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1864                        }
 1865                        project::Event::LanguageServerAdded(..)
 1866                        | project::Event::LanguageServerRemoved(..) => {
 1867                            if editor.tasks_update_task.is_none() {
 1868                                editor.tasks_update_task =
 1869                                    Some(editor.refresh_runnables(window, cx));
 1870                            }
 1871                            editor.update_lsp_data(true, None, window, cx);
 1872                        }
 1873                        project::Event::SnippetEdit(id, snippet_edits) => {
 1874                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1875                                let focus_handle = editor.focus_handle(cx);
 1876                                if focus_handle.is_focused(window) {
 1877                                    let snapshot = buffer.read(cx).snapshot();
 1878                                    for (range, snippet) in snippet_edits {
 1879                                        let editor_range =
 1880                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1881                                        editor
 1882                                            .insert_snippet(
 1883                                                &[editor_range],
 1884                                                snippet.clone(),
 1885                                                window,
 1886                                                cx,
 1887                                            )
 1888                                            .ok();
 1889                                    }
 1890                                }
 1891                            }
 1892                        }
 1893                        _ => {}
 1894                    },
 1895                ));
 1896                if let Some(task_inventory) = project
 1897                    .read(cx)
 1898                    .task_store()
 1899                    .read(cx)
 1900                    .task_inventory()
 1901                    .cloned()
 1902                {
 1903                    project_subscriptions.push(cx.observe_in(
 1904                        &task_inventory,
 1905                        window,
 1906                        |editor, _, window, cx| {
 1907                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1908                        },
 1909                    ));
 1910                };
 1911
 1912                project_subscriptions.push(cx.subscribe_in(
 1913                    &project.read(cx).breakpoint_store(),
 1914                    window,
 1915                    |editor, _, event, window, cx| match event {
 1916                        BreakpointStoreEvent::ClearDebugLines => {
 1917                            editor.clear_row_highlights::<ActiveDebugLine>();
 1918                            editor.refresh_inline_values(cx);
 1919                        }
 1920                        BreakpointStoreEvent::SetDebugLine => {
 1921                            if editor.go_to_active_debug_line(window, cx) {
 1922                                cx.stop_propagation();
 1923                            }
 1924
 1925                            editor.refresh_inline_values(cx);
 1926                        }
 1927                        _ => {}
 1928                    },
 1929                ));
 1930                let git_store = project.read(cx).git_store().clone();
 1931                let project = project.clone();
 1932                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1933                    match event {
 1934                        GitStoreEvent::RepositoryUpdated(
 1935                            _,
 1936                            RepositoryEvent::Updated {
 1937                                new_instance: true, ..
 1938                            },
 1939                            _,
 1940                        ) => {
 1941                            this.load_diff_task = Some(
 1942                                update_uncommitted_diff_for_buffer(
 1943                                    cx.entity(),
 1944                                    &project,
 1945                                    this.buffer.read(cx).all_buffers(),
 1946                                    this.buffer.clone(),
 1947                                    cx,
 1948                                )
 1949                                .shared(),
 1950                            );
 1951                        }
 1952                        _ => {}
 1953                    }
 1954                }));
 1955            }
 1956        }
 1957
 1958        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1959
 1960        let inlay_hint_settings =
 1961            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1962        let focus_handle = cx.focus_handle();
 1963        if !is_minimap {
 1964            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1965                .detach();
 1966            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1967                .detach();
 1968            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1969                .detach();
 1970            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1971                .detach();
 1972            cx.observe_pending_input(window, Self::observe_pending_input)
 1973                .detach();
 1974        }
 1975
 1976        let show_indent_guides = if matches!(
 1977            mode,
 1978            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1979        ) {
 1980            Some(false)
 1981        } else {
 1982            None
 1983        };
 1984
 1985        let breakpoint_store = match (&mode, project.as_ref()) {
 1986            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1987            _ => None,
 1988        };
 1989
 1990        let mut code_action_providers = Vec::new();
 1991        let mut load_uncommitted_diff = None;
 1992        if let Some(project) = project.clone() {
 1993            load_uncommitted_diff = Some(
 1994                update_uncommitted_diff_for_buffer(
 1995                    cx.entity(),
 1996                    &project,
 1997                    buffer.read(cx).all_buffers(),
 1998                    buffer.clone(),
 1999                    cx,
 2000                )
 2001                .shared(),
 2002            );
 2003            code_action_providers.push(Rc::new(project) as Rc<_>);
 2004        }
 2005
 2006        let mut editor = Self {
 2007            focus_handle,
 2008            show_cursor_when_unfocused: false,
 2009            last_focused_descendant: None,
 2010            buffer: buffer.clone(),
 2011            display_map: display_map.clone(),
 2012            selections,
 2013            scroll_manager: ScrollManager::new(cx),
 2014            columnar_selection_state: None,
 2015            add_selections_state: None,
 2016            select_next_state: None,
 2017            select_prev_state: None,
 2018            selection_history: SelectionHistory::default(),
 2019            defer_selection_effects: false,
 2020            deferred_selection_effects_state: None,
 2021            autoclose_regions: Vec::new(),
 2022            snippet_stack: InvalidationStack::default(),
 2023            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2024            ime_transaction: None,
 2025            active_diagnostics: ActiveDiagnostic::None,
 2026            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2027            inline_diagnostics_update: Task::ready(()),
 2028            inline_diagnostics: Vec::new(),
 2029            soft_wrap_mode_override,
 2030            diagnostics_max_severity,
 2031            hard_wrap: None,
 2032            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2033            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2034            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2035            project,
 2036            blink_manager: blink_manager.clone(),
 2037            show_local_selections: true,
 2038            show_scrollbars: ScrollbarAxes {
 2039                horizontal: full_mode,
 2040                vertical: full_mode,
 2041            },
 2042            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2043            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2044            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2045            show_gutter: full_mode,
 2046            show_line_numbers: (!full_mode).then_some(false),
 2047            use_relative_line_numbers: None,
 2048            disable_expand_excerpt_buttons: !full_mode,
 2049            show_git_diff_gutter: None,
 2050            show_code_actions: None,
 2051            show_runnables: None,
 2052            show_breakpoints: None,
 2053            show_wrap_guides: None,
 2054            show_indent_guides,
 2055            placeholder_text: None,
 2056            highlight_order: 0,
 2057            highlighted_rows: HashMap::default(),
 2058            background_highlights: TreeMap::default(),
 2059            gutter_highlights: TreeMap::default(),
 2060            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2061            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2062            nav_history: None,
 2063            context_menu: RefCell::new(None),
 2064            context_menu_options: None,
 2065            mouse_context_menu: None,
 2066            completion_tasks: Vec::new(),
 2067            inline_blame_popover: None,
 2068            inline_blame_popover_show_task: None,
 2069            signature_help_state: SignatureHelpState::default(),
 2070            auto_signature_help: None,
 2071            find_all_references_task_sources: Vec::new(),
 2072            next_completion_id: 0,
 2073            next_inlay_id: 0,
 2074            code_action_providers,
 2075            available_code_actions: None,
 2076            code_actions_task: None,
 2077            quick_selection_highlight_task: None,
 2078            debounced_selection_highlight_task: None,
 2079            document_highlights_task: None,
 2080            linked_editing_range_task: None,
 2081            pending_rename: None,
 2082            searchable: !is_minimap,
 2083            cursor_shape: EditorSettings::get_global(cx)
 2084                .cursor_shape
 2085                .unwrap_or_default(),
 2086            current_line_highlight: None,
 2087            autoindent_mode: Some(AutoindentMode::EachLine),
 2088            collapse_matches: false,
 2089            workspace: None,
 2090            input_enabled: !is_minimap,
 2091            use_modal_editing: full_mode,
 2092            read_only: is_minimap,
 2093            use_autoclose: true,
 2094            use_auto_surround: true,
 2095            auto_replace_emoji_shortcode: false,
 2096            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2097            leader_id: None,
 2098            remote_id: None,
 2099            hover_state: HoverState::default(),
 2100            pending_mouse_down: None,
 2101            hovered_link_state: None,
 2102            edit_prediction_provider: None,
 2103            active_inline_completion: None,
 2104            stale_inline_completion_in_menu: None,
 2105            edit_prediction_preview: EditPredictionPreview::Inactive {
 2106                released_too_fast: false,
 2107            },
 2108            inline_diagnostics_enabled: full_mode,
 2109            diagnostics_enabled: full_mode,
 2110            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2111            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2112            gutter_hovered: false,
 2113            pixel_position_of_newest_cursor: None,
 2114            last_bounds: None,
 2115            last_position_map: None,
 2116            expect_bounds_change: None,
 2117            gutter_dimensions: GutterDimensions::default(),
 2118            style: None,
 2119            show_cursor_names: false,
 2120            hovered_cursors: HashMap::default(),
 2121            next_editor_action_id: EditorActionId::default(),
 2122            editor_actions: Rc::default(),
 2123            inline_completions_hidden_for_vim_mode: false,
 2124            show_inline_completions_override: None,
 2125            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2126            edit_prediction_settings: EditPredictionSettings::Disabled,
 2127            edit_prediction_indent_conflict: false,
 2128            edit_prediction_requires_modifier_in_indent_conflict: true,
 2129            custom_context_menu: None,
 2130            show_git_blame_gutter: false,
 2131            show_git_blame_inline: false,
 2132            show_selection_menu: None,
 2133            show_git_blame_inline_delay_task: None,
 2134            git_blame_inline_enabled: full_mode
 2135                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2136            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2137            serialize_dirty_buffers: !is_minimap
 2138                && ProjectSettings::get_global(cx)
 2139                    .session
 2140                    .restore_unsaved_buffers,
 2141            blame: None,
 2142            blame_subscription: None,
 2143            tasks: BTreeMap::default(),
 2144
 2145            breakpoint_store,
 2146            gutter_breakpoint_indicator: (None, None),
 2147            hovered_diff_hunk_row: None,
 2148            _subscriptions: (!is_minimap)
 2149                .then(|| {
 2150                    vec![
 2151                        cx.observe(&buffer, Self::on_buffer_changed),
 2152                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2153                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2154                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2155                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2156                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2157                        cx.observe_window_activation(window, |editor, window, cx| {
 2158                            let active = window.is_window_active();
 2159                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2160                                if active {
 2161                                    blink_manager.enable(cx);
 2162                                } else {
 2163                                    blink_manager.disable(cx);
 2164                                }
 2165                            });
 2166                            if active {
 2167                                editor.show_mouse_cursor(cx);
 2168                            }
 2169                        }),
 2170                    ]
 2171                })
 2172                .unwrap_or_default(),
 2173            tasks_update_task: None,
 2174            pull_diagnostics_task: Task::ready(()),
 2175            colors: None,
 2176            next_color_inlay_id: 0,
 2177            linked_edit_ranges: Default::default(),
 2178            in_project_search: false,
 2179            previous_search_ranges: None,
 2180            breadcrumb_header: None,
 2181            focused_block: None,
 2182            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2183            addons: HashMap::default(),
 2184            registered_buffers: HashMap::default(),
 2185            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2186            selection_mark_mode: false,
 2187            toggle_fold_multiple_buffers: Task::ready(()),
 2188            serialize_selections: Task::ready(()),
 2189            serialize_folds: Task::ready(()),
 2190            text_style_refinement: None,
 2191            load_diff_task: load_uncommitted_diff,
 2192            temporary_diff_override: false,
 2193            mouse_cursor_hidden: false,
 2194            minimap: None,
 2195            hide_mouse_mode: EditorSettings::get_global(cx)
 2196                .hide_mouse
 2197                .unwrap_or_default(),
 2198            change_list: ChangeList::new(),
 2199            mode,
 2200            selection_drag_state: SelectionDragState::None,
 2201            folding_newlines: Task::ready(()),
 2202        };
 2203
 2204        if is_minimap {
 2205            return editor;
 2206        }
 2207
 2208        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2209            editor
 2210                ._subscriptions
 2211                .push(cx.observe(breakpoints, |_, _, cx| {
 2212                    cx.notify();
 2213                }));
 2214        }
 2215        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2216        editor._subscriptions.extend(project_subscriptions);
 2217
 2218        editor._subscriptions.push(cx.subscribe_in(
 2219            &cx.entity(),
 2220            window,
 2221            |editor, _, e: &EditorEvent, window, cx| match e {
 2222                EditorEvent::ScrollPositionChanged { local, .. } => {
 2223                    if *local {
 2224                        let new_anchor = editor.scroll_manager.anchor();
 2225                        let snapshot = editor.snapshot(window, cx);
 2226                        editor.update_restoration_data(cx, move |data| {
 2227                            data.scroll_position = (
 2228                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2229                                new_anchor.offset,
 2230                            );
 2231                        });
 2232                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2233                        editor.inline_blame_popover.take();
 2234                    }
 2235                }
 2236                EditorEvent::Edited { .. } => {
 2237                    if !vim_enabled(cx) {
 2238                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2239                        let pop_state = editor
 2240                            .change_list
 2241                            .last()
 2242                            .map(|previous| {
 2243                                previous.len() == selections.len()
 2244                                    && previous.iter().enumerate().all(|(ix, p)| {
 2245                                        p.to_display_point(&map).row()
 2246                                            == selections[ix].head().row()
 2247                                    })
 2248                            })
 2249                            .unwrap_or(false);
 2250                        let new_positions = selections
 2251                            .into_iter()
 2252                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2253                            .collect();
 2254                        editor
 2255                            .change_list
 2256                            .push_to_change_list(pop_state, new_positions);
 2257                    }
 2258                }
 2259                _ => (),
 2260            },
 2261        ));
 2262
 2263        if let Some(dap_store) = editor
 2264            .project
 2265            .as_ref()
 2266            .map(|project| project.read(cx).dap_store())
 2267        {
 2268            let weak_editor = cx.weak_entity();
 2269
 2270            editor
 2271                ._subscriptions
 2272                .push(
 2273                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2274                        let session_entity = cx.entity();
 2275                        weak_editor
 2276                            .update(cx, |editor, cx| {
 2277                                editor._subscriptions.push(
 2278                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2279                                );
 2280                            })
 2281                            .ok();
 2282                    }),
 2283                );
 2284
 2285            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2286                editor
 2287                    ._subscriptions
 2288                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2289            }
 2290        }
 2291
 2292        // skip adding the initial selection to selection history
 2293        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2294        editor.end_selection(window, cx);
 2295        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2296
 2297        editor.scroll_manager.show_scrollbars(window, cx);
 2298        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2299
 2300        if full_mode {
 2301            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2302            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2303
 2304            if editor.git_blame_inline_enabled {
 2305                editor.start_git_blame_inline(false, window, cx);
 2306            }
 2307
 2308            editor.go_to_active_debug_line(window, cx);
 2309
 2310            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2311                if let Some(project) = editor.project.as_ref() {
 2312                    let handle = project.update(cx, |project, cx| {
 2313                        project.register_buffer_with_language_servers(&buffer, cx)
 2314                    });
 2315                    editor
 2316                        .registered_buffers
 2317                        .insert(buffer.read(cx).remote_id(), handle);
 2318                }
 2319            }
 2320
 2321            editor.minimap =
 2322                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2323            editor.colors = Some(LspColorData::new(cx));
 2324            editor.update_lsp_data(false, None, window, cx);
 2325        }
 2326
 2327        if editor.mode.is_full() {
 2328            editor.report_editor_event("Editor Opened", None, cx);
 2329        }
 2330
 2331        editor
 2332    }
 2333
 2334    pub fn deploy_mouse_context_menu(
 2335        &mut self,
 2336        position: gpui::Point<Pixels>,
 2337        context_menu: Entity<ContextMenu>,
 2338        window: &mut Window,
 2339        cx: &mut Context<Self>,
 2340    ) {
 2341        self.mouse_context_menu = Some(MouseContextMenu::new(
 2342            self,
 2343            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2344            context_menu,
 2345            window,
 2346            cx,
 2347        ));
 2348    }
 2349
 2350    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2351        self.mouse_context_menu
 2352            .as_ref()
 2353            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2354    }
 2355
 2356    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2357        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2358    }
 2359
 2360    fn key_context_internal(
 2361        &self,
 2362        has_active_edit_prediction: bool,
 2363        window: &Window,
 2364        cx: &App,
 2365    ) -> KeyContext {
 2366        let mut key_context = KeyContext::new_with_defaults();
 2367        key_context.add("Editor");
 2368        let mode = match self.mode {
 2369            EditorMode::SingleLine { .. } => "single_line",
 2370            EditorMode::AutoHeight { .. } => "auto_height",
 2371            EditorMode::Minimap { .. } => "minimap",
 2372            EditorMode::Full { .. } => "full",
 2373        };
 2374
 2375        if EditorSettings::jupyter_enabled(cx) {
 2376            key_context.add("jupyter");
 2377        }
 2378
 2379        key_context.set("mode", mode);
 2380        if self.pending_rename.is_some() {
 2381            key_context.add("renaming");
 2382        }
 2383
 2384        match self.context_menu.borrow().as_ref() {
 2385            Some(CodeContextMenu::Completions(menu)) => {
 2386                if menu.visible() {
 2387                    key_context.add("menu");
 2388                    key_context.add("showing_completions");
 2389                }
 2390            }
 2391            Some(CodeContextMenu::CodeActions(menu)) => {
 2392                if menu.visible() {
 2393                    key_context.add("menu");
 2394                    key_context.add("showing_code_actions")
 2395                }
 2396            }
 2397            None => {}
 2398        }
 2399
 2400        if self.signature_help_state.has_multiple_signatures() {
 2401            key_context.add("showing_signature_help");
 2402        }
 2403
 2404        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2405        if !self.focus_handle(cx).contains_focused(window, cx)
 2406            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2407        {
 2408            for addon in self.addons.values() {
 2409                addon.extend_key_context(&mut key_context, cx)
 2410            }
 2411        }
 2412
 2413        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2414            if let Some(extension) = singleton_buffer
 2415                .read(cx)
 2416                .file()
 2417                .and_then(|file| file.path().extension()?.to_str())
 2418            {
 2419                key_context.set("extension", extension.to_string());
 2420            }
 2421        } else {
 2422            key_context.add("multibuffer");
 2423        }
 2424
 2425        if has_active_edit_prediction {
 2426            if self.edit_prediction_in_conflict() {
 2427                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2428            } else {
 2429                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2430                key_context.add("copilot_suggestion");
 2431            }
 2432        }
 2433
 2434        if self.selection_mark_mode {
 2435            key_context.add("selection_mode");
 2436        }
 2437
 2438        key_context
 2439    }
 2440
 2441    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2442        if self.mouse_cursor_hidden {
 2443            self.mouse_cursor_hidden = false;
 2444            cx.notify();
 2445        }
 2446    }
 2447
 2448    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2449        let hide_mouse_cursor = match origin {
 2450            HideMouseCursorOrigin::TypingAction => {
 2451                matches!(
 2452                    self.hide_mouse_mode,
 2453                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2454                )
 2455            }
 2456            HideMouseCursorOrigin::MovementAction => {
 2457                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2458            }
 2459        };
 2460        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2461            self.mouse_cursor_hidden = hide_mouse_cursor;
 2462            cx.notify();
 2463        }
 2464    }
 2465
 2466    pub fn edit_prediction_in_conflict(&self) -> bool {
 2467        if !self.show_edit_predictions_in_menu() {
 2468            return false;
 2469        }
 2470
 2471        let showing_completions = self
 2472            .context_menu
 2473            .borrow()
 2474            .as_ref()
 2475            .map_or(false, |context| {
 2476                matches!(context, CodeContextMenu::Completions(_))
 2477            });
 2478
 2479        showing_completions
 2480            || self.edit_prediction_requires_modifier()
 2481            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2482            // bindings to insert tab characters.
 2483            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2484    }
 2485
 2486    pub fn accept_edit_prediction_keybind(
 2487        &self,
 2488        accept_partial: bool,
 2489        window: &Window,
 2490        cx: &App,
 2491    ) -> AcceptEditPredictionBinding {
 2492        let key_context = self.key_context_internal(true, window, cx);
 2493        let in_conflict = self.edit_prediction_in_conflict();
 2494
 2495        let bindings = if accept_partial {
 2496            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2497        } else {
 2498            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2499        };
 2500
 2501        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2502        // just the first one.
 2503        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2504            !in_conflict
 2505                || binding
 2506                    .keystrokes()
 2507                    .first()
 2508                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2509        }))
 2510    }
 2511
 2512    pub fn new_file(
 2513        workspace: &mut Workspace,
 2514        _: &workspace::NewFile,
 2515        window: &mut Window,
 2516        cx: &mut Context<Workspace>,
 2517    ) {
 2518        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2519            "Failed to create buffer",
 2520            window,
 2521            cx,
 2522            |e, _, _| match e.error_code() {
 2523                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2524                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2525                e.error_tag("required").unwrap_or("the latest version")
 2526            )),
 2527                _ => None,
 2528            },
 2529        );
 2530    }
 2531
 2532    pub fn new_in_workspace(
 2533        workspace: &mut Workspace,
 2534        window: &mut Window,
 2535        cx: &mut Context<Workspace>,
 2536    ) -> Task<Result<Entity<Editor>>> {
 2537        let project = workspace.project().clone();
 2538        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2539
 2540        cx.spawn_in(window, async move |workspace, cx| {
 2541            let buffer = create.await?;
 2542            workspace.update_in(cx, |workspace, window, cx| {
 2543                let editor =
 2544                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2545                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2546                editor
 2547            })
 2548        })
 2549    }
 2550
 2551    fn new_file_vertical(
 2552        workspace: &mut Workspace,
 2553        _: &workspace::NewFileSplitVertical,
 2554        window: &mut Window,
 2555        cx: &mut Context<Workspace>,
 2556    ) {
 2557        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2558    }
 2559
 2560    fn new_file_horizontal(
 2561        workspace: &mut Workspace,
 2562        _: &workspace::NewFileSplitHorizontal,
 2563        window: &mut Window,
 2564        cx: &mut Context<Workspace>,
 2565    ) {
 2566        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2567    }
 2568
 2569    fn new_file_in_direction(
 2570        workspace: &mut Workspace,
 2571        direction: SplitDirection,
 2572        window: &mut Window,
 2573        cx: &mut Context<Workspace>,
 2574    ) {
 2575        let project = workspace.project().clone();
 2576        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2577
 2578        cx.spawn_in(window, async move |workspace, cx| {
 2579            let buffer = create.await?;
 2580            workspace.update_in(cx, move |workspace, window, cx| {
 2581                workspace.split_item(
 2582                    direction,
 2583                    Box::new(
 2584                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2585                    ),
 2586                    window,
 2587                    cx,
 2588                )
 2589            })?;
 2590            anyhow::Ok(())
 2591        })
 2592        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2593            match e.error_code() {
 2594                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2595                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2596                e.error_tag("required").unwrap_or("the latest version")
 2597            )),
 2598                _ => None,
 2599            }
 2600        });
 2601    }
 2602
 2603    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2604        self.leader_id
 2605    }
 2606
 2607    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2608        &self.buffer
 2609    }
 2610
 2611    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2612        self.workspace.as_ref()?.0.upgrade()
 2613    }
 2614
 2615    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2616        self.buffer().read(cx).title(cx)
 2617    }
 2618
 2619    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2620        let git_blame_gutter_max_author_length = self
 2621            .render_git_blame_gutter(cx)
 2622            .then(|| {
 2623                if let Some(blame) = self.blame.as_ref() {
 2624                    let max_author_length =
 2625                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2626                    Some(max_author_length)
 2627                } else {
 2628                    None
 2629                }
 2630            })
 2631            .flatten();
 2632
 2633        EditorSnapshot {
 2634            mode: self.mode.clone(),
 2635            show_gutter: self.show_gutter,
 2636            show_line_numbers: self.show_line_numbers,
 2637            show_git_diff_gutter: self.show_git_diff_gutter,
 2638            show_code_actions: self.show_code_actions,
 2639            show_runnables: self.show_runnables,
 2640            show_breakpoints: self.show_breakpoints,
 2641            git_blame_gutter_max_author_length,
 2642            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2643            scroll_anchor: self.scroll_manager.anchor(),
 2644            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2645            placeholder_text: self.placeholder_text.clone(),
 2646            is_focused: self.focus_handle.is_focused(window),
 2647            current_line_highlight: self
 2648                .current_line_highlight
 2649                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2650            gutter_hovered: self.gutter_hovered,
 2651        }
 2652    }
 2653
 2654    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2655        self.buffer.read(cx).language_at(point, cx)
 2656    }
 2657
 2658    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2659        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2660    }
 2661
 2662    pub fn active_excerpt(
 2663        &self,
 2664        cx: &App,
 2665    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2666        self.buffer
 2667            .read(cx)
 2668            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2669    }
 2670
 2671    pub fn mode(&self) -> &EditorMode {
 2672        &self.mode
 2673    }
 2674
 2675    pub fn set_mode(&mut self, mode: EditorMode) {
 2676        self.mode = mode;
 2677    }
 2678
 2679    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2680        self.collaboration_hub.as_deref()
 2681    }
 2682
 2683    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2684        self.collaboration_hub = Some(hub);
 2685    }
 2686
 2687    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2688        self.in_project_search = in_project_search;
 2689    }
 2690
 2691    pub fn set_custom_context_menu(
 2692        &mut self,
 2693        f: impl 'static
 2694        + Fn(
 2695            &mut Self,
 2696            DisplayPoint,
 2697            &mut Window,
 2698            &mut Context<Self>,
 2699        ) -> Option<Entity<ui::ContextMenu>>,
 2700    ) {
 2701        self.custom_context_menu = Some(Box::new(f))
 2702    }
 2703
 2704    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2705        self.completion_provider = provider;
 2706    }
 2707
 2708    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2709        self.semantics_provider.clone()
 2710    }
 2711
 2712    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2713        self.semantics_provider = provider;
 2714    }
 2715
 2716    pub fn set_edit_prediction_provider<T>(
 2717        &mut self,
 2718        provider: Option<Entity<T>>,
 2719        window: &mut Window,
 2720        cx: &mut Context<Self>,
 2721    ) where
 2722        T: EditPredictionProvider,
 2723    {
 2724        self.edit_prediction_provider =
 2725            provider.map(|provider| RegisteredInlineCompletionProvider {
 2726                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2727                    if this.focus_handle.is_focused(window) {
 2728                        this.update_visible_inline_completion(window, cx);
 2729                    }
 2730                }),
 2731                provider: Arc::new(provider),
 2732            });
 2733        self.update_edit_prediction_settings(cx);
 2734        self.refresh_inline_completion(false, false, window, cx);
 2735    }
 2736
 2737    pub fn placeholder_text(&self) -> Option<&str> {
 2738        self.placeholder_text.as_deref()
 2739    }
 2740
 2741    pub fn set_placeholder_text(
 2742        &mut self,
 2743        placeholder_text: impl Into<Arc<str>>,
 2744        cx: &mut Context<Self>,
 2745    ) {
 2746        let placeholder_text = Some(placeholder_text.into());
 2747        if self.placeholder_text != placeholder_text {
 2748            self.placeholder_text = placeholder_text;
 2749            cx.notify();
 2750        }
 2751    }
 2752
 2753    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2754        self.cursor_shape = cursor_shape;
 2755
 2756        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2757        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2758
 2759        cx.notify();
 2760    }
 2761
 2762    pub fn set_current_line_highlight(
 2763        &mut self,
 2764        current_line_highlight: Option<CurrentLineHighlight>,
 2765    ) {
 2766        self.current_line_highlight = current_line_highlight;
 2767    }
 2768
 2769    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2770        self.collapse_matches = collapse_matches;
 2771    }
 2772
 2773    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2774        let buffers = self.buffer.read(cx).all_buffers();
 2775        let Some(project) = self.project.as_ref() else {
 2776            return;
 2777        };
 2778        project.update(cx, |project, cx| {
 2779            for buffer in buffers {
 2780                self.registered_buffers
 2781                    .entry(buffer.read(cx).remote_id())
 2782                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2783            }
 2784        })
 2785    }
 2786
 2787    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2788        if self.collapse_matches {
 2789            return range.start..range.start;
 2790        }
 2791        range.clone()
 2792    }
 2793
 2794    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2795        if self.display_map.read(cx).clip_at_line_ends != clip {
 2796            self.display_map
 2797                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2798        }
 2799    }
 2800
 2801    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2802        self.input_enabled = input_enabled;
 2803    }
 2804
 2805    pub fn set_inline_completions_hidden_for_vim_mode(
 2806        &mut self,
 2807        hidden: bool,
 2808        window: &mut Window,
 2809        cx: &mut Context<Self>,
 2810    ) {
 2811        if hidden != self.inline_completions_hidden_for_vim_mode {
 2812            self.inline_completions_hidden_for_vim_mode = hidden;
 2813            if hidden {
 2814                self.update_visible_inline_completion(window, cx);
 2815            } else {
 2816                self.refresh_inline_completion(true, false, window, cx);
 2817            }
 2818        }
 2819    }
 2820
 2821    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2822        self.menu_inline_completions_policy = value;
 2823    }
 2824
 2825    pub fn set_autoindent(&mut self, autoindent: bool) {
 2826        if autoindent {
 2827            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2828        } else {
 2829            self.autoindent_mode = None;
 2830        }
 2831    }
 2832
 2833    pub fn read_only(&self, cx: &App) -> bool {
 2834        self.read_only || self.buffer.read(cx).read_only()
 2835    }
 2836
 2837    pub fn set_read_only(&mut self, read_only: bool) {
 2838        self.read_only = read_only;
 2839    }
 2840
 2841    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2842        self.use_autoclose = autoclose;
 2843    }
 2844
 2845    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2846        self.use_auto_surround = auto_surround;
 2847    }
 2848
 2849    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2850        self.auto_replace_emoji_shortcode = auto_replace;
 2851    }
 2852
 2853    pub fn toggle_edit_predictions(
 2854        &mut self,
 2855        _: &ToggleEditPrediction,
 2856        window: &mut Window,
 2857        cx: &mut Context<Self>,
 2858    ) {
 2859        if self.show_inline_completions_override.is_some() {
 2860            self.set_show_edit_predictions(None, window, cx);
 2861        } else {
 2862            let show_edit_predictions = !self.edit_predictions_enabled();
 2863            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2864        }
 2865    }
 2866
 2867    pub fn set_show_edit_predictions(
 2868        &mut self,
 2869        show_edit_predictions: Option<bool>,
 2870        window: &mut Window,
 2871        cx: &mut Context<Self>,
 2872    ) {
 2873        self.show_inline_completions_override = show_edit_predictions;
 2874        self.update_edit_prediction_settings(cx);
 2875
 2876        if let Some(false) = show_edit_predictions {
 2877            self.discard_inline_completion(false, cx);
 2878        } else {
 2879            self.refresh_inline_completion(false, true, window, cx);
 2880        }
 2881    }
 2882
 2883    fn inline_completions_disabled_in_scope(
 2884        &self,
 2885        buffer: &Entity<Buffer>,
 2886        buffer_position: language::Anchor,
 2887        cx: &App,
 2888    ) -> bool {
 2889        let snapshot = buffer.read(cx).snapshot();
 2890        let settings = snapshot.settings_at(buffer_position, cx);
 2891
 2892        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2893            return false;
 2894        };
 2895
 2896        scope.override_name().map_or(false, |scope_name| {
 2897            settings
 2898                .edit_predictions_disabled_in
 2899                .iter()
 2900                .any(|s| s == scope_name)
 2901        })
 2902    }
 2903
 2904    pub fn set_use_modal_editing(&mut self, to: bool) {
 2905        self.use_modal_editing = to;
 2906    }
 2907
 2908    pub fn use_modal_editing(&self) -> bool {
 2909        self.use_modal_editing
 2910    }
 2911
 2912    fn selections_did_change(
 2913        &mut self,
 2914        local: bool,
 2915        old_cursor_position: &Anchor,
 2916        effects: SelectionEffects,
 2917        window: &mut Window,
 2918        cx: &mut Context<Self>,
 2919    ) {
 2920        window.invalidate_character_coordinates();
 2921
 2922        // Copy selections to primary selection buffer
 2923        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2924        if local {
 2925            let selections = self.selections.all::<usize>(cx);
 2926            let buffer_handle = self.buffer.read(cx).read(cx);
 2927
 2928            let mut text = String::new();
 2929            for (index, selection) in selections.iter().enumerate() {
 2930                let text_for_selection = buffer_handle
 2931                    .text_for_range(selection.start..selection.end)
 2932                    .collect::<String>();
 2933
 2934                text.push_str(&text_for_selection);
 2935                if index != selections.len() - 1 {
 2936                    text.push('\n');
 2937                }
 2938            }
 2939
 2940            if !text.is_empty() {
 2941                cx.write_to_primary(ClipboardItem::new_string(text));
 2942            }
 2943        }
 2944
 2945        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2946            self.buffer.update(cx, |buffer, cx| {
 2947                buffer.set_active_selections(
 2948                    &self.selections.disjoint_anchors(),
 2949                    self.selections.line_mode,
 2950                    self.cursor_shape,
 2951                    cx,
 2952                )
 2953            });
 2954        }
 2955        let display_map = self
 2956            .display_map
 2957            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2958        let buffer = &display_map.buffer_snapshot;
 2959        if self.selections.count() == 1 {
 2960            self.add_selections_state = None;
 2961        }
 2962        self.select_next_state = None;
 2963        self.select_prev_state = None;
 2964        self.select_syntax_node_history.try_clear();
 2965        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2966        self.snippet_stack
 2967            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2968        self.take_rename(false, window, cx);
 2969
 2970        let newest_selection = self.selections.newest_anchor();
 2971        let new_cursor_position = newest_selection.head();
 2972        let selection_start = newest_selection.start;
 2973
 2974        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2975            self.push_to_nav_history(
 2976                *old_cursor_position,
 2977                Some(new_cursor_position.to_point(buffer)),
 2978                false,
 2979                effects.nav_history == Some(true),
 2980                cx,
 2981            );
 2982        }
 2983
 2984        if local {
 2985            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2986                if !self.registered_buffers.contains_key(&buffer_id) {
 2987                    if let Some(project) = self.project.as_ref() {
 2988                        project.update(cx, |project, cx| {
 2989                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2990                                return;
 2991                            };
 2992                            self.registered_buffers.insert(
 2993                                buffer_id,
 2994                                project.register_buffer_with_language_servers(&buffer, cx),
 2995                            );
 2996                        })
 2997                    }
 2998                }
 2999            }
 3000
 3001            let mut context_menu = self.context_menu.borrow_mut();
 3002            let completion_menu = match context_menu.as_ref() {
 3003                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3004                Some(CodeContextMenu::CodeActions(_)) => {
 3005                    *context_menu = None;
 3006                    None
 3007                }
 3008                None => None,
 3009            };
 3010            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3011            drop(context_menu);
 3012
 3013            if effects.completions {
 3014                if let Some(completion_position) = completion_position {
 3015                    let start_offset = selection_start.to_offset(buffer);
 3016                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3017                    let continue_showing = if position_matches {
 3018                        if self.snippet_stack.is_empty() {
 3019                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3020                        } else {
 3021                            // Snippet choices can be shown even when the cursor is in whitespace.
 3022                            // Dismissing the menu with actions like backspace is handled by
 3023                            // invalidation regions.
 3024                            true
 3025                        }
 3026                    } else {
 3027                        false
 3028                    };
 3029
 3030                    if continue_showing {
 3031                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3032                    } else {
 3033                        self.hide_context_menu(window, cx);
 3034                    }
 3035                }
 3036            }
 3037
 3038            hide_hover(self, cx);
 3039
 3040            if old_cursor_position.to_display_point(&display_map).row()
 3041                != new_cursor_position.to_display_point(&display_map).row()
 3042            {
 3043                self.available_code_actions.take();
 3044            }
 3045            self.refresh_code_actions(window, cx);
 3046            self.refresh_document_highlights(cx);
 3047            self.refresh_selected_text_highlights(false, window, cx);
 3048            refresh_matching_bracket_highlights(self, window, cx);
 3049            self.update_visible_inline_completion(window, cx);
 3050            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3051            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3052            self.inline_blame_popover.take();
 3053            if self.git_blame_inline_enabled {
 3054                self.start_inline_blame_timer(window, cx);
 3055            }
 3056        }
 3057
 3058        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3059        cx.emit(EditorEvent::SelectionsChanged { local });
 3060
 3061        let selections = &self.selections.disjoint;
 3062        if selections.len() == 1 {
 3063            cx.emit(SearchEvent::ActiveMatchChanged)
 3064        }
 3065        if local {
 3066            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3067                let inmemory_selections = selections
 3068                    .iter()
 3069                    .map(|s| {
 3070                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3071                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3072                    })
 3073                    .collect();
 3074                self.update_restoration_data(cx, |data| {
 3075                    data.selections = inmemory_selections;
 3076                });
 3077
 3078                if WorkspaceSettings::get(None, cx).restore_on_startup
 3079                    != RestoreOnStartupBehavior::None
 3080                {
 3081                    if let Some(workspace_id) =
 3082                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3083                    {
 3084                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3085                        let selections = selections.clone();
 3086                        let background_executor = cx.background_executor().clone();
 3087                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3088                        self.serialize_selections = cx.background_spawn(async move {
 3089                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3090                            let db_selections = selections
 3091                                .iter()
 3092                                .map(|selection| {
 3093                                    (
 3094                                        selection.start.to_offset(&snapshot),
 3095                                        selection.end.to_offset(&snapshot),
 3096                                    )
 3097                                })
 3098                                .collect();
 3099
 3100                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3101                                .await
 3102                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3103                                .log_err();
 3104                        });
 3105                    }
 3106                }
 3107            }
 3108        }
 3109
 3110        cx.notify();
 3111    }
 3112
 3113    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3114        use text::ToOffset as _;
 3115        use text::ToPoint as _;
 3116
 3117        if self.mode.is_minimap()
 3118            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3119        {
 3120            return;
 3121        }
 3122
 3123        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3124            return;
 3125        };
 3126
 3127        let snapshot = singleton.read(cx).snapshot();
 3128        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3129            let display_snapshot = display_map.snapshot(cx);
 3130
 3131            display_snapshot
 3132                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3133                .map(|fold| {
 3134                    fold.range.start.text_anchor.to_point(&snapshot)
 3135                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3136                })
 3137                .collect()
 3138        });
 3139        self.update_restoration_data(cx, |data| {
 3140            data.folds = inmemory_folds;
 3141        });
 3142
 3143        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3144            return;
 3145        };
 3146        let background_executor = cx.background_executor().clone();
 3147        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3148        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3149            display_map
 3150                .snapshot(cx)
 3151                .folds_in_range(0..snapshot.len())
 3152                .map(|fold| {
 3153                    (
 3154                        fold.range.start.text_anchor.to_offset(&snapshot),
 3155                        fold.range.end.text_anchor.to_offset(&snapshot),
 3156                    )
 3157                })
 3158                .collect()
 3159        });
 3160        self.serialize_folds = cx.background_spawn(async move {
 3161            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3162            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3163                .await
 3164                .with_context(|| {
 3165                    format!(
 3166                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3167                    )
 3168                })
 3169                .log_err();
 3170        });
 3171    }
 3172
 3173    pub fn sync_selections(
 3174        &mut self,
 3175        other: Entity<Editor>,
 3176        cx: &mut Context<Self>,
 3177    ) -> gpui::Subscription {
 3178        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3179        self.selections.change_with(cx, |selections| {
 3180            selections.select_anchors(other_selections);
 3181        });
 3182
 3183        let other_subscription =
 3184            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3185                EditorEvent::SelectionsChanged { local: true } => {
 3186                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3187                    if other_selections.is_empty() {
 3188                        return;
 3189                    }
 3190                    this.selections.change_with(cx, |selections| {
 3191                        selections.select_anchors(other_selections);
 3192                    });
 3193                }
 3194                _ => {}
 3195            });
 3196
 3197        let this_subscription =
 3198            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3199                EditorEvent::SelectionsChanged { local: true } => {
 3200                    let these_selections = this.selections.disjoint.to_vec();
 3201                    if these_selections.is_empty() {
 3202                        return;
 3203                    }
 3204                    other.update(cx, |other_editor, cx| {
 3205                        other_editor.selections.change_with(cx, |selections| {
 3206                            selections.select_anchors(these_selections);
 3207                        })
 3208                    });
 3209                }
 3210                _ => {}
 3211            });
 3212
 3213        Subscription::join(other_subscription, this_subscription)
 3214    }
 3215
 3216    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3217    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3218    /// effects of selection change occur at the end of the transaction.
 3219    pub fn change_selections<R>(
 3220        &mut self,
 3221        effects: SelectionEffects,
 3222        window: &mut Window,
 3223        cx: &mut Context<Self>,
 3224        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3225    ) -> R {
 3226        if let Some(state) = &mut self.deferred_selection_effects_state {
 3227            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3228            state.effects.completions = effects.completions;
 3229            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3230            let (changed, result) = self.selections.change_with(cx, change);
 3231            state.changed |= changed;
 3232            return result;
 3233        }
 3234        let mut state = DeferredSelectionEffectsState {
 3235            changed: false,
 3236            effects,
 3237            old_cursor_position: self.selections.newest_anchor().head(),
 3238            history_entry: SelectionHistoryEntry {
 3239                selections: self.selections.disjoint_anchors(),
 3240                select_next_state: self.select_next_state.clone(),
 3241                select_prev_state: self.select_prev_state.clone(),
 3242                add_selections_state: self.add_selections_state.clone(),
 3243            },
 3244        };
 3245        let (changed, result) = self.selections.change_with(cx, change);
 3246        state.changed = state.changed || changed;
 3247        if self.defer_selection_effects {
 3248            self.deferred_selection_effects_state = Some(state);
 3249        } else {
 3250            self.apply_selection_effects(state, window, cx);
 3251        }
 3252        result
 3253    }
 3254
 3255    /// Defers the effects of selection change, so that the effects of multiple calls to
 3256    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3257    /// to selection history and the state of popovers based on selection position aren't
 3258    /// erroneously updated.
 3259    pub fn with_selection_effects_deferred<R>(
 3260        &mut self,
 3261        window: &mut Window,
 3262        cx: &mut Context<Self>,
 3263        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3264    ) -> R {
 3265        let already_deferred = self.defer_selection_effects;
 3266        self.defer_selection_effects = true;
 3267        let result = update(self, window, cx);
 3268        if !already_deferred {
 3269            self.defer_selection_effects = false;
 3270            if let Some(state) = self.deferred_selection_effects_state.take() {
 3271                self.apply_selection_effects(state, window, cx);
 3272            }
 3273        }
 3274        result
 3275    }
 3276
 3277    fn apply_selection_effects(
 3278        &mut self,
 3279        state: DeferredSelectionEffectsState,
 3280        window: &mut Window,
 3281        cx: &mut Context<Self>,
 3282    ) {
 3283        if state.changed {
 3284            self.selection_history.push(state.history_entry);
 3285
 3286            if let Some(autoscroll) = state.effects.scroll {
 3287                self.request_autoscroll(autoscroll, cx);
 3288            }
 3289
 3290            let old_cursor_position = &state.old_cursor_position;
 3291
 3292            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3293
 3294            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3295                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3296            }
 3297        }
 3298    }
 3299
 3300    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3301    where
 3302        I: IntoIterator<Item = (Range<S>, T)>,
 3303        S: ToOffset,
 3304        T: Into<Arc<str>>,
 3305    {
 3306        if self.read_only(cx) {
 3307            return;
 3308        }
 3309
 3310        self.buffer
 3311            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3312    }
 3313
 3314    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3315    where
 3316        I: IntoIterator<Item = (Range<S>, T)>,
 3317        S: ToOffset,
 3318        T: Into<Arc<str>>,
 3319    {
 3320        if self.read_only(cx) {
 3321            return;
 3322        }
 3323
 3324        self.buffer.update(cx, |buffer, cx| {
 3325            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3326        });
 3327    }
 3328
 3329    pub fn edit_with_block_indent<I, S, T>(
 3330        &mut self,
 3331        edits: I,
 3332        original_indent_columns: Vec<Option<u32>>,
 3333        cx: &mut Context<Self>,
 3334    ) where
 3335        I: IntoIterator<Item = (Range<S>, T)>,
 3336        S: ToOffset,
 3337        T: Into<Arc<str>>,
 3338    {
 3339        if self.read_only(cx) {
 3340            return;
 3341        }
 3342
 3343        self.buffer.update(cx, |buffer, cx| {
 3344            buffer.edit(
 3345                edits,
 3346                Some(AutoindentMode::Block {
 3347                    original_indent_columns,
 3348                }),
 3349                cx,
 3350            )
 3351        });
 3352    }
 3353
 3354    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3355        self.hide_context_menu(window, cx);
 3356
 3357        match phase {
 3358            SelectPhase::Begin {
 3359                position,
 3360                add,
 3361                click_count,
 3362            } => self.begin_selection(position, add, click_count, window, cx),
 3363            SelectPhase::BeginColumnar {
 3364                position,
 3365                goal_column,
 3366                reset,
 3367                mode,
 3368            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3369            SelectPhase::Extend {
 3370                position,
 3371                click_count,
 3372            } => self.extend_selection(position, click_count, window, cx),
 3373            SelectPhase::Update {
 3374                position,
 3375                goal_column,
 3376                scroll_delta,
 3377            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3378            SelectPhase::End => self.end_selection(window, cx),
 3379        }
 3380    }
 3381
 3382    fn extend_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        click_count: usize,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388    ) {
 3389        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3390        let tail = self.selections.newest::<usize>(cx).tail();
 3391        self.begin_selection(position, false, click_count, window, cx);
 3392
 3393        let position = position.to_offset(&display_map, Bias::Left);
 3394        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3395
 3396        let mut pending_selection = self
 3397            .selections
 3398            .pending_anchor()
 3399            .expect("extend_selection not called with pending selection");
 3400        if position >= tail {
 3401            pending_selection.start = tail_anchor;
 3402        } else {
 3403            pending_selection.end = tail_anchor;
 3404            pending_selection.reversed = true;
 3405        }
 3406
 3407        let mut pending_mode = self.selections.pending_mode().unwrap();
 3408        match &mut pending_mode {
 3409            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3410            _ => {}
 3411        }
 3412
 3413        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3414            SelectionEffects::scroll(Autoscroll::fit())
 3415        } else {
 3416            SelectionEffects::no_scroll()
 3417        };
 3418
 3419        self.change_selections(effects, window, cx, |s| {
 3420            s.set_pending(pending_selection, pending_mode)
 3421        });
 3422    }
 3423
 3424    fn begin_selection(
 3425        &mut self,
 3426        position: DisplayPoint,
 3427        add: bool,
 3428        click_count: usize,
 3429        window: &mut Window,
 3430        cx: &mut Context<Self>,
 3431    ) {
 3432        if !self.focus_handle.is_focused(window) {
 3433            self.last_focused_descendant = None;
 3434            window.focus(&self.focus_handle);
 3435        }
 3436
 3437        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3438        let buffer = &display_map.buffer_snapshot;
 3439        let position = display_map.clip_point(position, Bias::Left);
 3440
 3441        let start;
 3442        let end;
 3443        let mode;
 3444        let mut auto_scroll;
 3445        match click_count {
 3446            1 => {
 3447                start = buffer.anchor_before(position.to_point(&display_map));
 3448                end = start;
 3449                mode = SelectMode::Character;
 3450                auto_scroll = true;
 3451            }
 3452            2 => {
 3453                let position = display_map
 3454                    .clip_point(position, Bias::Left)
 3455                    .to_offset(&display_map, Bias::Left);
 3456                let (range, _) = buffer.surrounding_word(position, false);
 3457                start = buffer.anchor_before(range.start);
 3458                end = buffer.anchor_before(range.end);
 3459                mode = SelectMode::Word(start..end);
 3460                auto_scroll = true;
 3461            }
 3462            3 => {
 3463                let position = display_map
 3464                    .clip_point(position, Bias::Left)
 3465                    .to_point(&display_map);
 3466                let line_start = display_map.prev_line_boundary(position).0;
 3467                let next_line_start = buffer.clip_point(
 3468                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3469                    Bias::Left,
 3470                );
 3471                start = buffer.anchor_before(line_start);
 3472                end = buffer.anchor_before(next_line_start);
 3473                mode = SelectMode::Line(start..end);
 3474                auto_scroll = true;
 3475            }
 3476            _ => {
 3477                start = buffer.anchor_before(0);
 3478                end = buffer.anchor_before(buffer.len());
 3479                mode = SelectMode::All;
 3480                auto_scroll = false;
 3481            }
 3482        }
 3483        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3484
 3485        let point_to_delete: Option<usize> = {
 3486            let selected_points: Vec<Selection<Point>> =
 3487                self.selections.disjoint_in_range(start..end, cx);
 3488
 3489            if !add || click_count > 1 {
 3490                None
 3491            } else if !selected_points.is_empty() {
 3492                Some(selected_points[0].id)
 3493            } else {
 3494                let clicked_point_already_selected =
 3495                    self.selections.disjoint.iter().find(|selection| {
 3496                        selection.start.to_point(buffer) == start.to_point(buffer)
 3497                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3498                    });
 3499
 3500                clicked_point_already_selected.map(|selection| selection.id)
 3501            }
 3502        };
 3503
 3504        let selections_count = self.selections.count();
 3505        let effects = if auto_scroll {
 3506            SelectionEffects::default()
 3507        } else {
 3508            SelectionEffects::no_scroll()
 3509        };
 3510
 3511        self.change_selections(effects, window, cx, |s| {
 3512            if let Some(point_to_delete) = point_to_delete {
 3513                s.delete(point_to_delete);
 3514
 3515                if selections_count == 1 {
 3516                    s.set_pending_anchor_range(start..end, mode);
 3517                }
 3518            } else {
 3519                if !add {
 3520                    s.clear_disjoint();
 3521                }
 3522
 3523                s.set_pending_anchor_range(start..end, mode);
 3524            }
 3525        });
 3526    }
 3527
 3528    fn begin_columnar_selection(
 3529        &mut self,
 3530        position: DisplayPoint,
 3531        goal_column: u32,
 3532        reset: bool,
 3533        mode: ColumnarMode,
 3534        window: &mut Window,
 3535        cx: &mut Context<Self>,
 3536    ) {
 3537        if !self.focus_handle.is_focused(window) {
 3538            self.last_focused_descendant = None;
 3539            window.focus(&self.focus_handle);
 3540        }
 3541
 3542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3543
 3544        if reset {
 3545            let pointer_position = display_map
 3546                .buffer_snapshot
 3547                .anchor_before(position.to_point(&display_map));
 3548
 3549            self.change_selections(
 3550                SelectionEffects::scroll(Autoscroll::newest()),
 3551                window,
 3552                cx,
 3553                |s| {
 3554                    s.clear_disjoint();
 3555                    s.set_pending_anchor_range(
 3556                        pointer_position..pointer_position,
 3557                        SelectMode::Character,
 3558                    );
 3559                },
 3560            );
 3561        };
 3562
 3563        let tail = self.selections.newest::<Point>(cx).tail();
 3564        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3565        self.columnar_selection_state = match mode {
 3566            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3567                selection_tail: selection_anchor,
 3568                display_point: if reset {
 3569                    if position.column() != goal_column {
 3570                        Some(DisplayPoint::new(position.row(), goal_column))
 3571                    } else {
 3572                        None
 3573                    }
 3574                } else {
 3575                    None
 3576                },
 3577            }),
 3578            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3579                selection_tail: selection_anchor,
 3580            }),
 3581        };
 3582
 3583        if !reset {
 3584            self.select_columns(position, goal_column, &display_map, window, cx);
 3585        }
 3586    }
 3587
 3588    fn update_selection(
 3589        &mut self,
 3590        position: DisplayPoint,
 3591        goal_column: u32,
 3592        scroll_delta: gpui::Point<f32>,
 3593        window: &mut Window,
 3594        cx: &mut Context<Self>,
 3595    ) {
 3596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3597
 3598        if self.columnar_selection_state.is_some() {
 3599            self.select_columns(position, goal_column, &display_map, window, cx);
 3600        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3601            let buffer = &display_map.buffer_snapshot;
 3602            let head;
 3603            let tail;
 3604            let mode = self.selections.pending_mode().unwrap();
 3605            match &mode {
 3606                SelectMode::Character => {
 3607                    head = position.to_point(&display_map);
 3608                    tail = pending.tail().to_point(buffer);
 3609                }
 3610                SelectMode::Word(original_range) => {
 3611                    let offset = display_map
 3612                        .clip_point(position, Bias::Left)
 3613                        .to_offset(&display_map, Bias::Left);
 3614                    let original_range = original_range.to_offset(buffer);
 3615
 3616                    let head_offset = if buffer.is_inside_word(offset, false)
 3617                        || original_range.contains(&offset)
 3618                    {
 3619                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3620                        if word_range.start < original_range.start {
 3621                            word_range.start
 3622                        } else {
 3623                            word_range.end
 3624                        }
 3625                    } else {
 3626                        offset
 3627                    };
 3628
 3629                    head = head_offset.to_point(buffer);
 3630                    if head_offset <= original_range.start {
 3631                        tail = original_range.end.to_point(buffer);
 3632                    } else {
 3633                        tail = original_range.start.to_point(buffer);
 3634                    }
 3635                }
 3636                SelectMode::Line(original_range) => {
 3637                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3638
 3639                    let position = display_map
 3640                        .clip_point(position, Bias::Left)
 3641                        .to_point(&display_map);
 3642                    let line_start = display_map.prev_line_boundary(position).0;
 3643                    let next_line_start = buffer.clip_point(
 3644                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3645                        Bias::Left,
 3646                    );
 3647
 3648                    if line_start < original_range.start {
 3649                        head = line_start
 3650                    } else {
 3651                        head = next_line_start
 3652                    }
 3653
 3654                    if head <= original_range.start {
 3655                        tail = original_range.end;
 3656                    } else {
 3657                        tail = original_range.start;
 3658                    }
 3659                }
 3660                SelectMode::All => {
 3661                    return;
 3662                }
 3663            };
 3664
 3665            if head < tail {
 3666                pending.start = buffer.anchor_before(head);
 3667                pending.end = buffer.anchor_before(tail);
 3668                pending.reversed = true;
 3669            } else {
 3670                pending.start = buffer.anchor_before(tail);
 3671                pending.end = buffer.anchor_before(head);
 3672                pending.reversed = false;
 3673            }
 3674
 3675            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3676                s.set_pending(pending, mode);
 3677            });
 3678        } else {
 3679            log::error!("update_selection dispatched with no pending selection");
 3680            return;
 3681        }
 3682
 3683        self.apply_scroll_delta(scroll_delta, window, cx);
 3684        cx.notify();
 3685    }
 3686
 3687    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3688        self.columnar_selection_state.take();
 3689        if self.selections.pending_anchor().is_some() {
 3690            let selections = self.selections.all::<usize>(cx);
 3691            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3692                s.select(selections);
 3693                s.clear_pending();
 3694            });
 3695        }
 3696    }
 3697
 3698    fn select_columns(
 3699        &mut self,
 3700        head: DisplayPoint,
 3701        goal_column: u32,
 3702        display_map: &DisplaySnapshot,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3707            return;
 3708        };
 3709
 3710        let tail = match columnar_state {
 3711            ColumnarSelectionState::FromMouse {
 3712                selection_tail,
 3713                display_point,
 3714            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3715            ColumnarSelectionState::FromSelection { selection_tail } => {
 3716                selection_tail.to_display_point(&display_map)
 3717            }
 3718        };
 3719
 3720        let start_row = cmp::min(tail.row(), head.row());
 3721        let end_row = cmp::max(tail.row(), head.row());
 3722        let start_column = cmp::min(tail.column(), goal_column);
 3723        let end_column = cmp::max(tail.column(), goal_column);
 3724        let reversed = start_column < tail.column();
 3725
 3726        let selection_ranges = (start_row.0..=end_row.0)
 3727            .map(DisplayRow)
 3728            .filter_map(|row| {
 3729                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3730                    || start_column <= display_map.line_len(row))
 3731                    && !display_map.is_block_line(row)
 3732                {
 3733                    let start = display_map
 3734                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3735                        .to_point(display_map);
 3736                    let end = display_map
 3737                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3738                        .to_point(display_map);
 3739                    if reversed {
 3740                        Some(end..start)
 3741                    } else {
 3742                        Some(start..end)
 3743                    }
 3744                } else {
 3745                    None
 3746                }
 3747            })
 3748            .collect::<Vec<_>>();
 3749
 3750        let ranges = match columnar_state {
 3751            ColumnarSelectionState::FromMouse { .. } => {
 3752                let mut non_empty_ranges = selection_ranges
 3753                    .iter()
 3754                    .filter(|selection_range| selection_range.start != selection_range.end)
 3755                    .peekable();
 3756                if non_empty_ranges.peek().is_some() {
 3757                    non_empty_ranges.cloned().collect()
 3758                } else {
 3759                    selection_ranges
 3760                }
 3761            }
 3762            _ => selection_ranges,
 3763        };
 3764
 3765        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3766            s.select_ranges(ranges);
 3767        });
 3768        cx.notify();
 3769    }
 3770
 3771    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3772        self.selections
 3773            .all_adjusted(cx)
 3774            .iter()
 3775            .any(|selection| !selection.is_empty())
 3776    }
 3777
 3778    pub fn has_pending_nonempty_selection(&self) -> bool {
 3779        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3780            Some(Selection { start, end, .. }) => start != end,
 3781            None => false,
 3782        };
 3783
 3784        pending_nonempty_selection
 3785            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3786    }
 3787
 3788    pub fn has_pending_selection(&self) -> bool {
 3789        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3790    }
 3791
 3792    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3793        self.selection_mark_mode = false;
 3794        self.selection_drag_state = SelectionDragState::None;
 3795
 3796        if self.clear_expanded_diff_hunks(cx) {
 3797            cx.notify();
 3798            return;
 3799        }
 3800        if self.dismiss_menus_and_popups(true, window, cx) {
 3801            return;
 3802        }
 3803
 3804        if self.mode.is_full()
 3805            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3806        {
 3807            return;
 3808        }
 3809
 3810        cx.propagate();
 3811    }
 3812
 3813    pub fn dismiss_menus_and_popups(
 3814        &mut self,
 3815        is_user_requested: bool,
 3816        window: &mut Window,
 3817        cx: &mut Context<Self>,
 3818    ) -> bool {
 3819        if self.take_rename(false, window, cx).is_some() {
 3820            return true;
 3821        }
 3822
 3823        if hide_hover(self, cx) {
 3824            return true;
 3825        }
 3826
 3827        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3828            return true;
 3829        }
 3830
 3831        if self.hide_context_menu(window, cx).is_some() {
 3832            return true;
 3833        }
 3834
 3835        if self.mouse_context_menu.take().is_some() {
 3836            return true;
 3837        }
 3838
 3839        if is_user_requested && self.discard_inline_completion(true, cx) {
 3840            return true;
 3841        }
 3842
 3843        if self.snippet_stack.pop().is_some() {
 3844            return true;
 3845        }
 3846
 3847        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3848            self.dismiss_diagnostics(cx);
 3849            return true;
 3850        }
 3851
 3852        false
 3853    }
 3854
 3855    fn linked_editing_ranges_for(
 3856        &self,
 3857        selection: Range<text::Anchor>,
 3858        cx: &App,
 3859    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3860        if self.linked_edit_ranges.is_empty() {
 3861            return None;
 3862        }
 3863        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3864            selection.end.buffer_id.and_then(|end_buffer_id| {
 3865                if selection.start.buffer_id != Some(end_buffer_id) {
 3866                    return None;
 3867                }
 3868                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3869                let snapshot = buffer.read(cx).snapshot();
 3870                self.linked_edit_ranges
 3871                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3872                    .map(|ranges| (ranges, snapshot, buffer))
 3873            })?;
 3874        use text::ToOffset as TO;
 3875        // find offset from the start of current range to current cursor position
 3876        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3877
 3878        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3879        let start_difference = start_offset - start_byte_offset;
 3880        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3881        let end_difference = end_offset - start_byte_offset;
 3882        // Current range has associated linked ranges.
 3883        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3884        for range in linked_ranges.iter() {
 3885            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3886            let end_offset = start_offset + end_difference;
 3887            let start_offset = start_offset + start_difference;
 3888            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3889                continue;
 3890            }
 3891            if self.selections.disjoint_anchor_ranges().any(|s| {
 3892                if s.start.buffer_id != selection.start.buffer_id
 3893                    || s.end.buffer_id != selection.end.buffer_id
 3894                {
 3895                    return false;
 3896                }
 3897                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3898                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3899            }) {
 3900                continue;
 3901            }
 3902            let start = buffer_snapshot.anchor_after(start_offset);
 3903            let end = buffer_snapshot.anchor_after(end_offset);
 3904            linked_edits
 3905                .entry(buffer.clone())
 3906                .or_default()
 3907                .push(start..end);
 3908        }
 3909        Some(linked_edits)
 3910    }
 3911
 3912    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3913        let text: Arc<str> = text.into();
 3914
 3915        if self.read_only(cx) {
 3916            return;
 3917        }
 3918
 3919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3920
 3921        let selections = self.selections.all_adjusted(cx);
 3922        let mut bracket_inserted = false;
 3923        let mut edits = Vec::new();
 3924        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3925        let mut new_selections = Vec::with_capacity(selections.len());
 3926        let mut new_autoclose_regions = Vec::new();
 3927        let snapshot = self.buffer.read(cx).read(cx);
 3928        let mut clear_linked_edit_ranges = false;
 3929
 3930        for (selection, autoclose_region) in
 3931            self.selections_with_autoclose_regions(selections, &snapshot)
 3932        {
 3933            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3934                // Determine if the inserted text matches the opening or closing
 3935                // bracket of any of this language's bracket pairs.
 3936                let mut bracket_pair = None;
 3937                let mut is_bracket_pair_start = false;
 3938                let mut is_bracket_pair_end = false;
 3939                if !text.is_empty() {
 3940                    let mut bracket_pair_matching_end = None;
 3941                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3942                    //  and they are removing the character that triggered IME popup.
 3943                    for (pair, enabled) in scope.brackets() {
 3944                        if !pair.close && !pair.surround {
 3945                            continue;
 3946                        }
 3947
 3948                        if enabled && pair.start.ends_with(text.as_ref()) {
 3949                            let prefix_len = pair.start.len() - text.len();
 3950                            let preceding_text_matches_prefix = prefix_len == 0
 3951                                || (selection.start.column >= (prefix_len as u32)
 3952                                    && snapshot.contains_str_at(
 3953                                        Point::new(
 3954                                            selection.start.row,
 3955                                            selection.start.column - (prefix_len as u32),
 3956                                        ),
 3957                                        &pair.start[..prefix_len],
 3958                                    ));
 3959                            if preceding_text_matches_prefix {
 3960                                bracket_pair = Some(pair.clone());
 3961                                is_bracket_pair_start = true;
 3962                                break;
 3963                            }
 3964                        }
 3965                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3966                        {
 3967                            // take first bracket pair matching end, but don't break in case a later bracket
 3968                            // pair matches start
 3969                            bracket_pair_matching_end = Some(pair.clone());
 3970                        }
 3971                    }
 3972                    if let Some(end) = bracket_pair_matching_end
 3973                        && bracket_pair.is_none()
 3974                    {
 3975                        bracket_pair = Some(end);
 3976                        is_bracket_pair_end = true;
 3977                    }
 3978                }
 3979
 3980                if let Some(bracket_pair) = bracket_pair {
 3981                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3982                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3983                    let auto_surround =
 3984                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3985                    if selection.is_empty() {
 3986                        if is_bracket_pair_start {
 3987                            // If the inserted text is a suffix of an opening bracket and the
 3988                            // selection is preceded by the rest of the opening bracket, then
 3989                            // insert the closing bracket.
 3990                            let following_text_allows_autoclose = snapshot
 3991                                .chars_at(selection.start)
 3992                                .next()
 3993                                .map_or(true, |c| scope.should_autoclose_before(c));
 3994
 3995                            let preceding_text_allows_autoclose = selection.start.column == 0
 3996                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3997                                    true,
 3998                                    |c| {
 3999                                        bracket_pair.start != bracket_pair.end
 4000                                            || !snapshot
 4001                                                .char_classifier_at(selection.start)
 4002                                                .is_word(c)
 4003                                    },
 4004                                );
 4005
 4006                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4007                                && bracket_pair.start.len() == 1
 4008                            {
 4009                                let target = bracket_pair.start.chars().next().unwrap();
 4010                                let current_line_count = snapshot
 4011                                    .reversed_chars_at(selection.start)
 4012                                    .take_while(|&c| c != '\n')
 4013                                    .filter(|&c| c == target)
 4014                                    .count();
 4015                                current_line_count % 2 == 1
 4016                            } else {
 4017                                false
 4018                            };
 4019
 4020                            if autoclose
 4021                                && bracket_pair.close
 4022                                && following_text_allows_autoclose
 4023                                && preceding_text_allows_autoclose
 4024                                && !is_closing_quote
 4025                            {
 4026                                let anchor = snapshot.anchor_before(selection.end);
 4027                                new_selections.push((selection.map(|_| anchor), text.len()));
 4028                                new_autoclose_regions.push((
 4029                                    anchor,
 4030                                    text.len(),
 4031                                    selection.id,
 4032                                    bracket_pair.clone(),
 4033                                ));
 4034                                edits.push((
 4035                                    selection.range(),
 4036                                    format!("{}{}", text, bracket_pair.end).into(),
 4037                                ));
 4038                                bracket_inserted = true;
 4039                                continue;
 4040                            }
 4041                        }
 4042
 4043                        if let Some(region) = autoclose_region {
 4044                            // If the selection is followed by an auto-inserted closing bracket,
 4045                            // then don't insert that closing bracket again; just move the selection
 4046                            // past the closing bracket.
 4047                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4048                                && text.as_ref() == region.pair.end.as_str();
 4049                            if should_skip {
 4050                                let anchor = snapshot.anchor_after(selection.end);
 4051                                new_selections
 4052                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4053                                continue;
 4054                            }
 4055                        }
 4056
 4057                        let always_treat_brackets_as_autoclosed = snapshot
 4058                            .language_settings_at(selection.start, cx)
 4059                            .always_treat_brackets_as_autoclosed;
 4060                        if always_treat_brackets_as_autoclosed
 4061                            && is_bracket_pair_end
 4062                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4063                        {
 4064                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4065                            // and the inserted text is a closing bracket and the selection is followed
 4066                            // by the closing bracket then move the selection past the closing bracket.
 4067                            let anchor = snapshot.anchor_after(selection.end);
 4068                            new_selections.push((selection.map(|_| anchor), text.len()));
 4069                            continue;
 4070                        }
 4071                    }
 4072                    // If an opening bracket is 1 character long and is typed while
 4073                    // text is selected, then surround that text with the bracket pair.
 4074                    else if auto_surround
 4075                        && bracket_pair.surround
 4076                        && is_bracket_pair_start
 4077                        && bracket_pair.start.chars().count() == 1
 4078                    {
 4079                        edits.push((selection.start..selection.start, text.clone()));
 4080                        edits.push((
 4081                            selection.end..selection.end,
 4082                            bracket_pair.end.as_str().into(),
 4083                        ));
 4084                        bracket_inserted = true;
 4085                        new_selections.push((
 4086                            Selection {
 4087                                id: selection.id,
 4088                                start: snapshot.anchor_after(selection.start),
 4089                                end: snapshot.anchor_before(selection.end),
 4090                                reversed: selection.reversed,
 4091                                goal: selection.goal,
 4092                            },
 4093                            0,
 4094                        ));
 4095                        continue;
 4096                    }
 4097                }
 4098            }
 4099
 4100            if self.auto_replace_emoji_shortcode
 4101                && selection.is_empty()
 4102                && text.as_ref().ends_with(':')
 4103            {
 4104                if let Some(possible_emoji_short_code) =
 4105                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4106                {
 4107                    if !possible_emoji_short_code.is_empty() {
 4108                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4109                            let emoji_shortcode_start = Point::new(
 4110                                selection.start.row,
 4111                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4112                            );
 4113
 4114                            // Remove shortcode from buffer
 4115                            edits.push((
 4116                                emoji_shortcode_start..selection.start,
 4117                                "".to_string().into(),
 4118                            ));
 4119                            new_selections.push((
 4120                                Selection {
 4121                                    id: selection.id,
 4122                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4123                                    end: snapshot.anchor_before(selection.start),
 4124                                    reversed: selection.reversed,
 4125                                    goal: selection.goal,
 4126                                },
 4127                                0,
 4128                            ));
 4129
 4130                            // Insert emoji
 4131                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4132                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4133                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4134
 4135                            continue;
 4136                        }
 4137                    }
 4138                }
 4139            }
 4140
 4141            // If not handling any auto-close operation, then just replace the selected
 4142            // text with the given input and move the selection to the end of the
 4143            // newly inserted text.
 4144            let anchor = snapshot.anchor_after(selection.end);
 4145            if !self.linked_edit_ranges.is_empty() {
 4146                let start_anchor = snapshot.anchor_before(selection.start);
 4147
 4148                let is_word_char = text.chars().next().map_or(true, |char| {
 4149                    let classifier = snapshot
 4150                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4151                        .ignore_punctuation(true);
 4152                    classifier.is_word(char)
 4153                });
 4154
 4155                if is_word_char {
 4156                    if let Some(ranges) = self
 4157                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4158                    {
 4159                        for (buffer, edits) in ranges {
 4160                            linked_edits
 4161                                .entry(buffer.clone())
 4162                                .or_default()
 4163                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4164                        }
 4165                    }
 4166                } else {
 4167                    clear_linked_edit_ranges = true;
 4168                }
 4169            }
 4170
 4171            new_selections.push((selection.map(|_| anchor), 0));
 4172            edits.push((selection.start..selection.end, text.clone()));
 4173        }
 4174
 4175        drop(snapshot);
 4176
 4177        self.transact(window, cx, |this, window, cx| {
 4178            if clear_linked_edit_ranges {
 4179                this.linked_edit_ranges.clear();
 4180            }
 4181            let initial_buffer_versions =
 4182                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4183
 4184            this.buffer.update(cx, |buffer, cx| {
 4185                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4186            });
 4187            for (buffer, edits) in linked_edits {
 4188                buffer.update(cx, |buffer, cx| {
 4189                    let snapshot = buffer.snapshot();
 4190                    let edits = edits
 4191                        .into_iter()
 4192                        .map(|(range, text)| {
 4193                            use text::ToPoint as TP;
 4194                            let end_point = TP::to_point(&range.end, &snapshot);
 4195                            let start_point = TP::to_point(&range.start, &snapshot);
 4196                            (start_point..end_point, text)
 4197                        })
 4198                        .sorted_by_key(|(range, _)| range.start);
 4199                    buffer.edit(edits, None, cx);
 4200                })
 4201            }
 4202            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4203            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4204            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4205            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4206                .zip(new_selection_deltas)
 4207                .map(|(selection, delta)| Selection {
 4208                    id: selection.id,
 4209                    start: selection.start + delta,
 4210                    end: selection.end + delta,
 4211                    reversed: selection.reversed,
 4212                    goal: SelectionGoal::None,
 4213                })
 4214                .collect::<Vec<_>>();
 4215
 4216            let mut i = 0;
 4217            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4218                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4219                let start = map.buffer_snapshot.anchor_before(position);
 4220                let end = map.buffer_snapshot.anchor_after(position);
 4221                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4222                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4223                        Ordering::Less => i += 1,
 4224                        Ordering::Greater => break,
 4225                        Ordering::Equal => {
 4226                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4227                                Ordering::Less => i += 1,
 4228                                Ordering::Equal => break,
 4229                                Ordering::Greater => break,
 4230                            }
 4231                        }
 4232                    }
 4233                }
 4234                this.autoclose_regions.insert(
 4235                    i,
 4236                    AutocloseRegion {
 4237                        selection_id,
 4238                        range: start..end,
 4239                        pair,
 4240                    },
 4241                );
 4242            }
 4243
 4244            let had_active_inline_completion = this.has_active_inline_completion();
 4245            this.change_selections(
 4246                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4247                window,
 4248                cx,
 4249                |s| s.select(new_selections),
 4250            );
 4251
 4252            if !bracket_inserted {
 4253                if let Some(on_type_format_task) =
 4254                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4255                {
 4256                    on_type_format_task.detach_and_log_err(cx);
 4257                }
 4258            }
 4259
 4260            let editor_settings = EditorSettings::get_global(cx);
 4261            if bracket_inserted
 4262                && (editor_settings.auto_signature_help
 4263                    || editor_settings.show_signature_help_after_edits)
 4264            {
 4265                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4266            }
 4267
 4268            let trigger_in_words =
 4269                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4270            if this.hard_wrap.is_some() {
 4271                let latest: Range<Point> = this.selections.newest(cx).range();
 4272                if latest.is_empty()
 4273                    && this
 4274                        .buffer()
 4275                        .read(cx)
 4276                        .snapshot(cx)
 4277                        .line_len(MultiBufferRow(latest.start.row))
 4278                        == latest.start.column
 4279                {
 4280                    this.rewrap_impl(
 4281                        RewrapOptions {
 4282                            override_language_settings: true,
 4283                            preserve_existing_whitespace: true,
 4284                        },
 4285                        cx,
 4286                    )
 4287                }
 4288            }
 4289            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4290            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4291            this.refresh_inline_completion(true, false, window, cx);
 4292            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4293        });
 4294    }
 4295
 4296    fn find_possible_emoji_shortcode_at_position(
 4297        snapshot: &MultiBufferSnapshot,
 4298        position: Point,
 4299    ) -> Option<String> {
 4300        let mut chars = Vec::new();
 4301        let mut found_colon = false;
 4302        for char in snapshot.reversed_chars_at(position).take(100) {
 4303            // Found a possible emoji shortcode in the middle of the buffer
 4304            if found_colon {
 4305                if char.is_whitespace() {
 4306                    chars.reverse();
 4307                    return Some(chars.iter().collect());
 4308                }
 4309                // If the previous character is not a whitespace, we are in the middle of a word
 4310                // and we only want to complete the shortcode if the word is made up of other emojis
 4311                let mut containing_word = String::new();
 4312                for ch in snapshot
 4313                    .reversed_chars_at(position)
 4314                    .skip(chars.len() + 1)
 4315                    .take(100)
 4316                {
 4317                    if ch.is_whitespace() {
 4318                        break;
 4319                    }
 4320                    containing_word.push(ch);
 4321                }
 4322                let containing_word = containing_word.chars().rev().collect::<String>();
 4323                if util::word_consists_of_emojis(containing_word.as_str()) {
 4324                    chars.reverse();
 4325                    return Some(chars.iter().collect());
 4326                }
 4327            }
 4328
 4329            if char.is_whitespace() || !char.is_ascii() {
 4330                return None;
 4331            }
 4332            if char == ':' {
 4333                found_colon = true;
 4334            } else {
 4335                chars.push(char);
 4336            }
 4337        }
 4338        // Found a possible emoji shortcode at the beginning of the buffer
 4339        chars.reverse();
 4340        Some(chars.iter().collect())
 4341    }
 4342
 4343    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4344        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4345        self.transact(window, cx, |this, window, cx| {
 4346            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4347                let selections = this.selections.all::<usize>(cx);
 4348                let multi_buffer = this.buffer.read(cx);
 4349                let buffer = multi_buffer.snapshot(cx);
 4350                selections
 4351                    .iter()
 4352                    .map(|selection| {
 4353                        let start_point = selection.start.to_point(&buffer);
 4354                        let mut existing_indent =
 4355                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4356                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4357                        let start = selection.start;
 4358                        let end = selection.end;
 4359                        let selection_is_empty = start == end;
 4360                        let language_scope = buffer.language_scope_at(start);
 4361                        let (
 4362                            comment_delimiter,
 4363                            doc_delimiter,
 4364                            insert_extra_newline,
 4365                            indent_on_newline,
 4366                            indent_on_extra_newline,
 4367                        ) = if let Some(language) = &language_scope {
 4368                            let mut insert_extra_newline =
 4369                                insert_extra_newline_brackets(&buffer, start..end, language)
 4370                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4371
 4372                            // Comment extension on newline is allowed only for cursor selections
 4373                            let comment_delimiter = maybe!({
 4374                                if !selection_is_empty {
 4375                                    return None;
 4376                                }
 4377
 4378                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4379                                    return None;
 4380                                }
 4381
 4382                                let delimiters = language.line_comment_prefixes();
 4383                                let max_len_of_delimiter =
 4384                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4385                                let (snapshot, range) =
 4386                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4387
 4388                                let num_of_whitespaces = snapshot
 4389                                    .chars_for_range(range.clone())
 4390                                    .take_while(|c| c.is_whitespace())
 4391                                    .count();
 4392                                let comment_candidate = snapshot
 4393                                    .chars_for_range(range.clone())
 4394                                    .skip(num_of_whitespaces)
 4395                                    .take(max_len_of_delimiter)
 4396                                    .collect::<String>();
 4397                                let (delimiter, trimmed_len) = delimiters
 4398                                    .iter()
 4399                                    .filter_map(|delimiter| {
 4400                                        let prefix = delimiter.trim_end();
 4401                                        if comment_candidate.starts_with(prefix) {
 4402                                            Some((delimiter, prefix.len()))
 4403                                        } else {
 4404                                            None
 4405                                        }
 4406                                    })
 4407                                    .max_by_key(|(_, len)| *len)?;
 4408
 4409                                if let Some((block_start, _)) = language.block_comment_delimiters()
 4410                                {
 4411                                    let block_start_trimmed = block_start.trim_end();
 4412                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4413                                        let line_content = snapshot
 4414                                            .chars_for_range(range)
 4415                                            .skip(num_of_whitespaces)
 4416                                            .take(block_start_trimmed.len())
 4417                                            .collect::<String>();
 4418
 4419                                        if line_content.starts_with(block_start_trimmed) {
 4420                                            return None;
 4421                                        }
 4422                                    }
 4423                                }
 4424
 4425                                let cursor_is_placed_after_comment_marker =
 4426                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4427                                if cursor_is_placed_after_comment_marker {
 4428                                    Some(delimiter.clone())
 4429                                } else {
 4430                                    None
 4431                                }
 4432                            });
 4433
 4434                            let mut indent_on_newline = IndentSize::spaces(0);
 4435                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4436
 4437                            let doc_delimiter = maybe!({
 4438                                if !selection_is_empty {
 4439                                    return None;
 4440                                }
 4441
 4442                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4443                                    return None;
 4444                                }
 4445
 4446                                let DocumentationConfig {
 4447                                    start: start_tag,
 4448                                    end: end_tag,
 4449                                    prefix: delimiter,
 4450                                    tab_size: len,
 4451                                } = language.documentation()?;
 4452
 4453                                let is_within_block_comment = buffer
 4454                                    .language_scope_at(start_point)
 4455                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4456                                if !is_within_block_comment {
 4457                                    return None;
 4458                                }
 4459
 4460                                let (snapshot, range) =
 4461                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4462
 4463                                let num_of_whitespaces = snapshot
 4464                                    .chars_for_range(range.clone())
 4465                                    .take_while(|c| c.is_whitespace())
 4466                                    .count();
 4467
 4468                                // 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.
 4469                                let column = start_point.column;
 4470                                let cursor_is_after_start_tag = {
 4471                                    let start_tag_len = start_tag.len();
 4472                                    let start_tag_line = snapshot
 4473                                        .chars_for_range(range.clone())
 4474                                        .skip(num_of_whitespaces)
 4475                                        .take(start_tag_len)
 4476                                        .collect::<String>();
 4477                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4478                                        num_of_whitespaces + start_tag_len <= column as usize
 4479                                    } else {
 4480                                        false
 4481                                    }
 4482                                };
 4483
 4484                                let cursor_is_after_delimiter = {
 4485                                    let delimiter_trim = delimiter.trim_end();
 4486                                    let delimiter_line = snapshot
 4487                                        .chars_for_range(range.clone())
 4488                                        .skip(num_of_whitespaces)
 4489                                        .take(delimiter_trim.len())
 4490                                        .collect::<String>();
 4491                                    if delimiter_line.starts_with(delimiter_trim) {
 4492                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4493                                    } else {
 4494                                        false
 4495                                    }
 4496                                };
 4497
 4498                                let cursor_is_before_end_tag_if_exists = {
 4499                                    let mut char_position = 0u32;
 4500                                    let mut end_tag_offset = None;
 4501
 4502                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4503                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4504                                            let chars_before_match =
 4505                                                chunk[..byte_pos].chars().count() as u32;
 4506                                            end_tag_offset =
 4507                                                Some(char_position + chars_before_match);
 4508                                            break 'outer;
 4509                                        }
 4510                                        char_position += chunk.chars().count() as u32;
 4511                                    }
 4512
 4513                                    if let Some(end_tag_offset) = end_tag_offset {
 4514                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4515                                        if cursor_is_after_start_tag {
 4516                                            if cursor_is_before_end_tag {
 4517                                                insert_extra_newline = true;
 4518                                            }
 4519                                            let cursor_is_at_start_of_end_tag =
 4520                                                column == end_tag_offset;
 4521                                            if cursor_is_at_start_of_end_tag {
 4522                                                indent_on_extra_newline.len = (*len).into();
 4523                                            }
 4524                                        }
 4525                                        cursor_is_before_end_tag
 4526                                    } else {
 4527                                        true
 4528                                    }
 4529                                };
 4530
 4531                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4532                                    && cursor_is_before_end_tag_if_exists
 4533                                {
 4534                                    if cursor_is_after_start_tag {
 4535                                        indent_on_newline.len = (*len).into();
 4536                                    }
 4537                                    Some(delimiter.clone())
 4538                                } else {
 4539                                    None
 4540                                }
 4541                            });
 4542
 4543                            (
 4544                                comment_delimiter,
 4545                                doc_delimiter,
 4546                                insert_extra_newline,
 4547                                indent_on_newline,
 4548                                indent_on_extra_newline,
 4549                            )
 4550                        } else {
 4551                            (
 4552                                None,
 4553                                None,
 4554                                false,
 4555                                IndentSize::default(),
 4556                                IndentSize::default(),
 4557                            )
 4558                        };
 4559
 4560                        let prevent_auto_indent = doc_delimiter.is_some();
 4561                        let delimiter = comment_delimiter.or(doc_delimiter);
 4562
 4563                        let capacity_for_delimiter =
 4564                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4565                        let mut new_text = String::with_capacity(
 4566                            1 + capacity_for_delimiter
 4567                                + existing_indent.len as usize
 4568                                + indent_on_newline.len as usize
 4569                                + indent_on_extra_newline.len as usize,
 4570                        );
 4571                        new_text.push('\n');
 4572                        new_text.extend(existing_indent.chars());
 4573                        new_text.extend(indent_on_newline.chars());
 4574
 4575                        if let Some(delimiter) = &delimiter {
 4576                            new_text.push_str(delimiter);
 4577                        }
 4578
 4579                        if insert_extra_newline {
 4580                            new_text.push('\n');
 4581                            new_text.extend(existing_indent.chars());
 4582                            new_text.extend(indent_on_extra_newline.chars());
 4583                        }
 4584
 4585                        let anchor = buffer.anchor_after(end);
 4586                        let new_selection = selection.map(|_| anchor);
 4587                        (
 4588                            ((start..end, new_text), prevent_auto_indent),
 4589                            (insert_extra_newline, new_selection),
 4590                        )
 4591                    })
 4592                    .unzip()
 4593            };
 4594
 4595            let mut auto_indent_edits = Vec::new();
 4596            let mut edits = Vec::new();
 4597            for (edit, prevent_auto_indent) in edits_with_flags {
 4598                if prevent_auto_indent {
 4599                    edits.push(edit);
 4600                } else {
 4601                    auto_indent_edits.push(edit);
 4602                }
 4603            }
 4604            if !edits.is_empty() {
 4605                this.edit(edits, cx);
 4606            }
 4607            if !auto_indent_edits.is_empty() {
 4608                this.edit_with_autoindent(auto_indent_edits, cx);
 4609            }
 4610
 4611            let buffer = this.buffer.read(cx).snapshot(cx);
 4612            let new_selections = selection_info
 4613                .into_iter()
 4614                .map(|(extra_newline_inserted, new_selection)| {
 4615                    let mut cursor = new_selection.end.to_point(&buffer);
 4616                    if extra_newline_inserted {
 4617                        cursor.row -= 1;
 4618                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4619                    }
 4620                    new_selection.map(|_| cursor)
 4621                })
 4622                .collect();
 4623
 4624            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4625            this.refresh_inline_completion(true, false, window, cx);
 4626        });
 4627    }
 4628
 4629    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4631
 4632        let buffer = self.buffer.read(cx);
 4633        let snapshot = buffer.snapshot(cx);
 4634
 4635        let mut edits = Vec::new();
 4636        let mut rows = Vec::new();
 4637
 4638        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4639            let cursor = selection.head();
 4640            let row = cursor.row;
 4641
 4642            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4643
 4644            let newline = "\n".to_string();
 4645            edits.push((start_of_line..start_of_line, newline));
 4646
 4647            rows.push(row + rows_inserted as u32);
 4648        }
 4649
 4650        self.transact(window, cx, |editor, window, cx| {
 4651            editor.edit(edits, cx);
 4652
 4653            editor.change_selections(Default::default(), window, cx, |s| {
 4654                let mut index = 0;
 4655                s.move_cursors_with(|map, _, _| {
 4656                    let row = rows[index];
 4657                    index += 1;
 4658
 4659                    let point = Point::new(row, 0);
 4660                    let boundary = map.next_line_boundary(point).1;
 4661                    let clipped = map.clip_point(boundary, Bias::Left);
 4662
 4663                    (clipped, SelectionGoal::None)
 4664                });
 4665            });
 4666
 4667            let mut indent_edits = Vec::new();
 4668            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4669            for row in rows {
 4670                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4671                for (row, indent) in indents {
 4672                    if indent.len == 0 {
 4673                        continue;
 4674                    }
 4675
 4676                    let text = match indent.kind {
 4677                        IndentKind::Space => " ".repeat(indent.len as usize),
 4678                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4679                    };
 4680                    let point = Point::new(row.0, 0);
 4681                    indent_edits.push((point..point, text));
 4682                }
 4683            }
 4684            editor.edit(indent_edits, cx);
 4685        });
 4686    }
 4687
 4688    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4689        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4690
 4691        let buffer = self.buffer.read(cx);
 4692        let snapshot = buffer.snapshot(cx);
 4693
 4694        let mut edits = Vec::new();
 4695        let mut rows = Vec::new();
 4696        let mut rows_inserted = 0;
 4697
 4698        for selection in self.selections.all_adjusted(cx) {
 4699            let cursor = selection.head();
 4700            let row = cursor.row;
 4701
 4702            let point = Point::new(row + 1, 0);
 4703            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4704
 4705            let newline = "\n".to_string();
 4706            edits.push((start_of_line..start_of_line, newline));
 4707
 4708            rows_inserted += 1;
 4709            rows.push(row + rows_inserted);
 4710        }
 4711
 4712        self.transact(window, cx, |editor, window, cx| {
 4713            editor.edit(edits, cx);
 4714
 4715            editor.change_selections(Default::default(), window, cx, |s| {
 4716                let mut index = 0;
 4717                s.move_cursors_with(|map, _, _| {
 4718                    let row = rows[index];
 4719                    index += 1;
 4720
 4721                    let point = Point::new(row, 0);
 4722                    let boundary = map.next_line_boundary(point).1;
 4723                    let clipped = map.clip_point(boundary, Bias::Left);
 4724
 4725                    (clipped, SelectionGoal::None)
 4726                });
 4727            });
 4728
 4729            let mut indent_edits = Vec::new();
 4730            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4731            for row in rows {
 4732                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4733                for (row, indent) in indents {
 4734                    if indent.len == 0 {
 4735                        continue;
 4736                    }
 4737
 4738                    let text = match indent.kind {
 4739                        IndentKind::Space => " ".repeat(indent.len as usize),
 4740                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4741                    };
 4742                    let point = Point::new(row.0, 0);
 4743                    indent_edits.push((point..point, text));
 4744                }
 4745            }
 4746            editor.edit(indent_edits, cx);
 4747        });
 4748    }
 4749
 4750    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4751        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4752            original_indent_columns: Vec::new(),
 4753        });
 4754        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4755    }
 4756
 4757    fn insert_with_autoindent_mode(
 4758        &mut self,
 4759        text: &str,
 4760        autoindent_mode: Option<AutoindentMode>,
 4761        window: &mut Window,
 4762        cx: &mut Context<Self>,
 4763    ) {
 4764        if self.read_only(cx) {
 4765            return;
 4766        }
 4767
 4768        let text: Arc<str> = text.into();
 4769        self.transact(window, cx, |this, window, cx| {
 4770            let old_selections = this.selections.all_adjusted(cx);
 4771            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4772                let anchors = {
 4773                    let snapshot = buffer.read(cx);
 4774                    old_selections
 4775                        .iter()
 4776                        .map(|s| {
 4777                            let anchor = snapshot.anchor_after(s.head());
 4778                            s.map(|_| anchor)
 4779                        })
 4780                        .collect::<Vec<_>>()
 4781                };
 4782                buffer.edit(
 4783                    old_selections
 4784                        .iter()
 4785                        .map(|s| (s.start..s.end, text.clone())),
 4786                    autoindent_mode,
 4787                    cx,
 4788                );
 4789                anchors
 4790            });
 4791
 4792            this.change_selections(Default::default(), window, cx, |s| {
 4793                s.select_anchors(selection_anchors);
 4794            });
 4795
 4796            cx.notify();
 4797        });
 4798    }
 4799
 4800    fn trigger_completion_on_input(
 4801        &mut self,
 4802        text: &str,
 4803        trigger_in_words: bool,
 4804        window: &mut Window,
 4805        cx: &mut Context<Self>,
 4806    ) {
 4807        let completions_source = self
 4808            .context_menu
 4809            .borrow()
 4810            .as_ref()
 4811            .and_then(|menu| match menu {
 4812                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4813                CodeContextMenu::CodeActions(_) => None,
 4814            });
 4815
 4816        match completions_source {
 4817            Some(CompletionsMenuSource::Words) => {
 4818                self.show_word_completions(&ShowWordCompletions, window, cx)
 4819            }
 4820            Some(CompletionsMenuSource::Normal)
 4821            | Some(CompletionsMenuSource::SnippetChoices)
 4822            | None
 4823                if self.is_completion_trigger(
 4824                    text,
 4825                    trigger_in_words,
 4826                    completions_source.is_some(),
 4827                    cx,
 4828                ) =>
 4829            {
 4830                self.show_completions(
 4831                    &ShowCompletions {
 4832                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4833                    },
 4834                    window,
 4835                    cx,
 4836                )
 4837            }
 4838            _ => {
 4839                self.hide_context_menu(window, cx);
 4840            }
 4841        }
 4842    }
 4843
 4844    fn is_completion_trigger(
 4845        &self,
 4846        text: &str,
 4847        trigger_in_words: bool,
 4848        menu_is_open: bool,
 4849        cx: &mut Context<Self>,
 4850    ) -> bool {
 4851        let position = self.selections.newest_anchor().head();
 4852        let multibuffer = self.buffer.read(cx);
 4853        let Some(buffer) = position
 4854            .buffer_id
 4855            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4856        else {
 4857            return false;
 4858        };
 4859
 4860        if let Some(completion_provider) = &self.completion_provider {
 4861            completion_provider.is_completion_trigger(
 4862                &buffer,
 4863                position.text_anchor,
 4864                text,
 4865                trigger_in_words,
 4866                menu_is_open,
 4867                cx,
 4868            )
 4869        } else {
 4870            false
 4871        }
 4872    }
 4873
 4874    /// If any empty selections is touching the start of its innermost containing autoclose
 4875    /// region, expand it to select the brackets.
 4876    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4877        let selections = self.selections.all::<usize>(cx);
 4878        let buffer = self.buffer.read(cx).read(cx);
 4879        let new_selections = self
 4880            .selections_with_autoclose_regions(selections, &buffer)
 4881            .map(|(mut selection, region)| {
 4882                if !selection.is_empty() {
 4883                    return selection;
 4884                }
 4885
 4886                if let Some(region) = region {
 4887                    let mut range = region.range.to_offset(&buffer);
 4888                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4889                        range.start -= region.pair.start.len();
 4890                        if buffer.contains_str_at(range.start, &region.pair.start)
 4891                            && buffer.contains_str_at(range.end, &region.pair.end)
 4892                        {
 4893                            range.end += region.pair.end.len();
 4894                            selection.start = range.start;
 4895                            selection.end = range.end;
 4896
 4897                            return selection;
 4898                        }
 4899                    }
 4900                }
 4901
 4902                let always_treat_brackets_as_autoclosed = buffer
 4903                    .language_settings_at(selection.start, cx)
 4904                    .always_treat_brackets_as_autoclosed;
 4905
 4906                if !always_treat_brackets_as_autoclosed {
 4907                    return selection;
 4908                }
 4909
 4910                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4911                    for (pair, enabled) in scope.brackets() {
 4912                        if !enabled || !pair.close {
 4913                            continue;
 4914                        }
 4915
 4916                        if buffer.contains_str_at(selection.start, &pair.end) {
 4917                            let pair_start_len = pair.start.len();
 4918                            if buffer.contains_str_at(
 4919                                selection.start.saturating_sub(pair_start_len),
 4920                                &pair.start,
 4921                            ) {
 4922                                selection.start -= pair_start_len;
 4923                                selection.end += pair.end.len();
 4924
 4925                                return selection;
 4926                            }
 4927                        }
 4928                    }
 4929                }
 4930
 4931                selection
 4932            })
 4933            .collect();
 4934
 4935        drop(buffer);
 4936        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4937            selections.select(new_selections)
 4938        });
 4939    }
 4940
 4941    /// Iterate the given selections, and for each one, find the smallest surrounding
 4942    /// autoclose region. This uses the ordering of the selections and the autoclose
 4943    /// regions to avoid repeated comparisons.
 4944    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4945        &'a self,
 4946        selections: impl IntoIterator<Item = Selection<D>>,
 4947        buffer: &'a MultiBufferSnapshot,
 4948    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4949        let mut i = 0;
 4950        let mut regions = self.autoclose_regions.as_slice();
 4951        selections.into_iter().map(move |selection| {
 4952            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4953
 4954            let mut enclosing = None;
 4955            while let Some(pair_state) = regions.get(i) {
 4956                if pair_state.range.end.to_offset(buffer) < range.start {
 4957                    regions = &regions[i + 1..];
 4958                    i = 0;
 4959                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4960                    break;
 4961                } else {
 4962                    if pair_state.selection_id == selection.id {
 4963                        enclosing = Some(pair_state);
 4964                    }
 4965                    i += 1;
 4966                }
 4967            }
 4968
 4969            (selection, enclosing)
 4970        })
 4971    }
 4972
 4973    /// Remove any autoclose regions that no longer contain their selection.
 4974    fn invalidate_autoclose_regions(
 4975        &mut self,
 4976        mut selections: &[Selection<Anchor>],
 4977        buffer: &MultiBufferSnapshot,
 4978    ) {
 4979        self.autoclose_regions.retain(|state| {
 4980            let mut i = 0;
 4981            while let Some(selection) = selections.get(i) {
 4982                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4983                    selections = &selections[1..];
 4984                    continue;
 4985                }
 4986                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4987                    break;
 4988                }
 4989                if selection.id == state.selection_id {
 4990                    return true;
 4991                } else {
 4992                    i += 1;
 4993                }
 4994            }
 4995            false
 4996        });
 4997    }
 4998
 4999    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5000        let offset = position.to_offset(buffer);
 5001        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5002        if offset > word_range.start && kind == Some(CharKind::Word) {
 5003            Some(
 5004                buffer
 5005                    .text_for_range(word_range.start..offset)
 5006                    .collect::<String>(),
 5007            )
 5008        } else {
 5009            None
 5010        }
 5011    }
 5012
 5013    pub fn toggle_inline_values(
 5014        &mut self,
 5015        _: &ToggleInlineValues,
 5016        _: &mut Window,
 5017        cx: &mut Context<Self>,
 5018    ) {
 5019        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5020
 5021        self.refresh_inline_values(cx);
 5022    }
 5023
 5024    pub fn toggle_inlay_hints(
 5025        &mut self,
 5026        _: &ToggleInlayHints,
 5027        _: &mut Window,
 5028        cx: &mut Context<Self>,
 5029    ) {
 5030        self.refresh_inlay_hints(
 5031            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5032            cx,
 5033        );
 5034    }
 5035
 5036    pub fn inlay_hints_enabled(&self) -> bool {
 5037        self.inlay_hint_cache.enabled
 5038    }
 5039
 5040    pub fn inline_values_enabled(&self) -> bool {
 5041        self.inline_value_cache.enabled
 5042    }
 5043
 5044    #[cfg(any(test, feature = "test-support"))]
 5045    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5046        self.display_map
 5047            .read(cx)
 5048            .current_inlays()
 5049            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5050            .cloned()
 5051            .collect()
 5052    }
 5053
 5054    #[cfg(any(test, feature = "test-support"))]
 5055    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5056        self.display_map
 5057            .read(cx)
 5058            .current_inlays()
 5059            .cloned()
 5060            .collect()
 5061    }
 5062
 5063    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5064        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5065            return;
 5066        }
 5067
 5068        let reason_description = reason.description();
 5069        let ignore_debounce = matches!(
 5070            reason,
 5071            InlayHintRefreshReason::SettingsChange(_)
 5072                | InlayHintRefreshReason::Toggle(_)
 5073                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5074                | InlayHintRefreshReason::ModifiersChanged(_)
 5075        );
 5076        let (invalidate_cache, required_languages) = match reason {
 5077            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5078                match self.inlay_hint_cache.modifiers_override(enabled) {
 5079                    Some(enabled) => {
 5080                        if enabled {
 5081                            (InvalidationStrategy::RefreshRequested, None)
 5082                        } else {
 5083                            self.splice_inlays(
 5084                                &self
 5085                                    .visible_inlay_hints(cx)
 5086                                    .iter()
 5087                                    .map(|inlay| inlay.id)
 5088                                    .collect::<Vec<InlayId>>(),
 5089                                Vec::new(),
 5090                                cx,
 5091                            );
 5092                            return;
 5093                        }
 5094                    }
 5095                    None => return,
 5096                }
 5097            }
 5098            InlayHintRefreshReason::Toggle(enabled) => {
 5099                if self.inlay_hint_cache.toggle(enabled) {
 5100                    if enabled {
 5101                        (InvalidationStrategy::RefreshRequested, None)
 5102                    } else {
 5103                        self.splice_inlays(
 5104                            &self
 5105                                .visible_inlay_hints(cx)
 5106                                .iter()
 5107                                .map(|inlay| inlay.id)
 5108                                .collect::<Vec<InlayId>>(),
 5109                            Vec::new(),
 5110                            cx,
 5111                        );
 5112                        return;
 5113                    }
 5114                } else {
 5115                    return;
 5116                }
 5117            }
 5118            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5119                match self.inlay_hint_cache.update_settings(
 5120                    &self.buffer,
 5121                    new_settings,
 5122                    self.visible_inlay_hints(cx),
 5123                    cx,
 5124                ) {
 5125                    ControlFlow::Break(Some(InlaySplice {
 5126                        to_remove,
 5127                        to_insert,
 5128                    })) => {
 5129                        self.splice_inlays(&to_remove, to_insert, cx);
 5130                        return;
 5131                    }
 5132                    ControlFlow::Break(None) => return,
 5133                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5134                }
 5135            }
 5136            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5137                if let Some(InlaySplice {
 5138                    to_remove,
 5139                    to_insert,
 5140                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5141                {
 5142                    self.splice_inlays(&to_remove, to_insert, cx);
 5143                }
 5144                self.display_map.update(cx, |display_map, _| {
 5145                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5146                });
 5147                return;
 5148            }
 5149            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5150            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5151                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5152            }
 5153            InlayHintRefreshReason::RefreshRequested => {
 5154                (InvalidationStrategy::RefreshRequested, None)
 5155            }
 5156        };
 5157
 5158        if let Some(InlaySplice {
 5159            to_remove,
 5160            to_insert,
 5161        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5162            reason_description,
 5163            self.visible_excerpts(required_languages.as_ref(), cx),
 5164            invalidate_cache,
 5165            ignore_debounce,
 5166            cx,
 5167        ) {
 5168            self.splice_inlays(&to_remove, to_insert, cx);
 5169        }
 5170    }
 5171
 5172    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5173        self.display_map
 5174            .read(cx)
 5175            .current_inlays()
 5176            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5177            .cloned()
 5178            .collect()
 5179    }
 5180
 5181    pub fn visible_excerpts(
 5182        &self,
 5183        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5184        cx: &mut Context<Editor>,
 5185    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5186        let Some(project) = self.project.as_ref() else {
 5187            return HashMap::default();
 5188        };
 5189        let project = project.read(cx);
 5190        let multi_buffer = self.buffer().read(cx);
 5191        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5192        let multi_buffer_visible_start = self
 5193            .scroll_manager
 5194            .anchor()
 5195            .anchor
 5196            .to_point(&multi_buffer_snapshot);
 5197        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5198            multi_buffer_visible_start
 5199                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5200            Bias::Left,
 5201        );
 5202        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5203        multi_buffer_snapshot
 5204            .range_to_buffer_ranges(multi_buffer_visible_range)
 5205            .into_iter()
 5206            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5207            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5208                let buffer_file = project::File::from_dyn(buffer.file())?;
 5209                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5210                let worktree_entry = buffer_worktree
 5211                    .read(cx)
 5212                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5213                if worktree_entry.is_ignored {
 5214                    return None;
 5215                }
 5216
 5217                let language = buffer.language()?;
 5218                if let Some(restrict_to_languages) = restrict_to_languages {
 5219                    if !restrict_to_languages.contains(language) {
 5220                        return None;
 5221                    }
 5222                }
 5223                Some((
 5224                    excerpt_id,
 5225                    (
 5226                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5227                        buffer.version().clone(),
 5228                        excerpt_visible_range,
 5229                    ),
 5230                ))
 5231            })
 5232            .collect()
 5233    }
 5234
 5235    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5236        TextLayoutDetails {
 5237            text_system: window.text_system().clone(),
 5238            editor_style: self.style.clone().unwrap(),
 5239            rem_size: window.rem_size(),
 5240            scroll_anchor: self.scroll_manager.anchor(),
 5241            visible_rows: self.visible_line_count(),
 5242            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5243        }
 5244    }
 5245
 5246    pub fn splice_inlays(
 5247        &self,
 5248        to_remove: &[InlayId],
 5249        to_insert: Vec<Inlay>,
 5250        cx: &mut Context<Self>,
 5251    ) {
 5252        self.display_map.update(cx, |display_map, cx| {
 5253            display_map.splice_inlays(to_remove, to_insert, cx)
 5254        });
 5255        cx.notify();
 5256    }
 5257
 5258    fn trigger_on_type_formatting(
 5259        &self,
 5260        input: String,
 5261        window: &mut Window,
 5262        cx: &mut Context<Self>,
 5263    ) -> Option<Task<Result<()>>> {
 5264        if input.len() != 1 {
 5265            return None;
 5266        }
 5267
 5268        let project = self.project.as_ref()?;
 5269        let position = self.selections.newest_anchor().head();
 5270        let (buffer, buffer_position) = self
 5271            .buffer
 5272            .read(cx)
 5273            .text_anchor_for_position(position, cx)?;
 5274
 5275        let settings = language_settings::language_settings(
 5276            buffer
 5277                .read(cx)
 5278                .language_at(buffer_position)
 5279                .map(|l| l.name()),
 5280            buffer.read(cx).file(),
 5281            cx,
 5282        );
 5283        if !settings.use_on_type_format {
 5284            return None;
 5285        }
 5286
 5287        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5288        // hence we do LSP request & edit on host side only — add formats to host's history.
 5289        let push_to_lsp_host_history = true;
 5290        // If this is not the host, append its history with new edits.
 5291        let push_to_client_history = project.read(cx).is_via_collab();
 5292
 5293        let on_type_formatting = project.update(cx, |project, cx| {
 5294            project.on_type_format(
 5295                buffer.clone(),
 5296                buffer_position,
 5297                input,
 5298                push_to_lsp_host_history,
 5299                cx,
 5300            )
 5301        });
 5302        Some(cx.spawn_in(window, async move |editor, cx| {
 5303            if let Some(transaction) = on_type_formatting.await? {
 5304                if push_to_client_history {
 5305                    buffer
 5306                        .update(cx, |buffer, _| {
 5307                            buffer.push_transaction(transaction, Instant::now());
 5308                            buffer.finalize_last_transaction();
 5309                        })
 5310                        .ok();
 5311                }
 5312                editor.update(cx, |editor, cx| {
 5313                    editor.refresh_document_highlights(cx);
 5314                })?;
 5315            }
 5316            Ok(())
 5317        }))
 5318    }
 5319
 5320    pub fn show_word_completions(
 5321        &mut self,
 5322        _: &ShowWordCompletions,
 5323        window: &mut Window,
 5324        cx: &mut Context<Self>,
 5325    ) {
 5326        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5327    }
 5328
 5329    pub fn show_completions(
 5330        &mut self,
 5331        options: &ShowCompletions,
 5332        window: &mut Window,
 5333        cx: &mut Context<Self>,
 5334    ) {
 5335        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5336    }
 5337
 5338    fn open_or_update_completions_menu(
 5339        &mut self,
 5340        requested_source: Option<CompletionsMenuSource>,
 5341        trigger: Option<&str>,
 5342        window: &mut Window,
 5343        cx: &mut Context<Self>,
 5344    ) {
 5345        if self.pending_rename.is_some() {
 5346            return;
 5347        }
 5348
 5349        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5350
 5351        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5352        // inserted and selected. To handle that case, the start of the selection is used so that
 5353        // the menu starts with all choices.
 5354        let position = self
 5355            .selections
 5356            .newest_anchor()
 5357            .start
 5358            .bias_right(&multibuffer_snapshot);
 5359        if position.diff_base_anchor.is_some() {
 5360            return;
 5361        }
 5362        let (buffer, buffer_position) =
 5363            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5364                output
 5365            } else {
 5366                return;
 5367            };
 5368        let buffer_snapshot = buffer.read(cx).snapshot();
 5369
 5370        let query: Option<Arc<String>> =
 5371            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5372
 5373        drop(multibuffer_snapshot);
 5374
 5375        let provider = match requested_source {
 5376            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5377            Some(CompletionsMenuSource::Words) => None,
 5378            Some(CompletionsMenuSource::SnippetChoices) => {
 5379                log::error!("bug: SnippetChoices requested_source is not handled");
 5380                None
 5381            }
 5382        };
 5383
 5384        let sort_completions = provider
 5385            .as_ref()
 5386            .map_or(false, |provider| provider.sort_completions());
 5387
 5388        let filter_completions = provider
 5389            .as_ref()
 5390            .map_or(true, |provider| provider.filter_completions());
 5391
 5392        let trigger_kind = match trigger {
 5393            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5394                CompletionTriggerKind::TRIGGER_CHARACTER
 5395            }
 5396            _ => CompletionTriggerKind::INVOKED,
 5397        };
 5398        let completion_context = CompletionContext {
 5399            trigger_character: trigger.and_then(|trigger| {
 5400                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5401                    Some(String::from(trigger))
 5402                } else {
 5403                    None
 5404                }
 5405            }),
 5406            trigger_kind,
 5407        };
 5408
 5409        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5410        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5411        // involve trigger chars, so this is skipped in that case.
 5412        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5413        {
 5414            let menu_is_open = matches!(
 5415                self.context_menu.borrow().as_ref(),
 5416                Some(CodeContextMenu::Completions(_))
 5417            );
 5418            if menu_is_open {
 5419                self.hide_context_menu(window, cx);
 5420            }
 5421        }
 5422
 5423        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5424            if filter_completions {
 5425                menu.filter(query.clone(), provider.clone(), window, cx);
 5426            }
 5427            // When `is_incomplete` is false, no need to re-query completions when the current query
 5428            // is a suffix of the initial query.
 5429            if !menu.is_incomplete {
 5430                // If the new query is a suffix of the old query (typing more characters) and
 5431                // the previous result was complete, the existing completions can be filtered.
 5432                //
 5433                // Note that this is always true for snippet completions.
 5434                let query_matches = match (&menu.initial_query, &query) {
 5435                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5436                    (None, _) => true,
 5437                    _ => false,
 5438                };
 5439                if query_matches {
 5440                    let position_matches = if menu.initial_position == position {
 5441                        true
 5442                    } else {
 5443                        let snapshot = self.buffer.read(cx).read(cx);
 5444                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5445                    };
 5446                    if position_matches {
 5447                        return;
 5448                    }
 5449                }
 5450            }
 5451        };
 5452
 5453        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5454            buffer_snapshot.surrounding_word(buffer_position, false)
 5455        {
 5456            let word_to_exclude = buffer_snapshot
 5457                .text_for_range(word_range.clone())
 5458                .collect::<String>();
 5459            (
 5460                buffer_snapshot.anchor_before(word_range.start)
 5461                    ..buffer_snapshot.anchor_after(buffer_position),
 5462                Some(word_to_exclude),
 5463            )
 5464        } else {
 5465            (buffer_position..buffer_position, None)
 5466        };
 5467
 5468        let language = buffer_snapshot
 5469            .language_at(buffer_position)
 5470            .map(|language| language.name());
 5471
 5472        let completion_settings =
 5473            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5474
 5475        let show_completion_documentation = buffer_snapshot
 5476            .settings_at(buffer_position, cx)
 5477            .show_completion_documentation;
 5478
 5479        // The document can be large, so stay in reasonable bounds when searching for words,
 5480        // otherwise completion pop-up might be slow to appear.
 5481        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5482        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5483        let min_word_search = buffer_snapshot.clip_point(
 5484            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5485            Bias::Left,
 5486        );
 5487        let max_word_search = buffer_snapshot.clip_point(
 5488            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5489            Bias::Right,
 5490        );
 5491        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5492            ..buffer_snapshot.point_to_offset(max_word_search);
 5493
 5494        let skip_digits = query
 5495            .as_ref()
 5496            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5497
 5498        let (mut words, provider_responses) = match &provider {
 5499            Some(provider) => {
 5500                let provider_responses = provider.completions(
 5501                    position.excerpt_id,
 5502                    &buffer,
 5503                    buffer_position,
 5504                    completion_context,
 5505                    window,
 5506                    cx,
 5507                );
 5508
 5509                let words = match completion_settings.words {
 5510                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5511                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5512                        .background_spawn(async move {
 5513                            buffer_snapshot.words_in_range(WordsQuery {
 5514                                fuzzy_contents: None,
 5515                                range: word_search_range,
 5516                                skip_digits,
 5517                            })
 5518                        }),
 5519                };
 5520
 5521                (words, provider_responses)
 5522            }
 5523            None => (
 5524                cx.background_spawn(async move {
 5525                    buffer_snapshot.words_in_range(WordsQuery {
 5526                        fuzzy_contents: None,
 5527                        range: word_search_range,
 5528                        skip_digits,
 5529                    })
 5530                }),
 5531                Task::ready(Ok(Vec::new())),
 5532            ),
 5533        };
 5534
 5535        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5536
 5537        let id = post_inc(&mut self.next_completion_id);
 5538        let task = cx.spawn_in(window, async move |editor, cx| {
 5539            let Ok(()) = editor.update(cx, |this, _| {
 5540                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5541            }) else {
 5542                return;
 5543            };
 5544
 5545            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5546            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5547            let mut completions = Vec::new();
 5548            let mut is_incomplete = false;
 5549            if let Some(provider_responses) = provider_responses.await.log_err() {
 5550                if !provider_responses.is_empty() {
 5551                    for response in provider_responses {
 5552                        completions.extend(response.completions);
 5553                        is_incomplete = is_incomplete || response.is_incomplete;
 5554                    }
 5555                    if completion_settings.words == WordsCompletionMode::Fallback {
 5556                        words = Task::ready(BTreeMap::default());
 5557                    }
 5558                }
 5559            }
 5560
 5561            let mut words = words.await;
 5562            if let Some(word_to_exclude) = &word_to_exclude {
 5563                words.remove(word_to_exclude);
 5564            }
 5565            for lsp_completion in &completions {
 5566                words.remove(&lsp_completion.new_text);
 5567            }
 5568            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5569                replace_range: word_replace_range.clone(),
 5570                new_text: word.clone(),
 5571                label: CodeLabel::plain(word, None),
 5572                icon_path: None,
 5573                documentation: None,
 5574                source: CompletionSource::BufferWord {
 5575                    word_range,
 5576                    resolved: false,
 5577                },
 5578                insert_text_mode: Some(InsertTextMode::AS_IS),
 5579                confirm: None,
 5580            }));
 5581
 5582            let menu = if completions.is_empty() {
 5583                None
 5584            } else {
 5585                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5586                    let languages = editor
 5587                        .workspace
 5588                        .as_ref()
 5589                        .and_then(|(workspace, _)| workspace.upgrade())
 5590                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5591                    let menu = CompletionsMenu::new(
 5592                        id,
 5593                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5594                        sort_completions,
 5595                        show_completion_documentation,
 5596                        position,
 5597                        query.clone(),
 5598                        is_incomplete,
 5599                        buffer.clone(),
 5600                        completions.into(),
 5601                        snippet_sort_order,
 5602                        languages,
 5603                        language,
 5604                        cx,
 5605                    );
 5606
 5607                    let query = if filter_completions { query } else { None };
 5608                    let matches_task = if let Some(query) = query {
 5609                        menu.do_async_filtering(query, cx)
 5610                    } else {
 5611                        Task::ready(menu.unfiltered_matches())
 5612                    };
 5613                    (menu, matches_task)
 5614                }) else {
 5615                    return;
 5616                };
 5617
 5618                let matches = matches_task.await;
 5619
 5620                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5621                    // Newer menu already set, so exit.
 5622                    match editor.context_menu.borrow().as_ref() {
 5623                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5624                            if prev_menu.id > id {
 5625                                return;
 5626                            }
 5627                        }
 5628                        _ => {}
 5629                    };
 5630
 5631                    // Only valid to take prev_menu because it the new menu is immediately set
 5632                    // below, or the menu is hidden.
 5633                    match editor.context_menu.borrow_mut().take() {
 5634                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5635                            let position_matches =
 5636                                if prev_menu.initial_position == menu.initial_position {
 5637                                    true
 5638                                } else {
 5639                                    let snapshot = editor.buffer.read(cx).read(cx);
 5640                                    prev_menu.initial_position.to_offset(&snapshot)
 5641                                        == menu.initial_position.to_offset(&snapshot)
 5642                                };
 5643                            if position_matches {
 5644                                // Preserve markdown cache before `set_filter_results` because it will
 5645                                // try to populate the documentation cache.
 5646                                menu.preserve_markdown_cache(prev_menu);
 5647                            }
 5648                        }
 5649                        _ => {}
 5650                    };
 5651
 5652                    menu.set_filter_results(matches, provider, window, cx);
 5653                }) else {
 5654                    return;
 5655                };
 5656
 5657                menu.visible().then_some(menu)
 5658            };
 5659
 5660            editor
 5661                .update_in(cx, |editor, window, cx| {
 5662                    if editor.focus_handle.is_focused(window) {
 5663                        if let Some(menu) = menu {
 5664                            *editor.context_menu.borrow_mut() =
 5665                                Some(CodeContextMenu::Completions(menu));
 5666
 5667                            crate::hover_popover::hide_hover(editor, cx);
 5668                            if editor.show_edit_predictions_in_menu() {
 5669                                editor.update_visible_inline_completion(window, cx);
 5670                            } else {
 5671                                editor.discard_inline_completion(false, cx);
 5672                            }
 5673
 5674                            cx.notify();
 5675                            return;
 5676                        }
 5677                    }
 5678
 5679                    if editor.completion_tasks.len() <= 1 {
 5680                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5681                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5682                        // If it was already hidden and we don't show inline completions in the menu, we should
 5683                        // also show the inline-completion when available.
 5684                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5685                            editor.update_visible_inline_completion(window, cx);
 5686                        }
 5687                    }
 5688                })
 5689                .ok();
 5690        });
 5691
 5692        self.completion_tasks.push((id, task));
 5693    }
 5694
 5695    #[cfg(feature = "test-support")]
 5696    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5697        let menu = self.context_menu.borrow();
 5698        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5699            let completions = menu.completions.borrow();
 5700            Some(completions.to_vec())
 5701        } else {
 5702            None
 5703        }
 5704    }
 5705
 5706    pub fn with_completions_menu_matching_id<R>(
 5707        &self,
 5708        id: CompletionId,
 5709        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5710    ) -> R {
 5711        let mut context_menu = self.context_menu.borrow_mut();
 5712        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5713            return f(None);
 5714        };
 5715        if completions_menu.id != id {
 5716            return f(None);
 5717        }
 5718        f(Some(completions_menu))
 5719    }
 5720
 5721    pub fn confirm_completion(
 5722        &mut self,
 5723        action: &ConfirmCompletion,
 5724        window: &mut Window,
 5725        cx: &mut Context<Self>,
 5726    ) -> Option<Task<Result<()>>> {
 5727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5728        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5729    }
 5730
 5731    pub fn confirm_completion_insert(
 5732        &mut self,
 5733        _: &ConfirmCompletionInsert,
 5734        window: &mut Window,
 5735        cx: &mut Context<Self>,
 5736    ) -> Option<Task<Result<()>>> {
 5737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5738        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5739    }
 5740
 5741    pub fn confirm_completion_replace(
 5742        &mut self,
 5743        _: &ConfirmCompletionReplace,
 5744        window: &mut Window,
 5745        cx: &mut Context<Self>,
 5746    ) -> Option<Task<Result<()>>> {
 5747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5748        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5749    }
 5750
 5751    pub fn compose_completion(
 5752        &mut self,
 5753        action: &ComposeCompletion,
 5754        window: &mut Window,
 5755        cx: &mut Context<Self>,
 5756    ) -> Option<Task<Result<()>>> {
 5757        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5758        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5759    }
 5760
 5761    fn do_completion(
 5762        &mut self,
 5763        item_ix: Option<usize>,
 5764        intent: CompletionIntent,
 5765        window: &mut Window,
 5766        cx: &mut Context<Editor>,
 5767    ) -> Option<Task<Result<()>>> {
 5768        use language::ToOffset as _;
 5769
 5770        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5771        else {
 5772            return None;
 5773        };
 5774
 5775        let candidate_id = {
 5776            let entries = completions_menu.entries.borrow();
 5777            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5778            if self.show_edit_predictions_in_menu() {
 5779                self.discard_inline_completion(true, cx);
 5780            }
 5781            mat.candidate_id
 5782        };
 5783
 5784        let completion = completions_menu
 5785            .completions
 5786            .borrow()
 5787            .get(candidate_id)?
 5788            .clone();
 5789        cx.stop_propagation();
 5790
 5791        let buffer_handle = completions_menu.buffer.clone();
 5792
 5793        let CompletionEdit {
 5794            new_text,
 5795            snippet,
 5796            replace_range,
 5797        } = process_completion_for_edit(
 5798            &completion,
 5799            intent,
 5800            &buffer_handle,
 5801            &completions_menu.initial_position.text_anchor,
 5802            cx,
 5803        );
 5804
 5805        let buffer = buffer_handle.read(cx);
 5806        let snapshot = self.buffer.read(cx).snapshot(cx);
 5807        let newest_anchor = self.selections.newest_anchor();
 5808        let replace_range_multibuffer = {
 5809            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5810            let multibuffer_anchor = snapshot
 5811                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5812                .unwrap()
 5813                ..snapshot
 5814                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5815                    .unwrap();
 5816            multibuffer_anchor.start.to_offset(&snapshot)
 5817                ..multibuffer_anchor.end.to_offset(&snapshot)
 5818        };
 5819        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5820            return None;
 5821        }
 5822
 5823        let old_text = buffer
 5824            .text_for_range(replace_range.clone())
 5825            .collect::<String>();
 5826        let lookbehind = newest_anchor
 5827            .start
 5828            .text_anchor
 5829            .to_offset(buffer)
 5830            .saturating_sub(replace_range.start);
 5831        let lookahead = replace_range
 5832            .end
 5833            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5834        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5835        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5836
 5837        let selections = self.selections.all::<usize>(cx);
 5838        let mut ranges = Vec::new();
 5839        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5840
 5841        for selection in &selections {
 5842            let range = if selection.id == newest_anchor.id {
 5843                replace_range_multibuffer.clone()
 5844            } else {
 5845                let mut range = selection.range();
 5846
 5847                // if prefix is present, don't duplicate it
 5848                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5849                    range.start = range.start.saturating_sub(lookbehind);
 5850
 5851                    // if suffix is also present, mimic the newest cursor and replace it
 5852                    if selection.id != newest_anchor.id
 5853                        && snapshot.contains_str_at(range.end, suffix)
 5854                    {
 5855                        range.end += lookahead;
 5856                    }
 5857                }
 5858                range
 5859            };
 5860
 5861            ranges.push(range.clone());
 5862
 5863            if !self.linked_edit_ranges.is_empty() {
 5864                let start_anchor = snapshot.anchor_before(range.start);
 5865                let end_anchor = snapshot.anchor_after(range.end);
 5866                if let Some(ranges) = self
 5867                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5868                {
 5869                    for (buffer, edits) in ranges {
 5870                        linked_edits
 5871                            .entry(buffer.clone())
 5872                            .or_default()
 5873                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5874                    }
 5875                }
 5876            }
 5877        }
 5878
 5879        let common_prefix_len = old_text
 5880            .chars()
 5881            .zip(new_text.chars())
 5882            .take_while(|(a, b)| a == b)
 5883            .map(|(a, _)| a.len_utf8())
 5884            .sum::<usize>();
 5885
 5886        cx.emit(EditorEvent::InputHandled {
 5887            utf16_range_to_replace: None,
 5888            text: new_text[common_prefix_len..].into(),
 5889        });
 5890
 5891        self.transact(window, cx, |this, window, cx| {
 5892            if let Some(mut snippet) = snippet {
 5893                snippet.text = new_text.to_string();
 5894                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5895            } else {
 5896                this.buffer.update(cx, |buffer, cx| {
 5897                    let auto_indent = match completion.insert_text_mode {
 5898                        Some(InsertTextMode::AS_IS) => None,
 5899                        _ => this.autoindent_mode.clone(),
 5900                    };
 5901                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5902                    buffer.edit(edits, auto_indent, cx);
 5903                });
 5904            }
 5905            for (buffer, edits) in linked_edits {
 5906                buffer.update(cx, |buffer, cx| {
 5907                    let snapshot = buffer.snapshot();
 5908                    let edits = edits
 5909                        .into_iter()
 5910                        .map(|(range, text)| {
 5911                            use text::ToPoint as TP;
 5912                            let end_point = TP::to_point(&range.end, &snapshot);
 5913                            let start_point = TP::to_point(&range.start, &snapshot);
 5914                            (start_point..end_point, text)
 5915                        })
 5916                        .sorted_by_key(|(range, _)| range.start);
 5917                    buffer.edit(edits, None, cx);
 5918                })
 5919            }
 5920
 5921            this.refresh_inline_completion(true, false, window, cx);
 5922        });
 5923
 5924        let show_new_completions_on_confirm = completion
 5925            .confirm
 5926            .as_ref()
 5927            .map_or(false, |confirm| confirm(intent, window, cx));
 5928        if show_new_completions_on_confirm {
 5929            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5930        }
 5931
 5932        let provider = self.completion_provider.as_ref()?;
 5933        drop(completion);
 5934        let apply_edits = provider.apply_additional_edits_for_completion(
 5935            buffer_handle,
 5936            completions_menu.completions.clone(),
 5937            candidate_id,
 5938            true,
 5939            cx,
 5940        );
 5941
 5942        let editor_settings = EditorSettings::get_global(cx);
 5943        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5944            // After the code completion is finished, users often want to know what signatures are needed.
 5945            // so we should automatically call signature_help
 5946            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5947        }
 5948
 5949        Some(cx.foreground_executor().spawn(async move {
 5950            apply_edits.await?;
 5951            Ok(())
 5952        }))
 5953    }
 5954
 5955    pub fn toggle_code_actions(
 5956        &mut self,
 5957        action: &ToggleCodeActions,
 5958        window: &mut Window,
 5959        cx: &mut Context<Self>,
 5960    ) {
 5961        let quick_launch = action.quick_launch;
 5962        let mut context_menu = self.context_menu.borrow_mut();
 5963        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5964            if code_actions.deployed_from == action.deployed_from {
 5965                // Toggle if we're selecting the same one
 5966                *context_menu = None;
 5967                cx.notify();
 5968                return;
 5969            } else {
 5970                // Otherwise, clear it and start a new one
 5971                *context_menu = None;
 5972                cx.notify();
 5973            }
 5974        }
 5975        drop(context_menu);
 5976        let snapshot = self.snapshot(window, cx);
 5977        let deployed_from = action.deployed_from.clone();
 5978        let action = action.clone();
 5979        self.completion_tasks.clear();
 5980        self.discard_inline_completion(false, cx);
 5981
 5982        let multibuffer_point = match &action.deployed_from {
 5983            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5984                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5985            }
 5986            _ => self.selections.newest::<Point>(cx).head(),
 5987        };
 5988        let Some((buffer, buffer_row)) = snapshot
 5989            .buffer_snapshot
 5990            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5991            .and_then(|(buffer_snapshot, range)| {
 5992                self.buffer()
 5993                    .read(cx)
 5994                    .buffer(buffer_snapshot.remote_id())
 5995                    .map(|buffer| (buffer, range.start.row))
 5996            })
 5997        else {
 5998            return;
 5999        };
 6000        let buffer_id = buffer.read(cx).remote_id();
 6001        let tasks = self
 6002            .tasks
 6003            .get(&(buffer_id, buffer_row))
 6004            .map(|t| Arc::new(t.to_owned()));
 6005
 6006        if !self.focus_handle.is_focused(window) {
 6007            return;
 6008        }
 6009        let project = self.project.clone();
 6010
 6011        let code_actions_task = match deployed_from {
 6012            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6013            _ => self.code_actions(buffer_row, window, cx),
 6014        };
 6015
 6016        let runnable_task = match deployed_from {
 6017            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6018            _ => {
 6019                let mut task_context_task = Task::ready(None);
 6020                if let Some(tasks) = &tasks {
 6021                    if let Some(project) = project {
 6022                        task_context_task =
 6023                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6024                    }
 6025                }
 6026
 6027                cx.spawn_in(window, {
 6028                    let buffer = buffer.clone();
 6029                    async move |editor, cx| {
 6030                        let task_context = task_context_task.await;
 6031
 6032                        let resolved_tasks =
 6033                            tasks
 6034                                .zip(task_context.clone())
 6035                                .map(|(tasks, task_context)| ResolvedTasks {
 6036                                    templates: tasks.resolve(&task_context).collect(),
 6037                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6038                                        multibuffer_point.row,
 6039                                        tasks.column,
 6040                                    )),
 6041                                });
 6042                        let debug_scenarios = editor
 6043                            .update(cx, |editor, cx| {
 6044                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6045                            })?
 6046                            .await;
 6047                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6048                    }
 6049                })
 6050            }
 6051        };
 6052
 6053        cx.spawn_in(window, async move |editor, cx| {
 6054            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6055            let code_actions = code_actions_task.await;
 6056            let spawn_straight_away = quick_launch
 6057                && resolved_tasks
 6058                    .as_ref()
 6059                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6060                && code_actions
 6061                    .as_ref()
 6062                    .map_or(true, |actions| actions.is_empty())
 6063                && debug_scenarios.is_empty();
 6064
 6065            editor.update_in(cx, |editor, window, cx| {
 6066                crate::hover_popover::hide_hover(editor, cx);
 6067                let actions = CodeActionContents::new(
 6068                    resolved_tasks,
 6069                    code_actions,
 6070                    debug_scenarios,
 6071                    task_context.unwrap_or_default(),
 6072                );
 6073
 6074                // Don't show the menu if there are no actions available
 6075                if actions.is_empty() {
 6076                    cx.notify();
 6077                    return Task::ready(Ok(()));
 6078                }
 6079
 6080                *editor.context_menu.borrow_mut() =
 6081                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6082                        buffer,
 6083                        actions,
 6084                        selected_item: Default::default(),
 6085                        scroll_handle: UniformListScrollHandle::default(),
 6086                        deployed_from,
 6087                    }));
 6088                cx.notify();
 6089                if spawn_straight_away {
 6090                    if let Some(task) = editor.confirm_code_action(
 6091                        &ConfirmCodeAction { item_ix: Some(0) },
 6092                        window,
 6093                        cx,
 6094                    ) {
 6095                        return task;
 6096                    }
 6097                }
 6098
 6099                Task::ready(Ok(()))
 6100            })
 6101        })
 6102        .detach_and_log_err(cx);
 6103    }
 6104
 6105    fn debug_scenarios(
 6106        &mut self,
 6107        resolved_tasks: &Option<ResolvedTasks>,
 6108        buffer: &Entity<Buffer>,
 6109        cx: &mut App,
 6110    ) -> Task<Vec<task::DebugScenario>> {
 6111        maybe!({
 6112            let project = self.project.as_ref()?;
 6113            let dap_store = project.read(cx).dap_store();
 6114            let mut scenarios = vec![];
 6115            let resolved_tasks = resolved_tasks.as_ref()?;
 6116            let buffer = buffer.read(cx);
 6117            let language = buffer.language()?;
 6118            let file = buffer.file();
 6119            let debug_adapter = language_settings(language.name().into(), file, cx)
 6120                .debuggers
 6121                .first()
 6122                .map(SharedString::from)
 6123                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6124
 6125            dap_store.update(cx, |dap_store, cx| {
 6126                for (_, task) in &resolved_tasks.templates {
 6127                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6128                        task.original_task().clone(),
 6129                        debug_adapter.clone().into(),
 6130                        task.display_label().to_owned().into(),
 6131                        cx,
 6132                    );
 6133                    scenarios.push(maybe_scenario);
 6134                }
 6135            });
 6136            Some(cx.background_spawn(async move {
 6137                let scenarios = futures::future::join_all(scenarios)
 6138                    .await
 6139                    .into_iter()
 6140                    .flatten()
 6141                    .collect::<Vec<_>>();
 6142                scenarios
 6143            }))
 6144        })
 6145        .unwrap_or_else(|| Task::ready(vec![]))
 6146    }
 6147
 6148    fn code_actions(
 6149        &mut self,
 6150        buffer_row: u32,
 6151        window: &mut Window,
 6152        cx: &mut Context<Self>,
 6153    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6154        let mut task = self.code_actions_task.take();
 6155        cx.spawn_in(window, async move |editor, cx| {
 6156            while let Some(prev_task) = task {
 6157                prev_task.await.log_err();
 6158                task = editor
 6159                    .update(cx, |this, _| this.code_actions_task.take())
 6160                    .ok()?;
 6161            }
 6162
 6163            editor
 6164                .update(cx, |editor, cx| {
 6165                    editor
 6166                        .available_code_actions
 6167                        .clone()
 6168                        .and_then(|(location, code_actions)| {
 6169                            let snapshot = location.buffer.read(cx).snapshot();
 6170                            let point_range = location.range.to_point(&snapshot);
 6171                            let point_range = point_range.start.row..=point_range.end.row;
 6172                            if point_range.contains(&buffer_row) {
 6173                                Some(code_actions)
 6174                            } else {
 6175                                None
 6176                            }
 6177                        })
 6178                })
 6179                .ok()
 6180                .flatten()
 6181        })
 6182    }
 6183
 6184    pub fn confirm_code_action(
 6185        &mut self,
 6186        action: &ConfirmCodeAction,
 6187        window: &mut Window,
 6188        cx: &mut Context<Self>,
 6189    ) -> Option<Task<Result<()>>> {
 6190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6191
 6192        let actions_menu =
 6193            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6194                menu
 6195            } else {
 6196                return None;
 6197            };
 6198
 6199        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6200        let action = actions_menu.actions.get(action_ix)?;
 6201        let title = action.label();
 6202        let buffer = actions_menu.buffer;
 6203        let workspace = self.workspace()?;
 6204
 6205        match action {
 6206            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6207                workspace.update(cx, |workspace, cx| {
 6208                    workspace.schedule_resolved_task(
 6209                        task_source_kind,
 6210                        resolved_task,
 6211                        false,
 6212                        window,
 6213                        cx,
 6214                    );
 6215
 6216                    Some(Task::ready(Ok(())))
 6217                })
 6218            }
 6219            CodeActionsItem::CodeAction {
 6220                excerpt_id,
 6221                action,
 6222                provider,
 6223            } => {
 6224                let apply_code_action =
 6225                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6226                let workspace = workspace.downgrade();
 6227                Some(cx.spawn_in(window, async move |editor, cx| {
 6228                    let project_transaction = apply_code_action.await?;
 6229                    Self::open_project_transaction(
 6230                        &editor,
 6231                        workspace,
 6232                        project_transaction,
 6233                        title,
 6234                        cx,
 6235                    )
 6236                    .await
 6237                }))
 6238            }
 6239            CodeActionsItem::DebugScenario(scenario) => {
 6240                let context = actions_menu.actions.context.clone();
 6241
 6242                workspace.update(cx, |workspace, cx| {
 6243                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6244                    workspace.start_debug_session(
 6245                        scenario,
 6246                        context,
 6247                        Some(buffer),
 6248                        None,
 6249                        window,
 6250                        cx,
 6251                    );
 6252                });
 6253                Some(Task::ready(Ok(())))
 6254            }
 6255        }
 6256    }
 6257
 6258    pub async fn open_project_transaction(
 6259        this: &WeakEntity<Editor>,
 6260        workspace: WeakEntity<Workspace>,
 6261        transaction: ProjectTransaction,
 6262        title: String,
 6263        cx: &mut AsyncWindowContext,
 6264    ) -> Result<()> {
 6265        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6266        cx.update(|_, cx| {
 6267            entries.sort_unstable_by_key(|(buffer, _)| {
 6268                buffer.read(cx).file().map(|f| f.path().clone())
 6269            });
 6270        })?;
 6271
 6272        // If the project transaction's edits are all contained within this editor, then
 6273        // avoid opening a new editor to display them.
 6274
 6275        if let Some((buffer, transaction)) = entries.first() {
 6276            if entries.len() == 1 {
 6277                let excerpt = this.update(cx, |editor, cx| {
 6278                    editor
 6279                        .buffer()
 6280                        .read(cx)
 6281                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6282                })?;
 6283                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6284                    if excerpted_buffer == *buffer {
 6285                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6286                            let excerpt_range = excerpt_range.to_offset(buffer);
 6287                            buffer
 6288                                .edited_ranges_for_transaction::<usize>(transaction)
 6289                                .all(|range| {
 6290                                    excerpt_range.start <= range.start
 6291                                        && excerpt_range.end >= range.end
 6292                                })
 6293                        })?;
 6294
 6295                        if all_edits_within_excerpt {
 6296                            return Ok(());
 6297                        }
 6298                    }
 6299                }
 6300            }
 6301        } else {
 6302            return Ok(());
 6303        }
 6304
 6305        let mut ranges_to_highlight = Vec::new();
 6306        let excerpt_buffer = cx.new(|cx| {
 6307            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6308            for (buffer_handle, transaction) in &entries {
 6309                let edited_ranges = buffer_handle
 6310                    .read(cx)
 6311                    .edited_ranges_for_transaction::<Point>(transaction)
 6312                    .collect::<Vec<_>>();
 6313                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6314                    PathKey::for_buffer(buffer_handle, cx),
 6315                    buffer_handle.clone(),
 6316                    edited_ranges,
 6317                    DEFAULT_MULTIBUFFER_CONTEXT,
 6318                    cx,
 6319                );
 6320
 6321                ranges_to_highlight.extend(ranges);
 6322            }
 6323            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6324            multibuffer
 6325        })?;
 6326
 6327        workspace.update_in(cx, |workspace, window, cx| {
 6328            let project = workspace.project().clone();
 6329            let editor =
 6330                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6331            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6332            editor.update(cx, |editor, cx| {
 6333                editor.highlight_background::<Self>(
 6334                    &ranges_to_highlight,
 6335                    |theme| theme.colors().editor_highlighted_line_background,
 6336                    cx,
 6337                );
 6338            });
 6339        })?;
 6340
 6341        Ok(())
 6342    }
 6343
 6344    pub fn clear_code_action_providers(&mut self) {
 6345        self.code_action_providers.clear();
 6346        self.available_code_actions.take();
 6347    }
 6348
 6349    pub fn add_code_action_provider(
 6350        &mut self,
 6351        provider: Rc<dyn CodeActionProvider>,
 6352        window: &mut Window,
 6353        cx: &mut Context<Self>,
 6354    ) {
 6355        if self
 6356            .code_action_providers
 6357            .iter()
 6358            .any(|existing_provider| existing_provider.id() == provider.id())
 6359        {
 6360            return;
 6361        }
 6362
 6363        self.code_action_providers.push(provider);
 6364        self.refresh_code_actions(window, cx);
 6365    }
 6366
 6367    pub fn remove_code_action_provider(
 6368        &mut self,
 6369        id: Arc<str>,
 6370        window: &mut Window,
 6371        cx: &mut Context<Self>,
 6372    ) {
 6373        self.code_action_providers
 6374            .retain(|provider| provider.id() != id);
 6375        self.refresh_code_actions(window, cx);
 6376    }
 6377
 6378    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6379        !self.code_action_providers.is_empty()
 6380            && EditorSettings::get_global(cx).toolbar.code_actions
 6381    }
 6382
 6383    pub fn has_available_code_actions(&self) -> bool {
 6384        self.available_code_actions
 6385            .as_ref()
 6386            .is_some_and(|(_, actions)| !actions.is_empty())
 6387    }
 6388
 6389    fn render_inline_code_actions(
 6390        &self,
 6391        icon_size: ui::IconSize,
 6392        display_row: DisplayRow,
 6393        is_active: bool,
 6394        cx: &mut Context<Self>,
 6395    ) -> AnyElement {
 6396        let show_tooltip = !self.context_menu_visible();
 6397        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6398            .icon_size(icon_size)
 6399            .shape(ui::IconButtonShape::Square)
 6400            .style(ButtonStyle::Transparent)
 6401            .icon_color(ui::Color::Hidden)
 6402            .toggle_state(is_active)
 6403            .when(show_tooltip, |this| {
 6404                this.tooltip({
 6405                    let focus_handle = self.focus_handle.clone();
 6406                    move |window, cx| {
 6407                        Tooltip::for_action_in(
 6408                            "Toggle Code Actions",
 6409                            &ToggleCodeActions {
 6410                                deployed_from: None,
 6411                                quick_launch: false,
 6412                            },
 6413                            &focus_handle,
 6414                            window,
 6415                            cx,
 6416                        )
 6417                    }
 6418                })
 6419            })
 6420            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6421                window.focus(&editor.focus_handle(cx));
 6422                editor.toggle_code_actions(
 6423                    &crate::actions::ToggleCodeActions {
 6424                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6425                            display_row,
 6426                        )),
 6427                        quick_launch: false,
 6428                    },
 6429                    window,
 6430                    cx,
 6431                );
 6432            }))
 6433            .into_any_element()
 6434    }
 6435
 6436    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6437        &self.context_menu
 6438    }
 6439
 6440    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6441        let newest_selection = self.selections.newest_anchor().clone();
 6442        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6443        let buffer = self.buffer.read(cx);
 6444        if newest_selection.head().diff_base_anchor.is_some() {
 6445            return None;
 6446        }
 6447        let (start_buffer, start) =
 6448            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6449        let (end_buffer, end) =
 6450            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6451        if start_buffer != end_buffer {
 6452            return None;
 6453        }
 6454
 6455        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6456            cx.background_executor()
 6457                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6458                .await;
 6459
 6460            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6461                let providers = this.code_action_providers.clone();
 6462                let tasks = this
 6463                    .code_action_providers
 6464                    .iter()
 6465                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6466                    .collect::<Vec<_>>();
 6467                (providers, tasks)
 6468            })?;
 6469
 6470            let mut actions = Vec::new();
 6471            for (provider, provider_actions) in
 6472                providers.into_iter().zip(future::join_all(tasks).await)
 6473            {
 6474                if let Some(provider_actions) = provider_actions.log_err() {
 6475                    actions.extend(provider_actions.into_iter().map(|action| {
 6476                        AvailableCodeAction {
 6477                            excerpt_id: newest_selection.start.excerpt_id,
 6478                            action,
 6479                            provider: provider.clone(),
 6480                        }
 6481                    }));
 6482                }
 6483            }
 6484
 6485            this.update(cx, |this, cx| {
 6486                this.available_code_actions = if actions.is_empty() {
 6487                    None
 6488                } else {
 6489                    Some((
 6490                        Location {
 6491                            buffer: start_buffer,
 6492                            range: start..end,
 6493                        },
 6494                        actions.into(),
 6495                    ))
 6496                };
 6497                cx.notify();
 6498            })
 6499        }));
 6500        None
 6501    }
 6502
 6503    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6504        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6505            self.show_git_blame_inline = false;
 6506
 6507            self.show_git_blame_inline_delay_task =
 6508                Some(cx.spawn_in(window, async move |this, cx| {
 6509                    cx.background_executor().timer(delay).await;
 6510
 6511                    this.update(cx, |this, cx| {
 6512                        this.show_git_blame_inline = true;
 6513                        cx.notify();
 6514                    })
 6515                    .log_err();
 6516                }));
 6517        }
 6518    }
 6519
 6520    fn show_blame_popover(
 6521        &mut self,
 6522        blame_entry: &BlameEntry,
 6523        position: gpui::Point<Pixels>,
 6524        cx: &mut Context<Self>,
 6525    ) {
 6526        if let Some(state) = &mut self.inline_blame_popover {
 6527            state.hide_task.take();
 6528        } else {
 6529            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6530            let blame_entry = blame_entry.clone();
 6531            let show_task = cx.spawn(async move |editor, cx| {
 6532                cx.background_executor()
 6533                    .timer(std::time::Duration::from_millis(delay))
 6534                    .await;
 6535                editor
 6536                    .update(cx, |editor, cx| {
 6537                        editor.inline_blame_popover_show_task.take();
 6538                        let Some(blame) = editor.blame.as_ref() else {
 6539                            return;
 6540                        };
 6541                        let blame = blame.read(cx);
 6542                        let details = blame.details_for_entry(&blame_entry);
 6543                        let markdown = cx.new(|cx| {
 6544                            Markdown::new(
 6545                                details
 6546                                    .as_ref()
 6547                                    .map(|message| message.message.clone())
 6548                                    .unwrap_or_default(),
 6549                                None,
 6550                                None,
 6551                                cx,
 6552                            )
 6553                        });
 6554                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6555                            position,
 6556                            hide_task: None,
 6557                            popover_bounds: None,
 6558                            popover_state: InlineBlamePopoverState {
 6559                                scroll_handle: ScrollHandle::new(),
 6560                                commit_message: details,
 6561                                markdown,
 6562                            },
 6563                        });
 6564                        cx.notify();
 6565                    })
 6566                    .ok();
 6567            });
 6568            self.inline_blame_popover_show_task = Some(show_task);
 6569        }
 6570    }
 6571
 6572    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6573        self.inline_blame_popover_show_task.take();
 6574        if let Some(state) = &mut self.inline_blame_popover {
 6575            let hide_task = cx.spawn(async move |editor, cx| {
 6576                cx.background_executor()
 6577                    .timer(std::time::Duration::from_millis(100))
 6578                    .await;
 6579                editor
 6580                    .update(cx, |editor, cx| {
 6581                        editor.inline_blame_popover.take();
 6582                        cx.notify();
 6583                    })
 6584                    .ok();
 6585            });
 6586            state.hide_task = Some(hide_task);
 6587        }
 6588    }
 6589
 6590    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6591        if self.pending_rename.is_some() {
 6592            return None;
 6593        }
 6594
 6595        let provider = self.semantics_provider.clone()?;
 6596        let buffer = self.buffer.read(cx);
 6597        let newest_selection = self.selections.newest_anchor().clone();
 6598        let cursor_position = newest_selection.head();
 6599        let (cursor_buffer, cursor_buffer_position) =
 6600            buffer.text_anchor_for_position(cursor_position, cx)?;
 6601        let (tail_buffer, tail_buffer_position) =
 6602            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6603        if cursor_buffer != tail_buffer {
 6604            return None;
 6605        }
 6606
 6607        let snapshot = cursor_buffer.read(cx).snapshot();
 6608        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6609        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6610        if start_word_range != end_word_range {
 6611            self.document_highlights_task.take();
 6612            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6613            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6614            return None;
 6615        }
 6616
 6617        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6618        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6619            cx.background_executor()
 6620                .timer(Duration::from_millis(debounce))
 6621                .await;
 6622
 6623            let highlights = if let Some(highlights) = cx
 6624                .update(|cx| {
 6625                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6626                })
 6627                .ok()
 6628                .flatten()
 6629            {
 6630                highlights.await.log_err()
 6631            } else {
 6632                None
 6633            };
 6634
 6635            if let Some(highlights) = highlights {
 6636                this.update(cx, |this, cx| {
 6637                    if this.pending_rename.is_some() {
 6638                        return;
 6639                    }
 6640
 6641                    let buffer_id = cursor_position.buffer_id;
 6642                    let buffer = this.buffer.read(cx);
 6643                    if !buffer
 6644                        .text_anchor_for_position(cursor_position, cx)
 6645                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6646                    {
 6647                        return;
 6648                    }
 6649
 6650                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6651                    let mut write_ranges = Vec::new();
 6652                    let mut read_ranges = Vec::new();
 6653                    for highlight in highlights {
 6654                        for (excerpt_id, excerpt_range) in
 6655                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6656                        {
 6657                            let start = highlight
 6658                                .range
 6659                                .start
 6660                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6661                            let end = highlight
 6662                                .range
 6663                                .end
 6664                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6665                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6666                                continue;
 6667                            }
 6668
 6669                            let range = Anchor {
 6670                                buffer_id,
 6671                                excerpt_id,
 6672                                text_anchor: start,
 6673                                diff_base_anchor: None,
 6674                            }..Anchor {
 6675                                buffer_id,
 6676                                excerpt_id,
 6677                                text_anchor: end,
 6678                                diff_base_anchor: None,
 6679                            };
 6680                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6681                                write_ranges.push(range);
 6682                            } else {
 6683                                read_ranges.push(range);
 6684                            }
 6685                        }
 6686                    }
 6687
 6688                    this.highlight_background::<DocumentHighlightRead>(
 6689                        &read_ranges,
 6690                        |theme| theme.colors().editor_document_highlight_read_background,
 6691                        cx,
 6692                    );
 6693                    this.highlight_background::<DocumentHighlightWrite>(
 6694                        &write_ranges,
 6695                        |theme| theme.colors().editor_document_highlight_write_background,
 6696                        cx,
 6697                    );
 6698                    cx.notify();
 6699                })
 6700                .log_err();
 6701            }
 6702        }));
 6703        None
 6704    }
 6705
 6706    fn prepare_highlight_query_from_selection(
 6707        &mut self,
 6708        cx: &mut Context<Editor>,
 6709    ) -> Option<(String, Range<Anchor>)> {
 6710        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6711            return None;
 6712        }
 6713        if !EditorSettings::get_global(cx).selection_highlight {
 6714            return None;
 6715        }
 6716        if self.selections.count() != 1 || self.selections.line_mode {
 6717            return None;
 6718        }
 6719        let selection = self.selections.newest::<Point>(cx);
 6720        if selection.is_empty() || selection.start.row != selection.end.row {
 6721            return None;
 6722        }
 6723        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6724        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6725        let query = multi_buffer_snapshot
 6726            .text_for_range(selection_anchor_range.clone())
 6727            .collect::<String>();
 6728        if query.trim().is_empty() {
 6729            return None;
 6730        }
 6731        Some((query, selection_anchor_range))
 6732    }
 6733
 6734    fn update_selection_occurrence_highlights(
 6735        &mut self,
 6736        query_text: String,
 6737        query_range: Range<Anchor>,
 6738        multi_buffer_range_to_query: Range<Point>,
 6739        use_debounce: bool,
 6740        window: &mut Window,
 6741        cx: &mut Context<Editor>,
 6742    ) -> Task<()> {
 6743        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6744        cx.spawn_in(window, async move |editor, cx| {
 6745            if use_debounce {
 6746                cx.background_executor()
 6747                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6748                    .await;
 6749            }
 6750            let match_task = cx.background_spawn(async move {
 6751                let buffer_ranges = multi_buffer_snapshot
 6752                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6753                    .into_iter()
 6754                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6755                let mut match_ranges = Vec::new();
 6756                let Ok(regex) = project::search::SearchQuery::text(
 6757                    query_text.clone(),
 6758                    false,
 6759                    false,
 6760                    false,
 6761                    Default::default(),
 6762                    Default::default(),
 6763                    false,
 6764                    None,
 6765                ) else {
 6766                    return Vec::default();
 6767                };
 6768                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6769                    match_ranges.extend(
 6770                        regex
 6771                            .search(&buffer_snapshot, Some(search_range.clone()))
 6772                            .await
 6773                            .into_iter()
 6774                            .filter_map(|match_range| {
 6775                                let match_start = buffer_snapshot
 6776                                    .anchor_after(search_range.start + match_range.start);
 6777                                let match_end = buffer_snapshot
 6778                                    .anchor_before(search_range.start + match_range.end);
 6779                                let match_anchor_range = Anchor::range_in_buffer(
 6780                                    excerpt_id,
 6781                                    buffer_snapshot.remote_id(),
 6782                                    match_start..match_end,
 6783                                );
 6784                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6785                            }),
 6786                    );
 6787                }
 6788                match_ranges
 6789            });
 6790            let match_ranges = match_task.await;
 6791            editor
 6792                .update_in(cx, |editor, _, cx| {
 6793                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6794                    if !match_ranges.is_empty() {
 6795                        editor.highlight_background::<SelectedTextHighlight>(
 6796                            &match_ranges,
 6797                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6798                            cx,
 6799                        )
 6800                    }
 6801                })
 6802                .log_err();
 6803        })
 6804    }
 6805
 6806    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6807        struct NewlineFold;
 6808        let type_id = std::any::TypeId::of::<NewlineFold>();
 6809        if !self.mode.is_single_line() {
 6810            return;
 6811        }
 6812        let snapshot = self.snapshot(window, cx);
 6813        if snapshot.buffer_snapshot.max_point().row == 0 {
 6814            return;
 6815        }
 6816        let task = cx.background_spawn(async move {
 6817            let new_newlines = snapshot
 6818                .buffer_chars_at(0)
 6819                .filter_map(|(c, i)| {
 6820                    if c == '\n' {
 6821                        Some(
 6822                            snapshot.buffer_snapshot.anchor_after(i)
 6823                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6824                        )
 6825                    } else {
 6826                        None
 6827                    }
 6828                })
 6829                .collect::<Vec<_>>();
 6830            let existing_newlines = snapshot
 6831                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6832                .filter_map(|fold| {
 6833                    if fold.placeholder.type_tag == Some(type_id) {
 6834                        Some(fold.range.start..fold.range.end)
 6835                    } else {
 6836                        None
 6837                    }
 6838                })
 6839                .collect::<Vec<_>>();
 6840
 6841            (new_newlines, existing_newlines)
 6842        });
 6843        self.folding_newlines = cx.spawn(async move |this, cx| {
 6844            let (new_newlines, existing_newlines) = task.await;
 6845            if new_newlines == existing_newlines {
 6846                return;
 6847            }
 6848            let placeholder = FoldPlaceholder {
 6849                render: Arc::new(move |_, _, cx| {
 6850                    div()
 6851                        .bg(cx.theme().status().hint_background)
 6852                        .border_b_1()
 6853                        .size_full()
 6854                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6855                        .border_color(cx.theme().status().hint)
 6856                        .child("\\n")
 6857                        .into_any()
 6858                }),
 6859                constrain_width: false,
 6860                merge_adjacent: false,
 6861                type_tag: Some(type_id),
 6862            };
 6863            let creases = new_newlines
 6864                .into_iter()
 6865                .map(|range| Crease::simple(range, placeholder.clone()))
 6866                .collect();
 6867            this.update(cx, |this, cx| {
 6868                this.display_map.update(cx, |display_map, cx| {
 6869                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6870                    display_map.fold(creases, cx);
 6871                });
 6872            })
 6873            .ok();
 6874        });
 6875    }
 6876
 6877    fn refresh_selected_text_highlights(
 6878        &mut self,
 6879        on_buffer_edit: bool,
 6880        window: &mut Window,
 6881        cx: &mut Context<Editor>,
 6882    ) {
 6883        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6884        else {
 6885            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6886            self.quick_selection_highlight_task.take();
 6887            self.debounced_selection_highlight_task.take();
 6888            return;
 6889        };
 6890        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6891        if on_buffer_edit
 6892            || self
 6893                .quick_selection_highlight_task
 6894                .as_ref()
 6895                .map_or(true, |(prev_anchor_range, _)| {
 6896                    prev_anchor_range != &query_range
 6897                })
 6898        {
 6899            let multi_buffer_visible_start = self
 6900                .scroll_manager
 6901                .anchor()
 6902                .anchor
 6903                .to_point(&multi_buffer_snapshot);
 6904            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6905                multi_buffer_visible_start
 6906                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6907                Bias::Left,
 6908            );
 6909            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6910            self.quick_selection_highlight_task = Some((
 6911                query_range.clone(),
 6912                self.update_selection_occurrence_highlights(
 6913                    query_text.clone(),
 6914                    query_range.clone(),
 6915                    multi_buffer_visible_range,
 6916                    false,
 6917                    window,
 6918                    cx,
 6919                ),
 6920            ));
 6921        }
 6922        if on_buffer_edit
 6923            || self
 6924                .debounced_selection_highlight_task
 6925                .as_ref()
 6926                .map_or(true, |(prev_anchor_range, _)| {
 6927                    prev_anchor_range != &query_range
 6928                })
 6929        {
 6930            let multi_buffer_start = multi_buffer_snapshot
 6931                .anchor_before(0)
 6932                .to_point(&multi_buffer_snapshot);
 6933            let multi_buffer_end = multi_buffer_snapshot
 6934                .anchor_after(multi_buffer_snapshot.len())
 6935                .to_point(&multi_buffer_snapshot);
 6936            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6937            self.debounced_selection_highlight_task = Some((
 6938                query_range.clone(),
 6939                self.update_selection_occurrence_highlights(
 6940                    query_text,
 6941                    query_range,
 6942                    multi_buffer_full_range,
 6943                    true,
 6944                    window,
 6945                    cx,
 6946                ),
 6947            ));
 6948        }
 6949    }
 6950
 6951    pub fn refresh_inline_completion(
 6952        &mut self,
 6953        debounce: bool,
 6954        user_requested: bool,
 6955        window: &mut Window,
 6956        cx: &mut Context<Self>,
 6957    ) -> Option<()> {
 6958        let provider = self.edit_prediction_provider()?;
 6959        let cursor = self.selections.newest_anchor().head();
 6960        let (buffer, cursor_buffer_position) =
 6961            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6962
 6963        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6964            self.discard_inline_completion(false, cx);
 6965            return None;
 6966        }
 6967
 6968        if !user_requested
 6969            && (!self.should_show_edit_predictions()
 6970                || !self.is_focused(window)
 6971                || buffer.read(cx).is_empty())
 6972        {
 6973            self.discard_inline_completion(false, cx);
 6974            return None;
 6975        }
 6976
 6977        self.update_visible_inline_completion(window, cx);
 6978        provider.refresh(
 6979            self.project.clone(),
 6980            buffer,
 6981            cursor_buffer_position,
 6982            debounce,
 6983            cx,
 6984        );
 6985        Some(())
 6986    }
 6987
 6988    fn show_edit_predictions_in_menu(&self) -> bool {
 6989        match self.edit_prediction_settings {
 6990            EditPredictionSettings::Disabled => false,
 6991            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6992        }
 6993    }
 6994
 6995    pub fn edit_predictions_enabled(&self) -> bool {
 6996        match self.edit_prediction_settings {
 6997            EditPredictionSettings::Disabled => false,
 6998            EditPredictionSettings::Enabled { .. } => true,
 6999        }
 7000    }
 7001
 7002    fn edit_prediction_requires_modifier(&self) -> bool {
 7003        match self.edit_prediction_settings {
 7004            EditPredictionSettings::Disabled => false,
 7005            EditPredictionSettings::Enabled {
 7006                preview_requires_modifier,
 7007                ..
 7008            } => preview_requires_modifier,
 7009        }
 7010    }
 7011
 7012    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7013        if self.edit_prediction_provider.is_none() {
 7014            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7015        } else {
 7016            let selection = self.selections.newest_anchor();
 7017            let cursor = selection.head();
 7018
 7019            if let Some((buffer, cursor_buffer_position)) =
 7020                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7021            {
 7022                self.edit_prediction_settings =
 7023                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7024            }
 7025        }
 7026    }
 7027
 7028    fn edit_prediction_settings_at_position(
 7029        &self,
 7030        buffer: &Entity<Buffer>,
 7031        buffer_position: language::Anchor,
 7032        cx: &App,
 7033    ) -> EditPredictionSettings {
 7034        if !self.mode.is_full()
 7035            || !self.show_inline_completions_override.unwrap_or(true)
 7036            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7037        {
 7038            return EditPredictionSettings::Disabled;
 7039        }
 7040
 7041        let buffer = buffer.read(cx);
 7042
 7043        let file = buffer.file();
 7044
 7045        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7046            return EditPredictionSettings::Disabled;
 7047        };
 7048
 7049        let by_provider = matches!(
 7050            self.menu_inline_completions_policy,
 7051            MenuInlineCompletionsPolicy::ByProvider
 7052        );
 7053
 7054        let show_in_menu = by_provider
 7055            && self
 7056                .edit_prediction_provider
 7057                .as_ref()
 7058                .map_or(false, |provider| {
 7059                    provider.provider.show_completions_in_menu()
 7060                });
 7061
 7062        let preview_requires_modifier =
 7063            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7064
 7065        EditPredictionSettings::Enabled {
 7066            show_in_menu,
 7067            preview_requires_modifier,
 7068        }
 7069    }
 7070
 7071    fn should_show_edit_predictions(&self) -> bool {
 7072        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7073    }
 7074
 7075    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7076        matches!(
 7077            self.edit_prediction_preview,
 7078            EditPredictionPreview::Active { .. }
 7079        )
 7080    }
 7081
 7082    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7083        let cursor = self.selections.newest_anchor().head();
 7084        if let Some((buffer, cursor_position)) =
 7085            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7086        {
 7087            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7088        } else {
 7089            false
 7090        }
 7091    }
 7092
 7093    pub fn supports_minimap(&self, cx: &App) -> bool {
 7094        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7095    }
 7096
 7097    fn edit_predictions_enabled_in_buffer(
 7098        &self,
 7099        buffer: &Entity<Buffer>,
 7100        buffer_position: language::Anchor,
 7101        cx: &App,
 7102    ) -> bool {
 7103        maybe!({
 7104            if self.read_only(cx) {
 7105                return Some(false);
 7106            }
 7107            let provider = self.edit_prediction_provider()?;
 7108            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7109                return Some(false);
 7110            }
 7111            let buffer = buffer.read(cx);
 7112            let Some(file) = buffer.file() else {
 7113                return Some(true);
 7114            };
 7115            let settings = all_language_settings(Some(file), cx);
 7116            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7117        })
 7118        .unwrap_or(false)
 7119    }
 7120
 7121    fn cycle_inline_completion(
 7122        &mut self,
 7123        direction: Direction,
 7124        window: &mut Window,
 7125        cx: &mut Context<Self>,
 7126    ) -> Option<()> {
 7127        let provider = self.edit_prediction_provider()?;
 7128        let cursor = self.selections.newest_anchor().head();
 7129        let (buffer, cursor_buffer_position) =
 7130            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7131        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7132            return None;
 7133        }
 7134
 7135        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7136        self.update_visible_inline_completion(window, cx);
 7137
 7138        Some(())
 7139    }
 7140
 7141    pub fn show_inline_completion(
 7142        &mut self,
 7143        _: &ShowEditPrediction,
 7144        window: &mut Window,
 7145        cx: &mut Context<Self>,
 7146    ) {
 7147        if !self.has_active_inline_completion() {
 7148            self.refresh_inline_completion(false, true, window, cx);
 7149            return;
 7150        }
 7151
 7152        self.update_visible_inline_completion(window, cx);
 7153    }
 7154
 7155    pub fn display_cursor_names(
 7156        &mut self,
 7157        _: &DisplayCursorNames,
 7158        window: &mut Window,
 7159        cx: &mut Context<Self>,
 7160    ) {
 7161        self.show_cursor_names(window, cx);
 7162    }
 7163
 7164    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7165        self.show_cursor_names = true;
 7166        cx.notify();
 7167        cx.spawn_in(window, async move |this, cx| {
 7168            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7169            this.update(cx, |this, cx| {
 7170                this.show_cursor_names = false;
 7171                cx.notify()
 7172            })
 7173            .ok()
 7174        })
 7175        .detach();
 7176    }
 7177
 7178    pub fn next_edit_prediction(
 7179        &mut self,
 7180        _: &NextEditPrediction,
 7181        window: &mut Window,
 7182        cx: &mut Context<Self>,
 7183    ) {
 7184        if self.has_active_inline_completion() {
 7185            self.cycle_inline_completion(Direction::Next, window, cx);
 7186        } else {
 7187            let is_copilot_disabled = self
 7188                .refresh_inline_completion(false, true, window, cx)
 7189                .is_none();
 7190            if is_copilot_disabled {
 7191                cx.propagate();
 7192            }
 7193        }
 7194    }
 7195
 7196    pub fn previous_edit_prediction(
 7197        &mut self,
 7198        _: &PreviousEditPrediction,
 7199        window: &mut Window,
 7200        cx: &mut Context<Self>,
 7201    ) {
 7202        if self.has_active_inline_completion() {
 7203            self.cycle_inline_completion(Direction::Prev, window, cx);
 7204        } else {
 7205            let is_copilot_disabled = self
 7206                .refresh_inline_completion(false, true, window, cx)
 7207                .is_none();
 7208            if is_copilot_disabled {
 7209                cx.propagate();
 7210            }
 7211        }
 7212    }
 7213
 7214    pub fn accept_edit_prediction(
 7215        &mut self,
 7216        _: &AcceptEditPrediction,
 7217        window: &mut Window,
 7218        cx: &mut Context<Self>,
 7219    ) {
 7220        if self.show_edit_predictions_in_menu() {
 7221            self.hide_context_menu(window, cx);
 7222        }
 7223
 7224        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7225            return;
 7226        };
 7227
 7228        self.report_inline_completion_event(
 7229            active_inline_completion.completion_id.clone(),
 7230            true,
 7231            cx,
 7232        );
 7233
 7234        match &active_inline_completion.completion {
 7235            InlineCompletion::Move { target, .. } => {
 7236                let target = *target;
 7237
 7238                if let Some(position_map) = &self.last_position_map {
 7239                    if position_map
 7240                        .visible_row_range
 7241                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7242                        || !self.edit_prediction_requires_modifier()
 7243                    {
 7244                        self.unfold_ranges(&[target..target], true, false, cx);
 7245                        // Note that this is also done in vim's handler of the Tab action.
 7246                        self.change_selections(
 7247                            SelectionEffects::scroll(Autoscroll::newest()),
 7248                            window,
 7249                            cx,
 7250                            |selections| {
 7251                                selections.select_anchor_ranges([target..target]);
 7252                            },
 7253                        );
 7254                        self.clear_row_highlights::<EditPredictionPreview>();
 7255
 7256                        self.edit_prediction_preview
 7257                            .set_previous_scroll_position(None);
 7258                    } else {
 7259                        self.edit_prediction_preview
 7260                            .set_previous_scroll_position(Some(
 7261                                position_map.snapshot.scroll_anchor,
 7262                            ));
 7263
 7264                        self.highlight_rows::<EditPredictionPreview>(
 7265                            target..target,
 7266                            cx.theme().colors().editor_highlighted_line_background,
 7267                            RowHighlightOptions {
 7268                                autoscroll: true,
 7269                                ..Default::default()
 7270                            },
 7271                            cx,
 7272                        );
 7273                        self.request_autoscroll(Autoscroll::fit(), cx);
 7274                    }
 7275                }
 7276            }
 7277            InlineCompletion::Edit { edits, .. } => {
 7278                if let Some(provider) = self.edit_prediction_provider() {
 7279                    provider.accept(cx);
 7280                }
 7281
 7282                // Store the transaction ID and selections before applying the edit
 7283                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7284
 7285                let snapshot = self.buffer.read(cx).snapshot(cx);
 7286                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7287
 7288                self.buffer.update(cx, |buffer, cx| {
 7289                    buffer.edit(edits.iter().cloned(), None, cx)
 7290                });
 7291
 7292                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7293                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7294                });
 7295
 7296                let selections = self.selections.disjoint_anchors();
 7297                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7298                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7299                    if has_new_transaction {
 7300                        self.selection_history
 7301                            .insert_transaction(transaction_id_now, selections);
 7302                    }
 7303                }
 7304
 7305                self.update_visible_inline_completion(window, cx);
 7306                if self.active_inline_completion.is_none() {
 7307                    self.refresh_inline_completion(true, true, window, cx);
 7308                }
 7309
 7310                cx.notify();
 7311            }
 7312        }
 7313
 7314        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7315    }
 7316
 7317    pub fn accept_partial_inline_completion(
 7318        &mut self,
 7319        _: &AcceptPartialEditPrediction,
 7320        window: &mut Window,
 7321        cx: &mut Context<Self>,
 7322    ) {
 7323        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7324            return;
 7325        };
 7326        if self.selections.count() != 1 {
 7327            return;
 7328        }
 7329
 7330        self.report_inline_completion_event(
 7331            active_inline_completion.completion_id.clone(),
 7332            true,
 7333            cx,
 7334        );
 7335
 7336        match &active_inline_completion.completion {
 7337            InlineCompletion::Move { target, .. } => {
 7338                let target = *target;
 7339                self.change_selections(
 7340                    SelectionEffects::scroll(Autoscroll::newest()),
 7341                    window,
 7342                    cx,
 7343                    |selections| {
 7344                        selections.select_anchor_ranges([target..target]);
 7345                    },
 7346                );
 7347            }
 7348            InlineCompletion::Edit { edits, .. } => {
 7349                // Find an insertion that starts at the cursor position.
 7350                let snapshot = self.buffer.read(cx).snapshot(cx);
 7351                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7352                let insertion = edits.iter().find_map(|(range, text)| {
 7353                    let range = range.to_offset(&snapshot);
 7354                    if range.is_empty() && range.start == cursor_offset {
 7355                        Some(text)
 7356                    } else {
 7357                        None
 7358                    }
 7359                });
 7360
 7361                if let Some(text) = insertion {
 7362                    let mut partial_completion = text
 7363                        .chars()
 7364                        .by_ref()
 7365                        .take_while(|c| c.is_alphabetic())
 7366                        .collect::<String>();
 7367                    if partial_completion.is_empty() {
 7368                        partial_completion = text
 7369                            .chars()
 7370                            .by_ref()
 7371                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7372                            .collect::<String>();
 7373                    }
 7374
 7375                    cx.emit(EditorEvent::InputHandled {
 7376                        utf16_range_to_replace: None,
 7377                        text: partial_completion.clone().into(),
 7378                    });
 7379
 7380                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7381
 7382                    self.refresh_inline_completion(true, true, window, cx);
 7383                    cx.notify();
 7384                } else {
 7385                    self.accept_edit_prediction(&Default::default(), window, cx);
 7386                }
 7387            }
 7388        }
 7389    }
 7390
 7391    fn discard_inline_completion(
 7392        &mut self,
 7393        should_report_inline_completion_event: bool,
 7394        cx: &mut Context<Self>,
 7395    ) -> bool {
 7396        if should_report_inline_completion_event {
 7397            let completion_id = self
 7398                .active_inline_completion
 7399                .as_ref()
 7400                .and_then(|active_completion| active_completion.completion_id.clone());
 7401
 7402            self.report_inline_completion_event(completion_id, false, cx);
 7403        }
 7404
 7405        if let Some(provider) = self.edit_prediction_provider() {
 7406            provider.discard(cx);
 7407        }
 7408
 7409        self.take_active_inline_completion(cx)
 7410    }
 7411
 7412    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7413        let Some(provider) = self.edit_prediction_provider() else {
 7414            return;
 7415        };
 7416
 7417        let Some((_, buffer, _)) = self
 7418            .buffer
 7419            .read(cx)
 7420            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7421        else {
 7422            return;
 7423        };
 7424
 7425        let extension = buffer
 7426            .read(cx)
 7427            .file()
 7428            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7429
 7430        let event_type = match accepted {
 7431            true => "Edit Prediction Accepted",
 7432            false => "Edit Prediction Discarded",
 7433        };
 7434        telemetry::event!(
 7435            event_type,
 7436            provider = provider.name(),
 7437            prediction_id = id,
 7438            suggestion_accepted = accepted,
 7439            file_extension = extension,
 7440        );
 7441    }
 7442
 7443    pub fn has_active_inline_completion(&self) -> bool {
 7444        self.active_inline_completion.is_some()
 7445    }
 7446
 7447    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7448        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7449            return false;
 7450        };
 7451
 7452        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7453        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7454        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7455        true
 7456    }
 7457
 7458    /// Returns true when we're displaying the edit prediction popover below the cursor
 7459    /// like we are not previewing and the LSP autocomplete menu is visible
 7460    /// or we are in `when_holding_modifier` mode.
 7461    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7462        if self.edit_prediction_preview_is_active()
 7463            || !self.show_edit_predictions_in_menu()
 7464            || !self.edit_predictions_enabled()
 7465        {
 7466            return false;
 7467        }
 7468
 7469        if self.has_visible_completions_menu() {
 7470            return true;
 7471        }
 7472
 7473        has_completion && self.edit_prediction_requires_modifier()
 7474    }
 7475
 7476    fn handle_modifiers_changed(
 7477        &mut self,
 7478        modifiers: Modifiers,
 7479        position_map: &PositionMap,
 7480        window: &mut Window,
 7481        cx: &mut Context<Self>,
 7482    ) {
 7483        if self.show_edit_predictions_in_menu() {
 7484            self.update_edit_prediction_preview(&modifiers, window, cx);
 7485        }
 7486
 7487        self.update_selection_mode(&modifiers, position_map, window, cx);
 7488
 7489        let mouse_position = window.mouse_position();
 7490        if !position_map.text_hitbox.is_hovered(window) {
 7491            return;
 7492        }
 7493
 7494        self.update_hovered_link(
 7495            position_map.point_for_position(mouse_position),
 7496            &position_map.snapshot,
 7497            modifiers,
 7498            window,
 7499            cx,
 7500        )
 7501    }
 7502
 7503    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7504        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7505        if invert {
 7506            match multi_cursor_setting {
 7507                MultiCursorModifier::Alt => modifiers.alt,
 7508                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7509            }
 7510        } else {
 7511            match multi_cursor_setting {
 7512                MultiCursorModifier::Alt => modifiers.secondary(),
 7513                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7514            }
 7515        }
 7516    }
 7517
 7518    fn columnar_selection_mode(
 7519        modifiers: &Modifiers,
 7520        cx: &mut Context<Self>,
 7521    ) -> Option<ColumnarMode> {
 7522        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7523            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7524                Some(ColumnarMode::FromMouse)
 7525            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7526                Some(ColumnarMode::FromSelection)
 7527            } else {
 7528                None
 7529            }
 7530        } else {
 7531            None
 7532        }
 7533    }
 7534
 7535    fn update_selection_mode(
 7536        &mut self,
 7537        modifiers: &Modifiers,
 7538        position_map: &PositionMap,
 7539        window: &mut Window,
 7540        cx: &mut Context<Self>,
 7541    ) {
 7542        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7543            return;
 7544        };
 7545        if self.selections.pending.is_none() {
 7546            return;
 7547        }
 7548
 7549        let mouse_position = window.mouse_position();
 7550        let point_for_position = position_map.point_for_position(mouse_position);
 7551        let position = point_for_position.previous_valid;
 7552
 7553        self.select(
 7554            SelectPhase::BeginColumnar {
 7555                position,
 7556                reset: false,
 7557                mode,
 7558                goal_column: point_for_position.exact_unclipped.column(),
 7559            },
 7560            window,
 7561            cx,
 7562        );
 7563    }
 7564
 7565    fn update_edit_prediction_preview(
 7566        &mut self,
 7567        modifiers: &Modifiers,
 7568        window: &mut Window,
 7569        cx: &mut Context<Self>,
 7570    ) {
 7571        let mut modifiers_held = false;
 7572        if let Some(accept_keystroke) = self
 7573            .accept_edit_prediction_keybind(false, window, cx)
 7574            .keystroke()
 7575        {
 7576            modifiers_held = modifiers_held
 7577                || (&accept_keystroke.modifiers == modifiers
 7578                    && accept_keystroke.modifiers.modified());
 7579        };
 7580        if let Some(accept_partial_keystroke) = self
 7581            .accept_edit_prediction_keybind(true, window, cx)
 7582            .keystroke()
 7583        {
 7584            modifiers_held = modifiers_held
 7585                || (&accept_partial_keystroke.modifiers == modifiers
 7586                    && accept_partial_keystroke.modifiers.modified());
 7587        }
 7588
 7589        if modifiers_held {
 7590            if matches!(
 7591                self.edit_prediction_preview,
 7592                EditPredictionPreview::Inactive { .. }
 7593            ) {
 7594                self.edit_prediction_preview = EditPredictionPreview::Active {
 7595                    previous_scroll_position: None,
 7596                    since: Instant::now(),
 7597                };
 7598
 7599                self.update_visible_inline_completion(window, cx);
 7600                cx.notify();
 7601            }
 7602        } else if let EditPredictionPreview::Active {
 7603            previous_scroll_position,
 7604            since,
 7605        } = self.edit_prediction_preview
 7606        {
 7607            if let (Some(previous_scroll_position), Some(position_map)) =
 7608                (previous_scroll_position, self.last_position_map.as_ref())
 7609            {
 7610                self.set_scroll_position(
 7611                    previous_scroll_position
 7612                        .scroll_position(&position_map.snapshot.display_snapshot),
 7613                    window,
 7614                    cx,
 7615                );
 7616            }
 7617
 7618            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7619                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7620            };
 7621            self.clear_row_highlights::<EditPredictionPreview>();
 7622            self.update_visible_inline_completion(window, cx);
 7623            cx.notify();
 7624        }
 7625    }
 7626
 7627    fn update_visible_inline_completion(
 7628        &mut self,
 7629        _window: &mut Window,
 7630        cx: &mut Context<Self>,
 7631    ) -> Option<()> {
 7632        let selection = self.selections.newest_anchor();
 7633        let cursor = selection.head();
 7634        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7635        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7636        let excerpt_id = cursor.excerpt_id;
 7637
 7638        let show_in_menu = self.show_edit_predictions_in_menu();
 7639        let completions_menu_has_precedence = !show_in_menu
 7640            && (self.context_menu.borrow().is_some()
 7641                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7642
 7643        if completions_menu_has_precedence
 7644            || !offset_selection.is_empty()
 7645            || self
 7646                .active_inline_completion
 7647                .as_ref()
 7648                .map_or(false, |completion| {
 7649                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7650                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7651                    !invalidation_range.contains(&offset_selection.head())
 7652                })
 7653        {
 7654            self.discard_inline_completion(false, cx);
 7655            return None;
 7656        }
 7657
 7658        self.take_active_inline_completion(cx);
 7659        let Some(provider) = self.edit_prediction_provider() else {
 7660            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7661            return None;
 7662        };
 7663
 7664        let (buffer, cursor_buffer_position) =
 7665            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7666
 7667        self.edit_prediction_settings =
 7668            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7669
 7670        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7671
 7672        if self.edit_prediction_indent_conflict {
 7673            let cursor_point = cursor.to_point(&multibuffer);
 7674
 7675            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7676
 7677            if let Some((_, indent)) = indents.iter().next() {
 7678                if indent.len == cursor_point.column {
 7679                    self.edit_prediction_indent_conflict = false;
 7680                }
 7681            }
 7682        }
 7683
 7684        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7685        let edits = inline_completion
 7686            .edits
 7687            .into_iter()
 7688            .flat_map(|(range, new_text)| {
 7689                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7690                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7691                Some((start..end, new_text))
 7692            })
 7693            .collect::<Vec<_>>();
 7694        if edits.is_empty() {
 7695            return None;
 7696        }
 7697
 7698        let first_edit_start = edits.first().unwrap().0.start;
 7699        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7700        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7701
 7702        let last_edit_end = edits.last().unwrap().0.end;
 7703        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7704        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7705
 7706        let cursor_row = cursor.to_point(&multibuffer).row;
 7707
 7708        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7709
 7710        let mut inlay_ids = Vec::new();
 7711        let invalidation_row_range;
 7712        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7713            Some(cursor_row..edit_end_row)
 7714        } else if cursor_row > edit_end_row {
 7715            Some(edit_start_row..cursor_row)
 7716        } else {
 7717            None
 7718        };
 7719        let is_move =
 7720            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7721        let completion = if is_move {
 7722            invalidation_row_range =
 7723                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7724            let target = first_edit_start;
 7725            InlineCompletion::Move { target, snapshot }
 7726        } else {
 7727            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7728                && !self.inline_completions_hidden_for_vim_mode;
 7729
 7730            if show_completions_in_buffer {
 7731                if edits
 7732                    .iter()
 7733                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7734                {
 7735                    let mut inlays = Vec::new();
 7736                    for (range, new_text) in &edits {
 7737                        let inlay = Inlay::inline_completion(
 7738                            post_inc(&mut self.next_inlay_id),
 7739                            range.start,
 7740                            new_text.as_str(),
 7741                        );
 7742                        inlay_ids.push(inlay.id);
 7743                        inlays.push(inlay);
 7744                    }
 7745
 7746                    self.splice_inlays(&[], inlays, cx);
 7747                } else {
 7748                    let background_color = cx.theme().status().deleted_background;
 7749                    self.highlight_text::<InlineCompletionHighlight>(
 7750                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7751                        HighlightStyle {
 7752                            background_color: Some(background_color),
 7753                            ..Default::default()
 7754                        },
 7755                        cx,
 7756                    );
 7757                }
 7758            }
 7759
 7760            invalidation_row_range = edit_start_row..edit_end_row;
 7761
 7762            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7763                if provider.show_tab_accept_marker() {
 7764                    EditDisplayMode::TabAccept
 7765                } else {
 7766                    EditDisplayMode::Inline
 7767                }
 7768            } else {
 7769                EditDisplayMode::DiffPopover
 7770            };
 7771
 7772            InlineCompletion::Edit {
 7773                edits,
 7774                edit_preview: inline_completion.edit_preview,
 7775                display_mode,
 7776                snapshot,
 7777            }
 7778        };
 7779
 7780        let invalidation_range = multibuffer
 7781            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7782            ..multibuffer.anchor_after(Point::new(
 7783                invalidation_row_range.end,
 7784                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7785            ));
 7786
 7787        self.stale_inline_completion_in_menu = None;
 7788        self.active_inline_completion = Some(InlineCompletionState {
 7789            inlay_ids,
 7790            completion,
 7791            completion_id: inline_completion.id,
 7792            invalidation_range,
 7793        });
 7794
 7795        cx.notify();
 7796
 7797        Some(())
 7798    }
 7799
 7800    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7801        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7802    }
 7803
 7804    fn clear_tasks(&mut self) {
 7805        self.tasks.clear()
 7806    }
 7807
 7808    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7809        if self.tasks.insert(key, value).is_some() {
 7810            // This case should hopefully be rare, but just in case...
 7811            log::error!(
 7812                "multiple different run targets found on a single line, only the last target will be rendered"
 7813            )
 7814        }
 7815    }
 7816
 7817    /// Get all display points of breakpoints that will be rendered within editor
 7818    ///
 7819    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7820    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7821    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7822    fn active_breakpoints(
 7823        &self,
 7824        range: Range<DisplayRow>,
 7825        window: &mut Window,
 7826        cx: &mut Context<Self>,
 7827    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7828        let mut breakpoint_display_points = HashMap::default();
 7829
 7830        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7831            return breakpoint_display_points;
 7832        };
 7833
 7834        let snapshot = self.snapshot(window, cx);
 7835
 7836        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7837        let Some(project) = self.project.as_ref() else {
 7838            return breakpoint_display_points;
 7839        };
 7840
 7841        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7842            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7843
 7844        for (buffer_snapshot, range, excerpt_id) in
 7845            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7846        {
 7847            let Some(buffer) = project
 7848                .read(cx)
 7849                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7850            else {
 7851                continue;
 7852            };
 7853            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7854                &buffer,
 7855                Some(
 7856                    buffer_snapshot.anchor_before(range.start)
 7857                        ..buffer_snapshot.anchor_after(range.end),
 7858                ),
 7859                buffer_snapshot,
 7860                cx,
 7861            );
 7862            for (breakpoint, state) in breakpoints {
 7863                let multi_buffer_anchor =
 7864                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7865                let position = multi_buffer_anchor
 7866                    .to_point(&multi_buffer_snapshot)
 7867                    .to_display_point(&snapshot);
 7868
 7869                breakpoint_display_points.insert(
 7870                    position.row(),
 7871                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7872                );
 7873            }
 7874        }
 7875
 7876        breakpoint_display_points
 7877    }
 7878
 7879    fn breakpoint_context_menu(
 7880        &self,
 7881        anchor: Anchor,
 7882        window: &mut Window,
 7883        cx: &mut Context<Self>,
 7884    ) -> Entity<ui::ContextMenu> {
 7885        let weak_editor = cx.weak_entity();
 7886        let focus_handle = self.focus_handle(cx);
 7887
 7888        let row = self
 7889            .buffer
 7890            .read(cx)
 7891            .snapshot(cx)
 7892            .summary_for_anchor::<Point>(&anchor)
 7893            .row;
 7894
 7895        let breakpoint = self
 7896            .breakpoint_at_row(row, window, cx)
 7897            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7898
 7899        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7900            "Edit Log Breakpoint"
 7901        } else {
 7902            "Set Log Breakpoint"
 7903        };
 7904
 7905        let condition_breakpoint_msg = if breakpoint
 7906            .as_ref()
 7907            .is_some_and(|bp| bp.1.condition.is_some())
 7908        {
 7909            "Edit Condition Breakpoint"
 7910        } else {
 7911            "Set Condition Breakpoint"
 7912        };
 7913
 7914        let hit_condition_breakpoint_msg = if breakpoint
 7915            .as_ref()
 7916            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7917        {
 7918            "Edit Hit Condition Breakpoint"
 7919        } else {
 7920            "Set Hit Condition Breakpoint"
 7921        };
 7922
 7923        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7924            "Unset Breakpoint"
 7925        } else {
 7926            "Set Breakpoint"
 7927        };
 7928
 7929        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7930
 7931        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7932            BreakpointState::Enabled => Some("Disable"),
 7933            BreakpointState::Disabled => Some("Enable"),
 7934        });
 7935
 7936        let (anchor, breakpoint) =
 7937            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7938
 7939        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7940            menu.on_blur_subscription(Subscription::new(|| {}))
 7941                .context(focus_handle)
 7942                .when(run_to_cursor, |this| {
 7943                    let weak_editor = weak_editor.clone();
 7944                    this.entry("Run to cursor", None, move |window, cx| {
 7945                        weak_editor
 7946                            .update(cx, |editor, cx| {
 7947                                editor.change_selections(
 7948                                    SelectionEffects::no_scroll(),
 7949                                    window,
 7950                                    cx,
 7951                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7952                                );
 7953                            })
 7954                            .ok();
 7955
 7956                        window.dispatch_action(Box::new(RunToCursor), cx);
 7957                    })
 7958                    .separator()
 7959                })
 7960                .when_some(toggle_state_msg, |this, msg| {
 7961                    this.entry(msg, None, {
 7962                        let weak_editor = weak_editor.clone();
 7963                        let breakpoint = breakpoint.clone();
 7964                        move |_window, cx| {
 7965                            weak_editor
 7966                                .update(cx, |this, cx| {
 7967                                    this.edit_breakpoint_at_anchor(
 7968                                        anchor,
 7969                                        breakpoint.as_ref().clone(),
 7970                                        BreakpointEditAction::InvertState,
 7971                                        cx,
 7972                                    );
 7973                                })
 7974                                .log_err();
 7975                        }
 7976                    })
 7977                })
 7978                .entry(set_breakpoint_msg, None, {
 7979                    let weak_editor = weak_editor.clone();
 7980                    let breakpoint = breakpoint.clone();
 7981                    move |_window, cx| {
 7982                        weak_editor
 7983                            .update(cx, |this, cx| {
 7984                                this.edit_breakpoint_at_anchor(
 7985                                    anchor,
 7986                                    breakpoint.as_ref().clone(),
 7987                                    BreakpointEditAction::Toggle,
 7988                                    cx,
 7989                                );
 7990                            })
 7991                            .log_err();
 7992                    }
 7993                })
 7994                .entry(log_breakpoint_msg, None, {
 7995                    let breakpoint = breakpoint.clone();
 7996                    let weak_editor = weak_editor.clone();
 7997                    move |window, cx| {
 7998                        weak_editor
 7999                            .update(cx, |this, cx| {
 8000                                this.add_edit_breakpoint_block(
 8001                                    anchor,
 8002                                    breakpoint.as_ref(),
 8003                                    BreakpointPromptEditAction::Log,
 8004                                    window,
 8005                                    cx,
 8006                                );
 8007                            })
 8008                            .log_err();
 8009                    }
 8010                })
 8011                .entry(condition_breakpoint_msg, None, {
 8012                    let breakpoint = breakpoint.clone();
 8013                    let weak_editor = weak_editor.clone();
 8014                    move |window, cx| {
 8015                        weak_editor
 8016                            .update(cx, |this, cx| {
 8017                                this.add_edit_breakpoint_block(
 8018                                    anchor,
 8019                                    breakpoint.as_ref(),
 8020                                    BreakpointPromptEditAction::Condition,
 8021                                    window,
 8022                                    cx,
 8023                                );
 8024                            })
 8025                            .log_err();
 8026                    }
 8027                })
 8028                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8029                    weak_editor
 8030                        .update(cx, |this, cx| {
 8031                            this.add_edit_breakpoint_block(
 8032                                anchor,
 8033                                breakpoint.as_ref(),
 8034                                BreakpointPromptEditAction::HitCondition,
 8035                                window,
 8036                                cx,
 8037                            );
 8038                        })
 8039                        .log_err();
 8040                })
 8041        })
 8042    }
 8043
 8044    fn render_breakpoint(
 8045        &self,
 8046        position: Anchor,
 8047        row: DisplayRow,
 8048        breakpoint: &Breakpoint,
 8049        state: Option<BreakpointSessionState>,
 8050        cx: &mut Context<Self>,
 8051    ) -> IconButton {
 8052        let is_rejected = state.is_some_and(|s| !s.verified);
 8053        // Is it a breakpoint that shows up when hovering over gutter?
 8054        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8055            (false, false),
 8056            |PhantomBreakpointIndicator {
 8057                 is_active,
 8058                 display_row,
 8059                 collides_with_existing_breakpoint,
 8060             }| {
 8061                (
 8062                    is_active && display_row == row,
 8063                    collides_with_existing_breakpoint,
 8064                )
 8065            },
 8066        );
 8067
 8068        let (color, icon) = {
 8069            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8070                (false, false) => ui::IconName::DebugBreakpoint,
 8071                (true, false) => ui::IconName::DebugLogBreakpoint,
 8072                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8073                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8074            };
 8075
 8076            let color = if is_phantom {
 8077                Color::Hint
 8078            } else if is_rejected {
 8079                Color::Disabled
 8080            } else {
 8081                Color::Debugger
 8082            };
 8083
 8084            (color, icon)
 8085        };
 8086
 8087        let breakpoint = Arc::from(breakpoint.clone());
 8088
 8089        let alt_as_text = gpui::Keystroke {
 8090            modifiers: Modifiers::secondary_key(),
 8091            ..Default::default()
 8092        };
 8093        let primary_action_text = if breakpoint.is_disabled() {
 8094            "Enable breakpoint"
 8095        } else if is_phantom && !collides_with_existing {
 8096            "Set breakpoint"
 8097        } else {
 8098            "Unset breakpoint"
 8099        };
 8100        let focus_handle = self.focus_handle.clone();
 8101
 8102        let meta = if is_rejected {
 8103            SharedString::from("No executable code is associated with this line.")
 8104        } else if collides_with_existing && !breakpoint.is_disabled() {
 8105            SharedString::from(format!(
 8106                "{alt_as_text}-click to disable,\nright-click for more options."
 8107            ))
 8108        } else {
 8109            SharedString::from("Right-click for more options.")
 8110        };
 8111        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8112            .icon_size(IconSize::XSmall)
 8113            .size(ui::ButtonSize::None)
 8114            .when(is_rejected, |this| {
 8115                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8116            })
 8117            .icon_color(color)
 8118            .style(ButtonStyle::Transparent)
 8119            .on_click(cx.listener({
 8120                let breakpoint = breakpoint.clone();
 8121
 8122                move |editor, event: &ClickEvent, window, cx| {
 8123                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8124                        BreakpointEditAction::InvertState
 8125                    } else {
 8126                        BreakpointEditAction::Toggle
 8127                    };
 8128
 8129                    window.focus(&editor.focus_handle(cx));
 8130                    editor.edit_breakpoint_at_anchor(
 8131                        position,
 8132                        breakpoint.as_ref().clone(),
 8133                        edit_action,
 8134                        cx,
 8135                    );
 8136                }
 8137            }))
 8138            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8139                editor.set_breakpoint_context_menu(
 8140                    row,
 8141                    Some(position),
 8142                    event.down.position,
 8143                    window,
 8144                    cx,
 8145                );
 8146            }))
 8147            .tooltip(move |window, cx| {
 8148                Tooltip::with_meta_in(
 8149                    primary_action_text,
 8150                    Some(&ToggleBreakpoint),
 8151                    meta.clone(),
 8152                    &focus_handle,
 8153                    window,
 8154                    cx,
 8155                )
 8156            })
 8157    }
 8158
 8159    fn build_tasks_context(
 8160        project: &Entity<Project>,
 8161        buffer: &Entity<Buffer>,
 8162        buffer_row: u32,
 8163        tasks: &Arc<RunnableTasks>,
 8164        cx: &mut Context<Self>,
 8165    ) -> Task<Option<task::TaskContext>> {
 8166        let position = Point::new(buffer_row, tasks.column);
 8167        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8168        let location = Location {
 8169            buffer: buffer.clone(),
 8170            range: range_start..range_start,
 8171        };
 8172        // Fill in the environmental variables from the tree-sitter captures
 8173        let mut captured_task_variables = TaskVariables::default();
 8174        for (capture_name, value) in tasks.extra_variables.clone() {
 8175            captured_task_variables.insert(
 8176                task::VariableName::Custom(capture_name.into()),
 8177                value.clone(),
 8178            );
 8179        }
 8180        project.update(cx, |project, cx| {
 8181            project.task_store().update(cx, |task_store, cx| {
 8182                task_store.task_context_for_location(captured_task_variables, location, cx)
 8183            })
 8184        })
 8185    }
 8186
 8187    pub fn spawn_nearest_task(
 8188        &mut self,
 8189        action: &SpawnNearestTask,
 8190        window: &mut Window,
 8191        cx: &mut Context<Self>,
 8192    ) {
 8193        let Some((workspace, _)) = self.workspace.clone() else {
 8194            return;
 8195        };
 8196        let Some(project) = self.project.clone() else {
 8197            return;
 8198        };
 8199
 8200        // Try to find a closest, enclosing node using tree-sitter that has a
 8201        // task
 8202        let Some((buffer, buffer_row, tasks)) = self
 8203            .find_enclosing_node_task(cx)
 8204            // Or find the task that's closest in row-distance.
 8205            .or_else(|| self.find_closest_task(cx))
 8206        else {
 8207            return;
 8208        };
 8209
 8210        let reveal_strategy = action.reveal;
 8211        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8212        cx.spawn_in(window, async move |_, cx| {
 8213            let context = task_context.await?;
 8214            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8215
 8216            let resolved = &mut resolved_task.resolved;
 8217            resolved.reveal = reveal_strategy;
 8218
 8219            workspace
 8220                .update_in(cx, |workspace, window, cx| {
 8221                    workspace.schedule_resolved_task(
 8222                        task_source_kind,
 8223                        resolved_task,
 8224                        false,
 8225                        window,
 8226                        cx,
 8227                    );
 8228                })
 8229                .ok()
 8230        })
 8231        .detach();
 8232    }
 8233
 8234    fn find_closest_task(
 8235        &mut self,
 8236        cx: &mut Context<Self>,
 8237    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8238        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8239
 8240        let ((buffer_id, row), tasks) = self
 8241            .tasks
 8242            .iter()
 8243            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8244
 8245        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8246        let tasks = Arc::new(tasks.to_owned());
 8247        Some((buffer, *row, tasks))
 8248    }
 8249
 8250    fn find_enclosing_node_task(
 8251        &mut self,
 8252        cx: &mut Context<Self>,
 8253    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8254        let snapshot = self.buffer.read(cx).snapshot(cx);
 8255        let offset = self.selections.newest::<usize>(cx).head();
 8256        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8257        let buffer_id = excerpt.buffer().remote_id();
 8258
 8259        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8260        let mut cursor = layer.node().walk();
 8261
 8262        while cursor.goto_first_child_for_byte(offset).is_some() {
 8263            if cursor.node().end_byte() == offset {
 8264                cursor.goto_next_sibling();
 8265            }
 8266        }
 8267
 8268        // Ascend to the smallest ancestor that contains the range and has a task.
 8269        loop {
 8270            let node = cursor.node();
 8271            let node_range = node.byte_range();
 8272            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8273
 8274            // Check if this node contains our offset
 8275            if node_range.start <= offset && node_range.end >= offset {
 8276                // If it contains offset, check for task
 8277                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8278                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8279                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8280                }
 8281            }
 8282
 8283            if !cursor.goto_parent() {
 8284                break;
 8285            }
 8286        }
 8287        None
 8288    }
 8289
 8290    fn render_run_indicator(
 8291        &self,
 8292        _style: &EditorStyle,
 8293        is_active: bool,
 8294        row: DisplayRow,
 8295        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8296        cx: &mut Context<Self>,
 8297    ) -> IconButton {
 8298        let color = Color::Muted;
 8299        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8300
 8301        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8302            .shape(ui::IconButtonShape::Square)
 8303            .icon_size(IconSize::XSmall)
 8304            .icon_color(color)
 8305            .toggle_state(is_active)
 8306            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8307                let quick_launch = e.down.button == MouseButton::Left;
 8308                window.focus(&editor.focus_handle(cx));
 8309                editor.toggle_code_actions(
 8310                    &ToggleCodeActions {
 8311                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8312                        quick_launch,
 8313                    },
 8314                    window,
 8315                    cx,
 8316                );
 8317            }))
 8318            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8319                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8320            }))
 8321    }
 8322
 8323    pub fn context_menu_visible(&self) -> bool {
 8324        !self.edit_prediction_preview_is_active()
 8325            && self
 8326                .context_menu
 8327                .borrow()
 8328                .as_ref()
 8329                .map_or(false, |menu| menu.visible())
 8330    }
 8331
 8332    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8333        self.context_menu
 8334            .borrow()
 8335            .as_ref()
 8336            .map(|menu| menu.origin())
 8337    }
 8338
 8339    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8340        self.context_menu_options = Some(options);
 8341    }
 8342
 8343    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8344    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8345
 8346    fn render_edit_prediction_popover(
 8347        &mut self,
 8348        text_bounds: &Bounds<Pixels>,
 8349        content_origin: gpui::Point<Pixels>,
 8350        right_margin: Pixels,
 8351        editor_snapshot: &EditorSnapshot,
 8352        visible_row_range: Range<DisplayRow>,
 8353        scroll_top: f32,
 8354        scroll_bottom: f32,
 8355        line_layouts: &[LineWithInvisibles],
 8356        line_height: Pixels,
 8357        scroll_pixel_position: gpui::Point<Pixels>,
 8358        newest_selection_head: Option<DisplayPoint>,
 8359        editor_width: Pixels,
 8360        style: &EditorStyle,
 8361        window: &mut Window,
 8362        cx: &mut App,
 8363    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8364        if self.mode().is_minimap() {
 8365            return None;
 8366        }
 8367        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8368
 8369        if self.edit_prediction_visible_in_cursor_popover(true) {
 8370            return None;
 8371        }
 8372
 8373        match &active_inline_completion.completion {
 8374            InlineCompletion::Move { target, .. } => {
 8375                let target_display_point = target.to_display_point(editor_snapshot);
 8376
 8377                if self.edit_prediction_requires_modifier() {
 8378                    if !self.edit_prediction_preview_is_active() {
 8379                        return None;
 8380                    }
 8381
 8382                    self.render_edit_prediction_modifier_jump_popover(
 8383                        text_bounds,
 8384                        content_origin,
 8385                        visible_row_range,
 8386                        line_layouts,
 8387                        line_height,
 8388                        scroll_pixel_position,
 8389                        newest_selection_head,
 8390                        target_display_point,
 8391                        window,
 8392                        cx,
 8393                    )
 8394                } else {
 8395                    self.render_edit_prediction_eager_jump_popover(
 8396                        text_bounds,
 8397                        content_origin,
 8398                        editor_snapshot,
 8399                        visible_row_range,
 8400                        scroll_top,
 8401                        scroll_bottom,
 8402                        line_height,
 8403                        scroll_pixel_position,
 8404                        target_display_point,
 8405                        editor_width,
 8406                        window,
 8407                        cx,
 8408                    )
 8409                }
 8410            }
 8411            InlineCompletion::Edit {
 8412                display_mode: EditDisplayMode::Inline,
 8413                ..
 8414            } => None,
 8415            InlineCompletion::Edit {
 8416                display_mode: EditDisplayMode::TabAccept,
 8417                edits,
 8418                ..
 8419            } => {
 8420                let range = &edits.first()?.0;
 8421                let target_display_point = range.end.to_display_point(editor_snapshot);
 8422
 8423                self.render_edit_prediction_end_of_line_popover(
 8424                    "Accept",
 8425                    editor_snapshot,
 8426                    visible_row_range,
 8427                    target_display_point,
 8428                    line_height,
 8429                    scroll_pixel_position,
 8430                    content_origin,
 8431                    editor_width,
 8432                    window,
 8433                    cx,
 8434                )
 8435            }
 8436            InlineCompletion::Edit {
 8437                edits,
 8438                edit_preview,
 8439                display_mode: EditDisplayMode::DiffPopover,
 8440                snapshot,
 8441            } => self.render_edit_prediction_diff_popover(
 8442                text_bounds,
 8443                content_origin,
 8444                right_margin,
 8445                editor_snapshot,
 8446                visible_row_range,
 8447                line_layouts,
 8448                line_height,
 8449                scroll_pixel_position,
 8450                newest_selection_head,
 8451                editor_width,
 8452                style,
 8453                edits,
 8454                edit_preview,
 8455                snapshot,
 8456                window,
 8457                cx,
 8458            ),
 8459        }
 8460    }
 8461
 8462    fn render_edit_prediction_modifier_jump_popover(
 8463        &mut self,
 8464        text_bounds: &Bounds<Pixels>,
 8465        content_origin: gpui::Point<Pixels>,
 8466        visible_row_range: Range<DisplayRow>,
 8467        line_layouts: &[LineWithInvisibles],
 8468        line_height: Pixels,
 8469        scroll_pixel_position: gpui::Point<Pixels>,
 8470        newest_selection_head: Option<DisplayPoint>,
 8471        target_display_point: DisplayPoint,
 8472        window: &mut Window,
 8473        cx: &mut App,
 8474    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8475        let scrolled_content_origin =
 8476            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8477
 8478        const SCROLL_PADDING_Y: Pixels = px(12.);
 8479
 8480        if target_display_point.row() < visible_row_range.start {
 8481            return self.render_edit_prediction_scroll_popover(
 8482                |_| SCROLL_PADDING_Y,
 8483                IconName::ArrowUp,
 8484                visible_row_range,
 8485                line_layouts,
 8486                newest_selection_head,
 8487                scrolled_content_origin,
 8488                window,
 8489                cx,
 8490            );
 8491        } else if target_display_point.row() >= visible_row_range.end {
 8492            return self.render_edit_prediction_scroll_popover(
 8493                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8494                IconName::ArrowDown,
 8495                visible_row_range,
 8496                line_layouts,
 8497                newest_selection_head,
 8498                scrolled_content_origin,
 8499                window,
 8500                cx,
 8501            );
 8502        }
 8503
 8504        const POLE_WIDTH: Pixels = px(2.);
 8505
 8506        let line_layout =
 8507            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8508        let target_column = target_display_point.column() as usize;
 8509
 8510        let target_x = line_layout.x_for_index(target_column);
 8511        let target_y =
 8512            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8513
 8514        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8515
 8516        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8517        border_color.l += 0.001;
 8518
 8519        let mut element = v_flex()
 8520            .items_end()
 8521            .when(flag_on_right, |el| el.items_start())
 8522            .child(if flag_on_right {
 8523                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8524                    .rounded_bl(px(0.))
 8525                    .rounded_tl(px(0.))
 8526                    .border_l_2()
 8527                    .border_color(border_color)
 8528            } else {
 8529                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8530                    .rounded_br(px(0.))
 8531                    .rounded_tr(px(0.))
 8532                    .border_r_2()
 8533                    .border_color(border_color)
 8534            })
 8535            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8536            .into_any();
 8537
 8538        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8539
 8540        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8541            - point(
 8542                if flag_on_right {
 8543                    POLE_WIDTH
 8544                } else {
 8545                    size.width - POLE_WIDTH
 8546                },
 8547                size.height - line_height,
 8548            );
 8549
 8550        origin.x = origin.x.max(content_origin.x);
 8551
 8552        element.prepaint_at(origin, window, cx);
 8553
 8554        Some((element, origin))
 8555    }
 8556
 8557    fn render_edit_prediction_scroll_popover(
 8558        &mut self,
 8559        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8560        scroll_icon: IconName,
 8561        visible_row_range: Range<DisplayRow>,
 8562        line_layouts: &[LineWithInvisibles],
 8563        newest_selection_head: Option<DisplayPoint>,
 8564        scrolled_content_origin: gpui::Point<Pixels>,
 8565        window: &mut Window,
 8566        cx: &mut App,
 8567    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8568        let mut element = self
 8569            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8570            .into_any();
 8571
 8572        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8573
 8574        let cursor = newest_selection_head?;
 8575        let cursor_row_layout =
 8576            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8577        let cursor_column = cursor.column() as usize;
 8578
 8579        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8580
 8581        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8582
 8583        element.prepaint_at(origin, window, cx);
 8584        Some((element, origin))
 8585    }
 8586
 8587    fn render_edit_prediction_eager_jump_popover(
 8588        &mut self,
 8589        text_bounds: &Bounds<Pixels>,
 8590        content_origin: gpui::Point<Pixels>,
 8591        editor_snapshot: &EditorSnapshot,
 8592        visible_row_range: Range<DisplayRow>,
 8593        scroll_top: f32,
 8594        scroll_bottom: f32,
 8595        line_height: Pixels,
 8596        scroll_pixel_position: gpui::Point<Pixels>,
 8597        target_display_point: DisplayPoint,
 8598        editor_width: Pixels,
 8599        window: &mut Window,
 8600        cx: &mut App,
 8601    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8602        if target_display_point.row().as_f32() < scroll_top {
 8603            let mut element = self
 8604                .render_edit_prediction_line_popover(
 8605                    "Jump to Edit",
 8606                    Some(IconName::ArrowUp),
 8607                    window,
 8608                    cx,
 8609                )?
 8610                .into_any();
 8611
 8612            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8613            let offset = point(
 8614                (text_bounds.size.width - size.width) / 2.,
 8615                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8616            );
 8617
 8618            let origin = text_bounds.origin + offset;
 8619            element.prepaint_at(origin, window, cx);
 8620            Some((element, origin))
 8621        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8622            let mut element = self
 8623                .render_edit_prediction_line_popover(
 8624                    "Jump to Edit",
 8625                    Some(IconName::ArrowDown),
 8626                    window,
 8627                    cx,
 8628                )?
 8629                .into_any();
 8630
 8631            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8632            let offset = point(
 8633                (text_bounds.size.width - size.width) / 2.,
 8634                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8635            );
 8636
 8637            let origin = text_bounds.origin + offset;
 8638            element.prepaint_at(origin, window, cx);
 8639            Some((element, origin))
 8640        } else {
 8641            self.render_edit_prediction_end_of_line_popover(
 8642                "Jump to Edit",
 8643                editor_snapshot,
 8644                visible_row_range,
 8645                target_display_point,
 8646                line_height,
 8647                scroll_pixel_position,
 8648                content_origin,
 8649                editor_width,
 8650                window,
 8651                cx,
 8652            )
 8653        }
 8654    }
 8655
 8656    fn render_edit_prediction_end_of_line_popover(
 8657        self: &mut Editor,
 8658        label: &'static str,
 8659        editor_snapshot: &EditorSnapshot,
 8660        visible_row_range: Range<DisplayRow>,
 8661        target_display_point: DisplayPoint,
 8662        line_height: Pixels,
 8663        scroll_pixel_position: gpui::Point<Pixels>,
 8664        content_origin: gpui::Point<Pixels>,
 8665        editor_width: Pixels,
 8666        window: &mut Window,
 8667        cx: &mut App,
 8668    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8669        let target_line_end = DisplayPoint::new(
 8670            target_display_point.row(),
 8671            editor_snapshot.line_len(target_display_point.row()),
 8672        );
 8673
 8674        let mut element = self
 8675            .render_edit_prediction_line_popover(label, None, window, cx)?
 8676            .into_any();
 8677
 8678        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8679
 8680        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8681
 8682        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8683        let mut origin = start_point
 8684            + line_origin
 8685            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8686        origin.x = origin.x.max(content_origin.x);
 8687
 8688        let max_x = content_origin.x + editor_width - size.width;
 8689
 8690        if origin.x > max_x {
 8691            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8692
 8693            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8694                origin.y += offset;
 8695                IconName::ArrowUp
 8696            } else {
 8697                origin.y -= offset;
 8698                IconName::ArrowDown
 8699            };
 8700
 8701            element = self
 8702                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8703                .into_any();
 8704
 8705            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8706
 8707            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8708        }
 8709
 8710        element.prepaint_at(origin, window, cx);
 8711        Some((element, origin))
 8712    }
 8713
 8714    fn render_edit_prediction_diff_popover(
 8715        self: &Editor,
 8716        text_bounds: &Bounds<Pixels>,
 8717        content_origin: gpui::Point<Pixels>,
 8718        right_margin: Pixels,
 8719        editor_snapshot: &EditorSnapshot,
 8720        visible_row_range: Range<DisplayRow>,
 8721        line_layouts: &[LineWithInvisibles],
 8722        line_height: Pixels,
 8723        scroll_pixel_position: gpui::Point<Pixels>,
 8724        newest_selection_head: Option<DisplayPoint>,
 8725        editor_width: Pixels,
 8726        style: &EditorStyle,
 8727        edits: &Vec<(Range<Anchor>, String)>,
 8728        edit_preview: &Option<language::EditPreview>,
 8729        snapshot: &language::BufferSnapshot,
 8730        window: &mut Window,
 8731        cx: &mut App,
 8732    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8733        let edit_start = edits
 8734            .first()
 8735            .unwrap()
 8736            .0
 8737            .start
 8738            .to_display_point(editor_snapshot);
 8739        let edit_end = edits
 8740            .last()
 8741            .unwrap()
 8742            .0
 8743            .end
 8744            .to_display_point(editor_snapshot);
 8745
 8746        let is_visible = visible_row_range.contains(&edit_start.row())
 8747            || visible_row_range.contains(&edit_end.row());
 8748        if !is_visible {
 8749            return None;
 8750        }
 8751
 8752        let highlighted_edits =
 8753            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8754
 8755        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8756        let line_count = highlighted_edits.text.lines().count();
 8757
 8758        const BORDER_WIDTH: Pixels = px(1.);
 8759
 8760        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8761        let has_keybind = keybind.is_some();
 8762
 8763        let mut element = h_flex()
 8764            .items_start()
 8765            .child(
 8766                h_flex()
 8767                    .bg(cx.theme().colors().editor_background)
 8768                    .border(BORDER_WIDTH)
 8769                    .shadow_xs()
 8770                    .border_color(cx.theme().colors().border)
 8771                    .rounded_l_lg()
 8772                    .when(line_count > 1, |el| el.rounded_br_lg())
 8773                    .pr_1()
 8774                    .child(styled_text),
 8775            )
 8776            .child(
 8777                h_flex()
 8778                    .h(line_height + BORDER_WIDTH * 2.)
 8779                    .px_1p5()
 8780                    .gap_1()
 8781                    // Workaround: For some reason, there's a gap if we don't do this
 8782                    .ml(-BORDER_WIDTH)
 8783                    .shadow(vec![gpui::BoxShadow {
 8784                        color: gpui::black().opacity(0.05),
 8785                        offset: point(px(1.), px(1.)),
 8786                        blur_radius: px(2.),
 8787                        spread_radius: px(0.),
 8788                    }])
 8789                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8790                    .border(BORDER_WIDTH)
 8791                    .border_color(cx.theme().colors().border)
 8792                    .rounded_r_lg()
 8793                    .id("edit_prediction_diff_popover_keybind")
 8794                    .when(!has_keybind, |el| {
 8795                        let status_colors = cx.theme().status();
 8796
 8797                        el.bg(status_colors.error_background)
 8798                            .border_color(status_colors.error.opacity(0.6))
 8799                            .child(Icon::new(IconName::Info).color(Color::Error))
 8800                            .cursor_default()
 8801                            .hoverable_tooltip(move |_window, cx| {
 8802                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8803                            })
 8804                    })
 8805                    .children(keybind),
 8806            )
 8807            .into_any();
 8808
 8809        let longest_row =
 8810            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8811        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8812            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8813        } else {
 8814            layout_line(
 8815                longest_row,
 8816                editor_snapshot,
 8817                style,
 8818                editor_width,
 8819                |_| false,
 8820                window,
 8821                cx,
 8822            )
 8823            .width
 8824        };
 8825
 8826        let viewport_bounds =
 8827            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8828                right: -right_margin,
 8829                ..Default::default()
 8830            });
 8831
 8832        let x_after_longest =
 8833            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8834                - scroll_pixel_position.x;
 8835
 8836        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8837
 8838        // Fully visible if it can be displayed within the window (allow overlapping other
 8839        // panes). However, this is only allowed if the popover starts within text_bounds.
 8840        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8841            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8842
 8843        let mut origin = if can_position_to_the_right {
 8844            point(
 8845                x_after_longest,
 8846                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8847                    - scroll_pixel_position.y,
 8848            )
 8849        } else {
 8850            let cursor_row = newest_selection_head.map(|head| head.row());
 8851            let above_edit = edit_start
 8852                .row()
 8853                .0
 8854                .checked_sub(line_count as u32)
 8855                .map(DisplayRow);
 8856            let below_edit = Some(edit_end.row() + 1);
 8857            let above_cursor =
 8858                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8859            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8860
 8861            // Place the edit popover adjacent to the edit if there is a location
 8862            // available that is onscreen and does not obscure the cursor. Otherwise,
 8863            // place it adjacent to the cursor.
 8864            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8865                .into_iter()
 8866                .flatten()
 8867                .find(|&start_row| {
 8868                    let end_row = start_row + line_count as u32;
 8869                    visible_row_range.contains(&start_row)
 8870                        && visible_row_range.contains(&end_row)
 8871                        && cursor_row.map_or(true, |cursor_row| {
 8872                            !((start_row..end_row).contains(&cursor_row))
 8873                        })
 8874                })?;
 8875
 8876            content_origin
 8877                + point(
 8878                    -scroll_pixel_position.x,
 8879                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8880                )
 8881        };
 8882
 8883        origin.x -= BORDER_WIDTH;
 8884
 8885        window.defer_draw(element, origin, 1);
 8886
 8887        // Do not return an element, since it will already be drawn due to defer_draw.
 8888        None
 8889    }
 8890
 8891    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8892        px(30.)
 8893    }
 8894
 8895    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8896        if self.read_only(cx) {
 8897            cx.theme().players().read_only()
 8898        } else {
 8899            self.style.as_ref().unwrap().local_player
 8900        }
 8901    }
 8902
 8903    fn render_edit_prediction_accept_keybind(
 8904        &self,
 8905        window: &mut Window,
 8906        cx: &App,
 8907    ) -> Option<AnyElement> {
 8908        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8909        let accept_keystroke = accept_binding.keystroke()?;
 8910
 8911        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8912
 8913        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8914            Color::Accent
 8915        } else {
 8916            Color::Muted
 8917        };
 8918
 8919        h_flex()
 8920            .px_0p5()
 8921            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8922            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8923            .text_size(TextSize::XSmall.rems(cx))
 8924            .child(h_flex().children(ui::render_modifiers(
 8925                &accept_keystroke.modifiers,
 8926                PlatformStyle::platform(),
 8927                Some(modifiers_color),
 8928                Some(IconSize::XSmall.rems().into()),
 8929                true,
 8930            )))
 8931            .when(is_platform_style_mac, |parent| {
 8932                parent.child(accept_keystroke.key.clone())
 8933            })
 8934            .when(!is_platform_style_mac, |parent| {
 8935                parent.child(
 8936                    Key::new(
 8937                        util::capitalize(&accept_keystroke.key),
 8938                        Some(Color::Default),
 8939                    )
 8940                    .size(Some(IconSize::XSmall.rems().into())),
 8941                )
 8942            })
 8943            .into_any()
 8944            .into()
 8945    }
 8946
 8947    fn render_edit_prediction_line_popover(
 8948        &self,
 8949        label: impl Into<SharedString>,
 8950        icon: Option<IconName>,
 8951        window: &mut Window,
 8952        cx: &App,
 8953    ) -> Option<Stateful<Div>> {
 8954        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8955
 8956        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8957        let has_keybind = keybind.is_some();
 8958
 8959        let result = h_flex()
 8960            .id("ep-line-popover")
 8961            .py_0p5()
 8962            .pl_1()
 8963            .pr(padding_right)
 8964            .gap_1()
 8965            .rounded_md()
 8966            .border_1()
 8967            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8968            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8969            .shadow_xs()
 8970            .when(!has_keybind, |el| {
 8971                let status_colors = cx.theme().status();
 8972
 8973                el.bg(status_colors.error_background)
 8974                    .border_color(status_colors.error.opacity(0.6))
 8975                    .pl_2()
 8976                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8977                    .cursor_default()
 8978                    .hoverable_tooltip(move |_window, cx| {
 8979                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8980                    })
 8981            })
 8982            .children(keybind)
 8983            .child(
 8984                Label::new(label)
 8985                    .size(LabelSize::Small)
 8986                    .when(!has_keybind, |el| {
 8987                        el.color(cx.theme().status().error.into()).strikethrough()
 8988                    }),
 8989            )
 8990            .when(!has_keybind, |el| {
 8991                el.child(
 8992                    h_flex().ml_1().child(
 8993                        Icon::new(IconName::Info)
 8994                            .size(IconSize::Small)
 8995                            .color(cx.theme().status().error.into()),
 8996                    ),
 8997                )
 8998            })
 8999            .when_some(icon, |element, icon| {
 9000                element.child(
 9001                    div()
 9002                        .mt(px(1.5))
 9003                        .child(Icon::new(icon).size(IconSize::Small)),
 9004                )
 9005            });
 9006
 9007        Some(result)
 9008    }
 9009
 9010    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9011        let accent_color = cx.theme().colors().text_accent;
 9012        let editor_bg_color = cx.theme().colors().editor_background;
 9013        editor_bg_color.blend(accent_color.opacity(0.1))
 9014    }
 9015
 9016    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9017        let accent_color = cx.theme().colors().text_accent;
 9018        let editor_bg_color = cx.theme().colors().editor_background;
 9019        editor_bg_color.blend(accent_color.opacity(0.6))
 9020    }
 9021
 9022    fn render_edit_prediction_cursor_popover(
 9023        &self,
 9024        min_width: Pixels,
 9025        max_width: Pixels,
 9026        cursor_point: Point,
 9027        style: &EditorStyle,
 9028        accept_keystroke: Option<&gpui::Keystroke>,
 9029        _window: &Window,
 9030        cx: &mut Context<Editor>,
 9031    ) -> Option<AnyElement> {
 9032        let provider = self.edit_prediction_provider.as_ref()?;
 9033
 9034        if provider.provider.needs_terms_acceptance(cx) {
 9035            return Some(
 9036                h_flex()
 9037                    .min_w(min_width)
 9038                    .flex_1()
 9039                    .px_2()
 9040                    .py_1()
 9041                    .gap_3()
 9042                    .elevation_2(cx)
 9043                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9044                    .id("accept-terms")
 9045                    .cursor_pointer()
 9046                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9047                    .on_click(cx.listener(|this, _event, window, cx| {
 9048                        cx.stop_propagation();
 9049                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9050                        window.dispatch_action(
 9051                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9052                            cx,
 9053                        );
 9054                    }))
 9055                    .child(
 9056                        h_flex()
 9057                            .flex_1()
 9058                            .gap_2()
 9059                            .child(Icon::new(IconName::ZedPredict))
 9060                            .child(Label::new("Accept Terms of Service"))
 9061                            .child(div().w_full())
 9062                            .child(
 9063                                Icon::new(IconName::ArrowUpRight)
 9064                                    .color(Color::Muted)
 9065                                    .size(IconSize::Small),
 9066                            )
 9067                            .into_any_element(),
 9068                    )
 9069                    .into_any(),
 9070            );
 9071        }
 9072
 9073        let is_refreshing = provider.provider.is_refreshing(cx);
 9074
 9075        fn pending_completion_container() -> Div {
 9076            h_flex()
 9077                .h_full()
 9078                .flex_1()
 9079                .gap_2()
 9080                .child(Icon::new(IconName::ZedPredict))
 9081        }
 9082
 9083        let completion = match &self.active_inline_completion {
 9084            Some(prediction) => {
 9085                if !self.has_visible_completions_menu() {
 9086                    const RADIUS: Pixels = px(6.);
 9087                    const BORDER_WIDTH: Pixels = px(1.);
 9088
 9089                    return Some(
 9090                        h_flex()
 9091                            .elevation_2(cx)
 9092                            .border(BORDER_WIDTH)
 9093                            .border_color(cx.theme().colors().border)
 9094                            .when(accept_keystroke.is_none(), |el| {
 9095                                el.border_color(cx.theme().status().error)
 9096                            })
 9097                            .rounded(RADIUS)
 9098                            .rounded_tl(px(0.))
 9099                            .overflow_hidden()
 9100                            .child(div().px_1p5().child(match &prediction.completion {
 9101                                InlineCompletion::Move { target, snapshot } => {
 9102                                    use text::ToPoint as _;
 9103                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9104                                    {
 9105                                        Icon::new(IconName::ZedPredictDown)
 9106                                    } else {
 9107                                        Icon::new(IconName::ZedPredictUp)
 9108                                    }
 9109                                }
 9110                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9111                            }))
 9112                            .child(
 9113                                h_flex()
 9114                                    .gap_1()
 9115                                    .py_1()
 9116                                    .px_2()
 9117                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9118                                    .border_l_1()
 9119                                    .border_color(cx.theme().colors().border)
 9120                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9121                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9122                                        el.child(
 9123                                            Label::new("Hold")
 9124                                                .size(LabelSize::Small)
 9125                                                .when(accept_keystroke.is_none(), |el| {
 9126                                                    el.strikethrough()
 9127                                                })
 9128                                                .line_height_style(LineHeightStyle::UiLabel),
 9129                                        )
 9130                                    })
 9131                                    .id("edit_prediction_cursor_popover_keybind")
 9132                                    .when(accept_keystroke.is_none(), |el| {
 9133                                        let status_colors = cx.theme().status();
 9134
 9135                                        el.bg(status_colors.error_background)
 9136                                            .border_color(status_colors.error.opacity(0.6))
 9137                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9138                                            .cursor_default()
 9139                                            .hoverable_tooltip(move |_window, cx| {
 9140                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9141                                                    .into()
 9142                                            })
 9143                                    })
 9144                                    .when_some(
 9145                                        accept_keystroke.as_ref(),
 9146                                        |el, accept_keystroke| {
 9147                                            el.child(h_flex().children(ui::render_modifiers(
 9148                                                &accept_keystroke.modifiers,
 9149                                                PlatformStyle::platform(),
 9150                                                Some(Color::Default),
 9151                                                Some(IconSize::XSmall.rems().into()),
 9152                                                false,
 9153                                            )))
 9154                                        },
 9155                                    ),
 9156                            )
 9157                            .into_any(),
 9158                    );
 9159                }
 9160
 9161                self.render_edit_prediction_cursor_popover_preview(
 9162                    prediction,
 9163                    cursor_point,
 9164                    style,
 9165                    cx,
 9166                )?
 9167            }
 9168
 9169            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9170                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9171                    stale_completion,
 9172                    cursor_point,
 9173                    style,
 9174                    cx,
 9175                )?,
 9176
 9177                None => {
 9178                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9179                }
 9180            },
 9181
 9182            None => pending_completion_container().child(Label::new("No Prediction")),
 9183        };
 9184
 9185        let completion = if is_refreshing {
 9186            completion
 9187                .with_animation(
 9188                    "loading-completion",
 9189                    Animation::new(Duration::from_secs(2))
 9190                        .repeat()
 9191                        .with_easing(pulsating_between(0.4, 0.8)),
 9192                    |label, delta| label.opacity(delta),
 9193                )
 9194                .into_any_element()
 9195        } else {
 9196            completion.into_any_element()
 9197        };
 9198
 9199        let has_completion = self.active_inline_completion.is_some();
 9200
 9201        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9202        Some(
 9203            h_flex()
 9204                .min_w(min_width)
 9205                .max_w(max_width)
 9206                .flex_1()
 9207                .elevation_2(cx)
 9208                .border_color(cx.theme().colors().border)
 9209                .child(
 9210                    div()
 9211                        .flex_1()
 9212                        .py_1()
 9213                        .px_2()
 9214                        .overflow_hidden()
 9215                        .child(completion),
 9216                )
 9217                .when_some(accept_keystroke, |el, accept_keystroke| {
 9218                    if !accept_keystroke.modifiers.modified() {
 9219                        return el;
 9220                    }
 9221
 9222                    el.child(
 9223                        h_flex()
 9224                            .h_full()
 9225                            .border_l_1()
 9226                            .rounded_r_lg()
 9227                            .border_color(cx.theme().colors().border)
 9228                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9229                            .gap_1()
 9230                            .py_1()
 9231                            .px_2()
 9232                            .child(
 9233                                h_flex()
 9234                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9235                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9236                                    .child(h_flex().children(ui::render_modifiers(
 9237                                        &accept_keystroke.modifiers,
 9238                                        PlatformStyle::platform(),
 9239                                        Some(if !has_completion {
 9240                                            Color::Muted
 9241                                        } else {
 9242                                            Color::Default
 9243                                        }),
 9244                                        None,
 9245                                        false,
 9246                                    ))),
 9247                            )
 9248                            .child(Label::new("Preview").into_any_element())
 9249                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9250                    )
 9251                })
 9252                .into_any(),
 9253        )
 9254    }
 9255
 9256    fn render_edit_prediction_cursor_popover_preview(
 9257        &self,
 9258        completion: &InlineCompletionState,
 9259        cursor_point: Point,
 9260        style: &EditorStyle,
 9261        cx: &mut Context<Editor>,
 9262    ) -> Option<Div> {
 9263        use text::ToPoint as _;
 9264
 9265        fn render_relative_row_jump(
 9266            prefix: impl Into<String>,
 9267            current_row: u32,
 9268            target_row: u32,
 9269        ) -> Div {
 9270            let (row_diff, arrow) = if target_row < current_row {
 9271                (current_row - target_row, IconName::ArrowUp)
 9272            } else {
 9273                (target_row - current_row, IconName::ArrowDown)
 9274            };
 9275
 9276            h_flex()
 9277                .child(
 9278                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9279                        .color(Color::Muted)
 9280                        .size(LabelSize::Small),
 9281                )
 9282                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9283        }
 9284
 9285        match &completion.completion {
 9286            InlineCompletion::Move {
 9287                target, snapshot, ..
 9288            } => Some(
 9289                h_flex()
 9290                    .px_2()
 9291                    .gap_2()
 9292                    .flex_1()
 9293                    .child(
 9294                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9295                            Icon::new(IconName::ZedPredictDown)
 9296                        } else {
 9297                            Icon::new(IconName::ZedPredictUp)
 9298                        },
 9299                    )
 9300                    .child(Label::new("Jump to Edit")),
 9301            ),
 9302
 9303            InlineCompletion::Edit {
 9304                edits,
 9305                edit_preview,
 9306                snapshot,
 9307                display_mode: _,
 9308            } => {
 9309                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9310
 9311                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9312                    &snapshot,
 9313                    &edits,
 9314                    edit_preview.as_ref()?,
 9315                    true,
 9316                    cx,
 9317                )
 9318                .first_line_preview();
 9319
 9320                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9321                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9322
 9323                let preview = h_flex()
 9324                    .gap_1()
 9325                    .min_w_16()
 9326                    .child(styled_text)
 9327                    .when(has_more_lines, |parent| parent.child(""));
 9328
 9329                let left = if first_edit_row != cursor_point.row {
 9330                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9331                        .into_any_element()
 9332                } else {
 9333                    Icon::new(IconName::ZedPredict).into_any_element()
 9334                };
 9335
 9336                Some(
 9337                    h_flex()
 9338                        .h_full()
 9339                        .flex_1()
 9340                        .gap_2()
 9341                        .pr_1()
 9342                        .overflow_x_hidden()
 9343                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9344                        .child(left)
 9345                        .child(preview),
 9346                )
 9347            }
 9348        }
 9349    }
 9350
 9351    pub fn render_context_menu(
 9352        &self,
 9353        style: &EditorStyle,
 9354        max_height_in_lines: u32,
 9355        window: &mut Window,
 9356        cx: &mut Context<Editor>,
 9357    ) -> Option<AnyElement> {
 9358        let menu = self.context_menu.borrow();
 9359        let menu = menu.as_ref()?;
 9360        if !menu.visible() {
 9361            return None;
 9362        };
 9363        Some(menu.render(style, max_height_in_lines, window, cx))
 9364    }
 9365
 9366    fn render_context_menu_aside(
 9367        &mut self,
 9368        max_size: Size<Pixels>,
 9369        window: &mut Window,
 9370        cx: &mut Context<Editor>,
 9371    ) -> Option<AnyElement> {
 9372        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9373            if menu.visible() {
 9374                menu.render_aside(max_size, window, cx)
 9375            } else {
 9376                None
 9377            }
 9378        })
 9379    }
 9380
 9381    fn hide_context_menu(
 9382        &mut self,
 9383        window: &mut Window,
 9384        cx: &mut Context<Self>,
 9385    ) -> Option<CodeContextMenu> {
 9386        cx.notify();
 9387        self.completion_tasks.clear();
 9388        let context_menu = self.context_menu.borrow_mut().take();
 9389        self.stale_inline_completion_in_menu.take();
 9390        self.update_visible_inline_completion(window, cx);
 9391        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9392            if let Some(completion_provider) = &self.completion_provider {
 9393                completion_provider.selection_changed(None, window, cx);
 9394            }
 9395        }
 9396        context_menu
 9397    }
 9398
 9399    fn show_snippet_choices(
 9400        &mut self,
 9401        choices: &Vec<String>,
 9402        selection: Range<Anchor>,
 9403        cx: &mut Context<Self>,
 9404    ) {
 9405        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9406            (Some(a), Some(b)) if a == b => a,
 9407            _ => {
 9408                log::error!("expected anchor range to have matching buffer IDs");
 9409                return;
 9410            }
 9411        };
 9412        let multi_buffer = self.buffer().read(cx);
 9413        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9414            return;
 9415        };
 9416
 9417        let id = post_inc(&mut self.next_completion_id);
 9418        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9419        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9420            CompletionsMenu::new_snippet_choices(
 9421                id,
 9422                true,
 9423                choices,
 9424                selection,
 9425                buffer,
 9426                snippet_sort_order,
 9427            ),
 9428        ));
 9429    }
 9430
 9431    pub fn insert_snippet(
 9432        &mut self,
 9433        insertion_ranges: &[Range<usize>],
 9434        snippet: Snippet,
 9435        window: &mut Window,
 9436        cx: &mut Context<Self>,
 9437    ) -> Result<()> {
 9438        struct Tabstop<T> {
 9439            is_end_tabstop: bool,
 9440            ranges: Vec<Range<T>>,
 9441            choices: Option<Vec<String>>,
 9442        }
 9443
 9444        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9445            let snippet_text: Arc<str> = snippet.text.clone().into();
 9446            let edits = insertion_ranges
 9447                .iter()
 9448                .cloned()
 9449                .map(|range| (range, snippet_text.clone()));
 9450            let autoindent_mode = AutoindentMode::Block {
 9451                original_indent_columns: Vec::new(),
 9452            };
 9453            buffer.edit(edits, Some(autoindent_mode), cx);
 9454
 9455            let snapshot = &*buffer.read(cx);
 9456            let snippet = &snippet;
 9457            snippet
 9458                .tabstops
 9459                .iter()
 9460                .map(|tabstop| {
 9461                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9462                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9463                    });
 9464                    let mut tabstop_ranges = tabstop
 9465                        .ranges
 9466                        .iter()
 9467                        .flat_map(|tabstop_range| {
 9468                            let mut delta = 0_isize;
 9469                            insertion_ranges.iter().map(move |insertion_range| {
 9470                                let insertion_start = insertion_range.start as isize + delta;
 9471                                delta +=
 9472                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9473
 9474                                let start = ((insertion_start + tabstop_range.start) as usize)
 9475                                    .min(snapshot.len());
 9476                                let end = ((insertion_start + tabstop_range.end) as usize)
 9477                                    .min(snapshot.len());
 9478                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9479                            })
 9480                        })
 9481                        .collect::<Vec<_>>();
 9482                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9483
 9484                    Tabstop {
 9485                        is_end_tabstop,
 9486                        ranges: tabstop_ranges,
 9487                        choices: tabstop.choices.clone(),
 9488                    }
 9489                })
 9490                .collect::<Vec<_>>()
 9491        });
 9492        if let Some(tabstop) = tabstops.first() {
 9493            self.change_selections(Default::default(), window, cx, |s| {
 9494                // Reverse order so that the first range is the newest created selection.
 9495                // Completions will use it and autoscroll will prioritize it.
 9496                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9497            });
 9498
 9499            if let Some(choices) = &tabstop.choices {
 9500                if let Some(selection) = tabstop.ranges.first() {
 9501                    self.show_snippet_choices(choices, selection.clone(), cx)
 9502                }
 9503            }
 9504
 9505            // If we're already at the last tabstop and it's at the end of the snippet,
 9506            // we're done, we don't need to keep the state around.
 9507            if !tabstop.is_end_tabstop {
 9508                let choices = tabstops
 9509                    .iter()
 9510                    .map(|tabstop| tabstop.choices.clone())
 9511                    .collect();
 9512
 9513                let ranges = tabstops
 9514                    .into_iter()
 9515                    .map(|tabstop| tabstop.ranges)
 9516                    .collect::<Vec<_>>();
 9517
 9518                self.snippet_stack.push(SnippetState {
 9519                    active_index: 0,
 9520                    ranges,
 9521                    choices,
 9522                });
 9523            }
 9524
 9525            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9526            if self.autoclose_regions.is_empty() {
 9527                let snapshot = self.buffer.read(cx).snapshot(cx);
 9528                for selection in &mut self.selections.all::<Point>(cx) {
 9529                    let selection_head = selection.head();
 9530                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9531                        continue;
 9532                    };
 9533
 9534                    let mut bracket_pair = None;
 9535                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9536                    let prev_chars = snapshot
 9537                        .reversed_chars_at(selection_head)
 9538                        .collect::<String>();
 9539                    for (pair, enabled) in scope.brackets() {
 9540                        if enabled
 9541                            && pair.close
 9542                            && prev_chars.starts_with(pair.start.as_str())
 9543                            && next_chars.starts_with(pair.end.as_str())
 9544                        {
 9545                            bracket_pair = Some(pair.clone());
 9546                            break;
 9547                        }
 9548                    }
 9549                    if let Some(pair) = bracket_pair {
 9550                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9551                        let autoclose_enabled =
 9552                            self.use_autoclose && snapshot_settings.use_autoclose;
 9553                        if autoclose_enabled {
 9554                            let start = snapshot.anchor_after(selection_head);
 9555                            let end = snapshot.anchor_after(selection_head);
 9556                            self.autoclose_regions.push(AutocloseRegion {
 9557                                selection_id: selection.id,
 9558                                range: start..end,
 9559                                pair,
 9560                            });
 9561                        }
 9562                    }
 9563                }
 9564            }
 9565        }
 9566        Ok(())
 9567    }
 9568
 9569    pub fn move_to_next_snippet_tabstop(
 9570        &mut self,
 9571        window: &mut Window,
 9572        cx: &mut Context<Self>,
 9573    ) -> bool {
 9574        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9575    }
 9576
 9577    pub fn move_to_prev_snippet_tabstop(
 9578        &mut self,
 9579        window: &mut Window,
 9580        cx: &mut Context<Self>,
 9581    ) -> bool {
 9582        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9583    }
 9584
 9585    pub fn move_to_snippet_tabstop(
 9586        &mut self,
 9587        bias: Bias,
 9588        window: &mut Window,
 9589        cx: &mut Context<Self>,
 9590    ) -> bool {
 9591        if let Some(mut snippet) = self.snippet_stack.pop() {
 9592            match bias {
 9593                Bias::Left => {
 9594                    if snippet.active_index > 0 {
 9595                        snippet.active_index -= 1;
 9596                    } else {
 9597                        self.snippet_stack.push(snippet);
 9598                        return false;
 9599                    }
 9600                }
 9601                Bias::Right => {
 9602                    if snippet.active_index + 1 < snippet.ranges.len() {
 9603                        snippet.active_index += 1;
 9604                    } else {
 9605                        self.snippet_stack.push(snippet);
 9606                        return false;
 9607                    }
 9608                }
 9609            }
 9610            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9611                self.change_selections(Default::default(), window, cx, |s| {
 9612                    // Reverse order so that the first range is the newest created selection.
 9613                    // Completions will use it and autoscroll will prioritize it.
 9614                    s.select_ranges(current_ranges.iter().rev().cloned())
 9615                });
 9616
 9617                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9618                    if let Some(selection) = current_ranges.first() {
 9619                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9620                    }
 9621                }
 9622
 9623                // If snippet state is not at the last tabstop, push it back on the stack
 9624                if snippet.active_index + 1 < snippet.ranges.len() {
 9625                    self.snippet_stack.push(snippet);
 9626                }
 9627                return true;
 9628            }
 9629        }
 9630
 9631        false
 9632    }
 9633
 9634    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9635        self.transact(window, cx, |this, window, cx| {
 9636            this.select_all(&SelectAll, window, cx);
 9637            this.insert("", window, cx);
 9638        });
 9639    }
 9640
 9641    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9642        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9643        self.transact(window, cx, |this, window, cx| {
 9644            this.select_autoclose_pair(window, cx);
 9645            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9646            if !this.linked_edit_ranges.is_empty() {
 9647                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9648                let snapshot = this.buffer.read(cx).snapshot(cx);
 9649
 9650                for selection in selections.iter() {
 9651                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9652                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9653                    if selection_start.buffer_id != selection_end.buffer_id {
 9654                        continue;
 9655                    }
 9656                    if let Some(ranges) =
 9657                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9658                    {
 9659                        for (buffer, entries) in ranges {
 9660                            linked_ranges.entry(buffer).or_default().extend(entries);
 9661                        }
 9662                    }
 9663                }
 9664            }
 9665
 9666            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9667            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9668            for selection in &mut selections {
 9669                if selection.is_empty() {
 9670                    let old_head = selection.head();
 9671                    let mut new_head =
 9672                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9673                            .to_point(&display_map);
 9674                    if let Some((buffer, line_buffer_range)) = display_map
 9675                        .buffer_snapshot
 9676                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9677                    {
 9678                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9679                        let indent_len = match indent_size.kind {
 9680                            IndentKind::Space => {
 9681                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9682                            }
 9683                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9684                        };
 9685                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9686                            let indent_len = indent_len.get();
 9687                            new_head = cmp::min(
 9688                                new_head,
 9689                                MultiBufferPoint::new(
 9690                                    old_head.row,
 9691                                    ((old_head.column - 1) / indent_len) * indent_len,
 9692                                ),
 9693                            );
 9694                        }
 9695                    }
 9696
 9697                    selection.set_head(new_head, SelectionGoal::None);
 9698                }
 9699            }
 9700
 9701            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9702            this.insert("", window, cx);
 9703            let empty_str: Arc<str> = Arc::from("");
 9704            for (buffer, edits) in linked_ranges {
 9705                let snapshot = buffer.read(cx).snapshot();
 9706                use text::ToPoint as TP;
 9707
 9708                let edits = edits
 9709                    .into_iter()
 9710                    .map(|range| {
 9711                        let end_point = TP::to_point(&range.end, &snapshot);
 9712                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9713
 9714                        if end_point == start_point {
 9715                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9716                                .saturating_sub(1);
 9717                            start_point =
 9718                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9719                        };
 9720
 9721                        (start_point..end_point, empty_str.clone())
 9722                    })
 9723                    .sorted_by_key(|(range, _)| range.start)
 9724                    .collect::<Vec<_>>();
 9725                buffer.update(cx, |this, cx| {
 9726                    this.edit(edits, None, cx);
 9727                })
 9728            }
 9729            this.refresh_inline_completion(true, false, window, cx);
 9730            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9731        });
 9732    }
 9733
 9734    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9735        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9736        self.transact(window, cx, |this, window, cx| {
 9737            this.change_selections(Default::default(), window, cx, |s| {
 9738                s.move_with(|map, selection| {
 9739                    if selection.is_empty() {
 9740                        let cursor = movement::right(map, selection.head());
 9741                        selection.end = cursor;
 9742                        selection.reversed = true;
 9743                        selection.goal = SelectionGoal::None;
 9744                    }
 9745                })
 9746            });
 9747            this.insert("", window, cx);
 9748            this.refresh_inline_completion(true, false, window, cx);
 9749        });
 9750    }
 9751
 9752    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9753        if self.mode.is_single_line() {
 9754            cx.propagate();
 9755            return;
 9756        }
 9757
 9758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9759        if self.move_to_prev_snippet_tabstop(window, cx) {
 9760            return;
 9761        }
 9762        self.outdent(&Outdent, window, cx);
 9763    }
 9764
 9765    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9766        if self.mode.is_single_line() {
 9767            cx.propagate();
 9768            return;
 9769        }
 9770
 9771        if self.move_to_next_snippet_tabstop(window, cx) {
 9772            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9773            return;
 9774        }
 9775        if self.read_only(cx) {
 9776            return;
 9777        }
 9778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9779        let mut selections = self.selections.all_adjusted(cx);
 9780        let buffer = self.buffer.read(cx);
 9781        let snapshot = buffer.snapshot(cx);
 9782        let rows_iter = selections.iter().map(|s| s.head().row);
 9783        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9784
 9785        let has_some_cursor_in_whitespace = selections
 9786            .iter()
 9787            .filter(|selection| selection.is_empty())
 9788            .any(|selection| {
 9789                let cursor = selection.head();
 9790                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9791                cursor.column < current_indent.len
 9792            });
 9793
 9794        let mut edits = Vec::new();
 9795        let mut prev_edited_row = 0;
 9796        let mut row_delta = 0;
 9797        for selection in &mut selections {
 9798            if selection.start.row != prev_edited_row {
 9799                row_delta = 0;
 9800            }
 9801            prev_edited_row = selection.end.row;
 9802
 9803            // If the selection is non-empty, then increase the indentation of the selected lines.
 9804            if !selection.is_empty() {
 9805                row_delta =
 9806                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9807                continue;
 9808            }
 9809
 9810            let cursor = selection.head();
 9811            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9812            if let Some(suggested_indent) =
 9813                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9814            {
 9815                // Don't do anything if already at suggested indent
 9816                // and there is any other cursor which is not
 9817                if has_some_cursor_in_whitespace
 9818                    && cursor.column == current_indent.len
 9819                    && current_indent.len == suggested_indent.len
 9820                {
 9821                    continue;
 9822                }
 9823
 9824                // Adjust line and move cursor to suggested indent
 9825                // if cursor is not at suggested indent
 9826                if cursor.column < suggested_indent.len
 9827                    && cursor.column <= current_indent.len
 9828                    && current_indent.len <= suggested_indent.len
 9829                {
 9830                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9831                    selection.end = selection.start;
 9832                    if row_delta == 0 {
 9833                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9834                            cursor.row,
 9835                            current_indent,
 9836                            suggested_indent,
 9837                        ));
 9838                        row_delta = suggested_indent.len - current_indent.len;
 9839                    }
 9840                    continue;
 9841                }
 9842
 9843                // If current indent is more than suggested indent
 9844                // only move cursor to current indent and skip indent
 9845                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9846                    selection.start = Point::new(cursor.row, current_indent.len);
 9847                    selection.end = selection.start;
 9848                    continue;
 9849                }
 9850            }
 9851
 9852            // Otherwise, insert a hard or soft tab.
 9853            let settings = buffer.language_settings_at(cursor, cx);
 9854            let tab_size = if settings.hard_tabs {
 9855                IndentSize::tab()
 9856            } else {
 9857                let tab_size = settings.tab_size.get();
 9858                let indent_remainder = snapshot
 9859                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9860                    .flat_map(str::chars)
 9861                    .fold(row_delta % tab_size, |counter: u32, c| {
 9862                        if c == '\t' {
 9863                            0
 9864                        } else {
 9865                            (counter + 1) % tab_size
 9866                        }
 9867                    });
 9868
 9869                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9870                IndentSize::spaces(chars_to_next_tab_stop)
 9871            };
 9872            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9873            selection.end = selection.start;
 9874            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9875            row_delta += tab_size.len;
 9876        }
 9877
 9878        self.transact(window, cx, |this, window, cx| {
 9879            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9880            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9881            this.refresh_inline_completion(true, false, window, cx);
 9882        });
 9883    }
 9884
 9885    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9886        if self.read_only(cx) {
 9887            return;
 9888        }
 9889        if self.mode.is_single_line() {
 9890            cx.propagate();
 9891            return;
 9892        }
 9893
 9894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9895        let mut selections = self.selections.all::<Point>(cx);
 9896        let mut prev_edited_row = 0;
 9897        let mut row_delta = 0;
 9898        let mut edits = Vec::new();
 9899        let buffer = self.buffer.read(cx);
 9900        let snapshot = buffer.snapshot(cx);
 9901        for selection in &mut selections {
 9902            if selection.start.row != prev_edited_row {
 9903                row_delta = 0;
 9904            }
 9905            prev_edited_row = selection.end.row;
 9906
 9907            row_delta =
 9908                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9909        }
 9910
 9911        self.transact(window, cx, |this, window, cx| {
 9912            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9913            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9914        });
 9915    }
 9916
 9917    fn indent_selection(
 9918        buffer: &MultiBuffer,
 9919        snapshot: &MultiBufferSnapshot,
 9920        selection: &mut Selection<Point>,
 9921        edits: &mut Vec<(Range<Point>, String)>,
 9922        delta_for_start_row: u32,
 9923        cx: &App,
 9924    ) -> u32 {
 9925        let settings = buffer.language_settings_at(selection.start, cx);
 9926        let tab_size = settings.tab_size.get();
 9927        let indent_kind = if settings.hard_tabs {
 9928            IndentKind::Tab
 9929        } else {
 9930            IndentKind::Space
 9931        };
 9932        let mut start_row = selection.start.row;
 9933        let mut end_row = selection.end.row + 1;
 9934
 9935        // If a selection ends at the beginning of a line, don't indent
 9936        // that last line.
 9937        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9938            end_row -= 1;
 9939        }
 9940
 9941        // Avoid re-indenting a row that has already been indented by a
 9942        // previous selection, but still update this selection's column
 9943        // to reflect that indentation.
 9944        if delta_for_start_row > 0 {
 9945            start_row += 1;
 9946            selection.start.column += delta_for_start_row;
 9947            if selection.end.row == selection.start.row {
 9948                selection.end.column += delta_for_start_row;
 9949            }
 9950        }
 9951
 9952        let mut delta_for_end_row = 0;
 9953        let has_multiple_rows = start_row + 1 != end_row;
 9954        for row in start_row..end_row {
 9955            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9956            let indent_delta = match (current_indent.kind, indent_kind) {
 9957                (IndentKind::Space, IndentKind::Space) => {
 9958                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9959                    IndentSize::spaces(columns_to_next_tab_stop)
 9960                }
 9961                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9962                (_, IndentKind::Tab) => IndentSize::tab(),
 9963            };
 9964
 9965            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9966                0
 9967            } else {
 9968                selection.start.column
 9969            };
 9970            let row_start = Point::new(row, start);
 9971            edits.push((
 9972                row_start..row_start,
 9973                indent_delta.chars().collect::<String>(),
 9974            ));
 9975
 9976            // Update this selection's endpoints to reflect the indentation.
 9977            if row == selection.start.row {
 9978                selection.start.column += indent_delta.len;
 9979            }
 9980            if row == selection.end.row {
 9981                selection.end.column += indent_delta.len;
 9982                delta_for_end_row = indent_delta.len;
 9983            }
 9984        }
 9985
 9986        if selection.start.row == selection.end.row {
 9987            delta_for_start_row + delta_for_end_row
 9988        } else {
 9989            delta_for_end_row
 9990        }
 9991    }
 9992
 9993    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9994        if self.read_only(cx) {
 9995            return;
 9996        }
 9997        if self.mode.is_single_line() {
 9998            cx.propagate();
 9999            return;
10000        }
10001
10002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10003        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10004        let selections = self.selections.all::<Point>(cx);
10005        let mut deletion_ranges = Vec::new();
10006        let mut last_outdent = None;
10007        {
10008            let buffer = self.buffer.read(cx);
10009            let snapshot = buffer.snapshot(cx);
10010            for selection in &selections {
10011                let settings = buffer.language_settings_at(selection.start, cx);
10012                let tab_size = settings.tab_size.get();
10013                let mut rows = selection.spanned_rows(false, &display_map);
10014
10015                // Avoid re-outdenting a row that has already been outdented by a
10016                // previous selection.
10017                if let Some(last_row) = last_outdent {
10018                    if last_row == rows.start {
10019                        rows.start = rows.start.next_row();
10020                    }
10021                }
10022                let has_multiple_rows = rows.len() > 1;
10023                for row in rows.iter_rows() {
10024                    let indent_size = snapshot.indent_size_for_line(row);
10025                    if indent_size.len > 0 {
10026                        let deletion_len = match indent_size.kind {
10027                            IndentKind::Space => {
10028                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10029                                if columns_to_prev_tab_stop == 0 {
10030                                    tab_size
10031                                } else {
10032                                    columns_to_prev_tab_stop
10033                                }
10034                            }
10035                            IndentKind::Tab => 1,
10036                        };
10037                        let start = if has_multiple_rows
10038                            || deletion_len > selection.start.column
10039                            || indent_size.len < selection.start.column
10040                        {
10041                            0
10042                        } else {
10043                            selection.start.column - deletion_len
10044                        };
10045                        deletion_ranges.push(
10046                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10047                        );
10048                        last_outdent = Some(row);
10049                    }
10050                }
10051            }
10052        }
10053
10054        self.transact(window, cx, |this, window, cx| {
10055            this.buffer.update(cx, |buffer, cx| {
10056                let empty_str: Arc<str> = Arc::default();
10057                buffer.edit(
10058                    deletion_ranges
10059                        .into_iter()
10060                        .map(|range| (range, empty_str.clone())),
10061                    None,
10062                    cx,
10063                );
10064            });
10065            let selections = this.selections.all::<usize>(cx);
10066            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10067        });
10068    }
10069
10070    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10071        if self.read_only(cx) {
10072            return;
10073        }
10074        if self.mode.is_single_line() {
10075            cx.propagate();
10076            return;
10077        }
10078
10079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10080        let selections = self
10081            .selections
10082            .all::<usize>(cx)
10083            .into_iter()
10084            .map(|s| s.range());
10085
10086        self.transact(window, cx, |this, window, cx| {
10087            this.buffer.update(cx, |buffer, cx| {
10088                buffer.autoindent_ranges(selections, cx);
10089            });
10090            let selections = this.selections.all::<usize>(cx);
10091            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10092        });
10093    }
10094
10095    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10097        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10098        let selections = self.selections.all::<Point>(cx);
10099
10100        let mut new_cursors = Vec::new();
10101        let mut edit_ranges = Vec::new();
10102        let mut selections = selections.iter().peekable();
10103        while let Some(selection) = selections.next() {
10104            let mut rows = selection.spanned_rows(false, &display_map);
10105            let goal_display_column = selection.head().to_display_point(&display_map).column();
10106
10107            // Accumulate contiguous regions of rows that we want to delete.
10108            while let Some(next_selection) = selections.peek() {
10109                let next_rows = next_selection.spanned_rows(false, &display_map);
10110                if next_rows.start <= rows.end {
10111                    rows.end = next_rows.end;
10112                    selections.next().unwrap();
10113                } else {
10114                    break;
10115                }
10116            }
10117
10118            let buffer = &display_map.buffer_snapshot;
10119            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10120            let edit_end;
10121            let cursor_buffer_row;
10122            if buffer.max_point().row >= rows.end.0 {
10123                // If there's a line after the range, delete the \n from the end of the row range
10124                // and position the cursor on the next line.
10125                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10126                cursor_buffer_row = rows.end;
10127            } else {
10128                // If there isn't a line after the range, delete the \n from the line before the
10129                // start of the row range and position the cursor there.
10130                edit_start = edit_start.saturating_sub(1);
10131                edit_end = buffer.len();
10132                cursor_buffer_row = rows.start.previous_row();
10133            }
10134
10135            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10136            *cursor.column_mut() =
10137                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10138
10139            new_cursors.push((
10140                selection.id,
10141                buffer.anchor_after(cursor.to_point(&display_map)),
10142            ));
10143            edit_ranges.push(edit_start..edit_end);
10144        }
10145
10146        self.transact(window, cx, |this, window, cx| {
10147            let buffer = this.buffer.update(cx, |buffer, cx| {
10148                let empty_str: Arc<str> = Arc::default();
10149                buffer.edit(
10150                    edit_ranges
10151                        .into_iter()
10152                        .map(|range| (range, empty_str.clone())),
10153                    None,
10154                    cx,
10155                );
10156                buffer.snapshot(cx)
10157            });
10158            let new_selections = new_cursors
10159                .into_iter()
10160                .map(|(id, cursor)| {
10161                    let cursor = cursor.to_point(&buffer);
10162                    Selection {
10163                        id,
10164                        start: cursor,
10165                        end: cursor,
10166                        reversed: false,
10167                        goal: SelectionGoal::None,
10168                    }
10169                })
10170                .collect();
10171
10172            this.change_selections(Default::default(), window, cx, |s| {
10173                s.select(new_selections);
10174            });
10175        });
10176    }
10177
10178    pub fn join_lines_impl(
10179        &mut self,
10180        insert_whitespace: bool,
10181        window: &mut Window,
10182        cx: &mut Context<Self>,
10183    ) {
10184        if self.read_only(cx) {
10185            return;
10186        }
10187        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10188        for selection in self.selections.all::<Point>(cx) {
10189            let start = MultiBufferRow(selection.start.row);
10190            // Treat single line selections as if they include the next line. Otherwise this action
10191            // would do nothing for single line selections individual cursors.
10192            let end = if selection.start.row == selection.end.row {
10193                MultiBufferRow(selection.start.row + 1)
10194            } else {
10195                MultiBufferRow(selection.end.row)
10196            };
10197
10198            if let Some(last_row_range) = row_ranges.last_mut() {
10199                if start <= last_row_range.end {
10200                    last_row_range.end = end;
10201                    continue;
10202                }
10203            }
10204            row_ranges.push(start..end);
10205        }
10206
10207        let snapshot = self.buffer.read(cx).snapshot(cx);
10208        let mut cursor_positions = Vec::new();
10209        for row_range in &row_ranges {
10210            let anchor = snapshot.anchor_before(Point::new(
10211                row_range.end.previous_row().0,
10212                snapshot.line_len(row_range.end.previous_row()),
10213            ));
10214            cursor_positions.push(anchor..anchor);
10215        }
10216
10217        self.transact(window, cx, |this, window, cx| {
10218            for row_range in row_ranges.into_iter().rev() {
10219                for row in row_range.iter_rows().rev() {
10220                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10221                    let next_line_row = row.next_row();
10222                    let indent = snapshot.indent_size_for_line(next_line_row);
10223                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10224
10225                    let replace =
10226                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10227                            " "
10228                        } else {
10229                            ""
10230                        };
10231
10232                    this.buffer.update(cx, |buffer, cx| {
10233                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10234                    });
10235                }
10236            }
10237
10238            this.change_selections(Default::default(), window, cx, |s| {
10239                s.select_anchor_ranges(cursor_positions)
10240            });
10241        });
10242    }
10243
10244    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10246        self.join_lines_impl(true, window, cx);
10247    }
10248
10249    pub fn sort_lines_case_sensitive(
10250        &mut self,
10251        _: &SortLinesCaseSensitive,
10252        window: &mut Window,
10253        cx: &mut Context<Self>,
10254    ) {
10255        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10256    }
10257
10258    pub fn sort_lines_by_length(
10259        &mut self,
10260        _: &SortLinesByLength,
10261        window: &mut Window,
10262        cx: &mut Context<Self>,
10263    ) {
10264        self.manipulate_immutable_lines(window, cx, |lines| {
10265            lines.sort_by_key(|&line| line.chars().count())
10266        })
10267    }
10268
10269    pub fn sort_lines_case_insensitive(
10270        &mut self,
10271        _: &SortLinesCaseInsensitive,
10272        window: &mut Window,
10273        cx: &mut Context<Self>,
10274    ) {
10275        self.manipulate_immutable_lines(window, cx, |lines| {
10276            lines.sort_by_key(|line| line.to_lowercase())
10277        })
10278    }
10279
10280    pub fn unique_lines_case_insensitive(
10281        &mut self,
10282        _: &UniqueLinesCaseInsensitive,
10283        window: &mut Window,
10284        cx: &mut Context<Self>,
10285    ) {
10286        self.manipulate_immutable_lines(window, cx, |lines| {
10287            let mut seen = HashSet::default();
10288            lines.retain(|line| seen.insert(line.to_lowercase()));
10289        })
10290    }
10291
10292    pub fn unique_lines_case_sensitive(
10293        &mut self,
10294        _: &UniqueLinesCaseSensitive,
10295        window: &mut Window,
10296        cx: &mut Context<Self>,
10297    ) {
10298        self.manipulate_immutable_lines(window, cx, |lines| {
10299            let mut seen = HashSet::default();
10300            lines.retain(|line| seen.insert(*line));
10301        })
10302    }
10303
10304    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10305        let Some(project) = self.project.clone() else {
10306            return;
10307        };
10308        self.reload(project, window, cx)
10309            .detach_and_notify_err(window, cx);
10310    }
10311
10312    pub fn restore_file(
10313        &mut self,
10314        _: &::git::RestoreFile,
10315        window: &mut Window,
10316        cx: &mut Context<Self>,
10317    ) {
10318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10319        let mut buffer_ids = HashSet::default();
10320        let snapshot = self.buffer().read(cx).snapshot(cx);
10321        for selection in self.selections.all::<usize>(cx) {
10322            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10323        }
10324
10325        let buffer = self.buffer().read(cx);
10326        let ranges = buffer_ids
10327            .into_iter()
10328            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10329            .collect::<Vec<_>>();
10330
10331        self.restore_hunks_in_ranges(ranges, window, cx);
10332    }
10333
10334    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10336        let selections = self
10337            .selections
10338            .all(cx)
10339            .into_iter()
10340            .map(|s| s.range())
10341            .collect();
10342        self.restore_hunks_in_ranges(selections, window, cx);
10343    }
10344
10345    pub fn restore_hunks_in_ranges(
10346        &mut self,
10347        ranges: Vec<Range<Point>>,
10348        window: &mut Window,
10349        cx: &mut Context<Editor>,
10350    ) {
10351        let mut revert_changes = HashMap::default();
10352        let chunk_by = self
10353            .snapshot(window, cx)
10354            .hunks_for_ranges(ranges)
10355            .into_iter()
10356            .chunk_by(|hunk| hunk.buffer_id);
10357        for (buffer_id, hunks) in &chunk_by {
10358            let hunks = hunks.collect::<Vec<_>>();
10359            for hunk in &hunks {
10360                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10361            }
10362            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10363        }
10364        drop(chunk_by);
10365        if !revert_changes.is_empty() {
10366            self.transact(window, cx, |editor, window, cx| {
10367                editor.restore(revert_changes, window, cx);
10368            });
10369        }
10370    }
10371
10372    pub fn open_active_item_in_terminal(
10373        &mut self,
10374        _: &OpenInTerminal,
10375        window: &mut Window,
10376        cx: &mut Context<Self>,
10377    ) {
10378        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10379            let project_path = buffer.read(cx).project_path(cx)?;
10380            let project = self.project.as_ref()?.read(cx);
10381            let entry = project.entry_for_path(&project_path, cx)?;
10382            let parent = match &entry.canonical_path {
10383                Some(canonical_path) => canonical_path.to_path_buf(),
10384                None => project.absolute_path(&project_path, cx)?,
10385            }
10386            .parent()?
10387            .to_path_buf();
10388            Some(parent)
10389        }) {
10390            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10391        }
10392    }
10393
10394    fn set_breakpoint_context_menu(
10395        &mut self,
10396        display_row: DisplayRow,
10397        position: Option<Anchor>,
10398        clicked_point: gpui::Point<Pixels>,
10399        window: &mut Window,
10400        cx: &mut Context<Self>,
10401    ) {
10402        let source = self
10403            .buffer
10404            .read(cx)
10405            .snapshot(cx)
10406            .anchor_before(Point::new(display_row.0, 0u32));
10407
10408        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10409
10410        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10411            self,
10412            source,
10413            clicked_point,
10414            context_menu,
10415            window,
10416            cx,
10417        );
10418    }
10419
10420    fn add_edit_breakpoint_block(
10421        &mut self,
10422        anchor: Anchor,
10423        breakpoint: &Breakpoint,
10424        edit_action: BreakpointPromptEditAction,
10425        window: &mut Window,
10426        cx: &mut Context<Self>,
10427    ) {
10428        let weak_editor = cx.weak_entity();
10429        let bp_prompt = cx.new(|cx| {
10430            BreakpointPromptEditor::new(
10431                weak_editor,
10432                anchor,
10433                breakpoint.clone(),
10434                edit_action,
10435                window,
10436                cx,
10437            )
10438        });
10439
10440        let height = bp_prompt.update(cx, |this, cx| {
10441            this.prompt
10442                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10443        });
10444        let cloned_prompt = bp_prompt.clone();
10445        let blocks = vec![BlockProperties {
10446            style: BlockStyle::Sticky,
10447            placement: BlockPlacement::Above(anchor),
10448            height: Some(height),
10449            render: Arc::new(move |cx| {
10450                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10451                cloned_prompt.clone().into_any_element()
10452            }),
10453            priority: 0,
10454        }];
10455
10456        let focus_handle = bp_prompt.focus_handle(cx);
10457        window.focus(&focus_handle);
10458
10459        let block_ids = self.insert_blocks(blocks, None, cx);
10460        bp_prompt.update(cx, |prompt, _| {
10461            prompt.add_block_ids(block_ids);
10462        });
10463    }
10464
10465    pub(crate) fn breakpoint_at_row(
10466        &self,
10467        row: u32,
10468        window: &mut Window,
10469        cx: &mut Context<Self>,
10470    ) -> Option<(Anchor, Breakpoint)> {
10471        let snapshot = self.snapshot(window, cx);
10472        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10473
10474        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10475    }
10476
10477    pub(crate) fn breakpoint_at_anchor(
10478        &self,
10479        breakpoint_position: Anchor,
10480        snapshot: &EditorSnapshot,
10481        cx: &mut Context<Self>,
10482    ) -> Option<(Anchor, Breakpoint)> {
10483        let project = self.project.clone()?;
10484
10485        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10486            snapshot
10487                .buffer_snapshot
10488                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10489        })?;
10490
10491        let enclosing_excerpt = breakpoint_position.excerpt_id;
10492        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10493        let buffer_snapshot = buffer.read(cx).snapshot();
10494
10495        let row = buffer_snapshot
10496            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10497            .row;
10498
10499        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10500        let anchor_end = snapshot
10501            .buffer_snapshot
10502            .anchor_after(Point::new(row, line_len));
10503
10504        let bp = self
10505            .breakpoint_store
10506            .as_ref()?
10507            .read_with(cx, |breakpoint_store, cx| {
10508                breakpoint_store
10509                    .breakpoints(
10510                        &buffer,
10511                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10512                        &buffer_snapshot,
10513                        cx,
10514                    )
10515                    .next()
10516                    .and_then(|(bp, _)| {
10517                        let breakpoint_row = buffer_snapshot
10518                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10519                            .row;
10520
10521                        if breakpoint_row == row {
10522                            snapshot
10523                                .buffer_snapshot
10524                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10525                                .map(|position| (position, bp.bp.clone()))
10526                        } else {
10527                            None
10528                        }
10529                    })
10530            });
10531        bp
10532    }
10533
10534    pub fn edit_log_breakpoint(
10535        &mut self,
10536        _: &EditLogBreakpoint,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) {
10540        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10541            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10542                message: None,
10543                state: BreakpointState::Enabled,
10544                condition: None,
10545                hit_condition: None,
10546            });
10547
10548            self.add_edit_breakpoint_block(
10549                anchor,
10550                &breakpoint,
10551                BreakpointPromptEditAction::Log,
10552                window,
10553                cx,
10554            );
10555        }
10556    }
10557
10558    fn breakpoints_at_cursors(
10559        &self,
10560        window: &mut Window,
10561        cx: &mut Context<Self>,
10562    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10563        let snapshot = self.snapshot(window, cx);
10564        let cursors = self
10565            .selections
10566            .disjoint_anchors()
10567            .into_iter()
10568            .map(|selection| {
10569                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10570
10571                let breakpoint_position = self
10572                    .breakpoint_at_row(cursor_position.row, window, cx)
10573                    .map(|bp| bp.0)
10574                    .unwrap_or_else(|| {
10575                        snapshot
10576                            .display_snapshot
10577                            .buffer_snapshot
10578                            .anchor_after(Point::new(cursor_position.row, 0))
10579                    });
10580
10581                let breakpoint = self
10582                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10583                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10584
10585                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10586            })
10587            // 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.
10588            .collect::<HashMap<Anchor, _>>();
10589
10590        cursors.into_iter().collect()
10591    }
10592
10593    pub fn enable_breakpoint(
10594        &mut self,
10595        _: &crate::actions::EnableBreakpoint,
10596        window: &mut Window,
10597        cx: &mut Context<Self>,
10598    ) {
10599        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10600            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10601                continue;
10602            };
10603            self.edit_breakpoint_at_anchor(
10604                anchor,
10605                breakpoint,
10606                BreakpointEditAction::InvertState,
10607                cx,
10608            );
10609        }
10610    }
10611
10612    pub fn disable_breakpoint(
10613        &mut self,
10614        _: &crate::actions::DisableBreakpoint,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10619            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10620                continue;
10621            };
10622            self.edit_breakpoint_at_anchor(
10623                anchor,
10624                breakpoint,
10625                BreakpointEditAction::InvertState,
10626                cx,
10627            );
10628        }
10629    }
10630
10631    pub fn toggle_breakpoint(
10632        &mut self,
10633        _: &crate::actions::ToggleBreakpoint,
10634        window: &mut Window,
10635        cx: &mut Context<Self>,
10636    ) {
10637        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10638            if let Some(breakpoint) = breakpoint {
10639                self.edit_breakpoint_at_anchor(
10640                    anchor,
10641                    breakpoint,
10642                    BreakpointEditAction::Toggle,
10643                    cx,
10644                );
10645            } else {
10646                self.edit_breakpoint_at_anchor(
10647                    anchor,
10648                    Breakpoint::new_standard(),
10649                    BreakpointEditAction::Toggle,
10650                    cx,
10651                );
10652            }
10653        }
10654    }
10655
10656    pub fn edit_breakpoint_at_anchor(
10657        &mut self,
10658        breakpoint_position: Anchor,
10659        breakpoint: Breakpoint,
10660        edit_action: BreakpointEditAction,
10661        cx: &mut Context<Self>,
10662    ) {
10663        let Some(breakpoint_store) = &self.breakpoint_store else {
10664            return;
10665        };
10666
10667        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10668            if breakpoint_position == Anchor::min() {
10669                self.buffer()
10670                    .read(cx)
10671                    .excerpt_buffer_ids()
10672                    .into_iter()
10673                    .next()
10674            } else {
10675                None
10676            }
10677        }) else {
10678            return;
10679        };
10680
10681        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10682            return;
10683        };
10684
10685        breakpoint_store.update(cx, |breakpoint_store, cx| {
10686            breakpoint_store.toggle_breakpoint(
10687                buffer,
10688                BreakpointWithPosition {
10689                    position: breakpoint_position.text_anchor,
10690                    bp: breakpoint,
10691                },
10692                edit_action,
10693                cx,
10694            );
10695        });
10696
10697        cx.notify();
10698    }
10699
10700    #[cfg(any(test, feature = "test-support"))]
10701    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10702        self.breakpoint_store.clone()
10703    }
10704
10705    pub fn prepare_restore_change(
10706        &self,
10707        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10708        hunk: &MultiBufferDiffHunk,
10709        cx: &mut App,
10710    ) -> Option<()> {
10711        if hunk.is_created_file() {
10712            return None;
10713        }
10714        let buffer = self.buffer.read(cx);
10715        let diff = buffer.diff_for(hunk.buffer_id)?;
10716        let buffer = buffer.buffer(hunk.buffer_id)?;
10717        let buffer = buffer.read(cx);
10718        let original_text = diff
10719            .read(cx)
10720            .base_text()
10721            .as_rope()
10722            .slice(hunk.diff_base_byte_range.clone());
10723        let buffer_snapshot = buffer.snapshot();
10724        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10725        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10726            probe
10727                .0
10728                .start
10729                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10730                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10731        }) {
10732            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10733            Some(())
10734        } else {
10735            None
10736        }
10737    }
10738
10739    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10740        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10741    }
10742
10743    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10744        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10745    }
10746
10747    fn manipulate_lines<M>(
10748        &mut self,
10749        window: &mut Window,
10750        cx: &mut Context<Self>,
10751        mut manipulate: M,
10752    ) where
10753        M: FnMut(&str) -> LineManipulationResult,
10754    {
10755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10756
10757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10758        let buffer = self.buffer.read(cx).snapshot(cx);
10759
10760        let mut edits = Vec::new();
10761
10762        let selections = self.selections.all::<Point>(cx);
10763        let mut selections = selections.iter().peekable();
10764        let mut contiguous_row_selections = Vec::new();
10765        let mut new_selections = Vec::new();
10766        let mut added_lines = 0;
10767        let mut removed_lines = 0;
10768
10769        while let Some(selection) = selections.next() {
10770            let (start_row, end_row) = consume_contiguous_rows(
10771                &mut contiguous_row_selections,
10772                selection,
10773                &display_map,
10774                &mut selections,
10775            );
10776
10777            let start_point = Point::new(start_row.0, 0);
10778            let end_point = Point::new(
10779                end_row.previous_row().0,
10780                buffer.line_len(end_row.previous_row()),
10781            );
10782            let text = buffer
10783                .text_for_range(start_point..end_point)
10784                .collect::<String>();
10785
10786            let LineManipulationResult {
10787                new_text,
10788                line_count_before,
10789                line_count_after,
10790            } = manipulate(&text);
10791
10792            edits.push((start_point..end_point, new_text));
10793
10794            // Selections must change based on added and removed line count
10795            let start_row =
10796                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10797            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10798            new_selections.push(Selection {
10799                id: selection.id,
10800                start: start_row,
10801                end: end_row,
10802                goal: SelectionGoal::None,
10803                reversed: selection.reversed,
10804            });
10805
10806            if line_count_after > line_count_before {
10807                added_lines += line_count_after - line_count_before;
10808            } else if line_count_before > line_count_after {
10809                removed_lines += line_count_before - line_count_after;
10810            }
10811        }
10812
10813        self.transact(window, cx, |this, window, cx| {
10814            let buffer = this.buffer.update(cx, |buffer, cx| {
10815                buffer.edit(edits, None, cx);
10816                buffer.snapshot(cx)
10817            });
10818
10819            // Recalculate offsets on newly edited buffer
10820            let new_selections = new_selections
10821                .iter()
10822                .map(|s| {
10823                    let start_point = Point::new(s.start.0, 0);
10824                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10825                    Selection {
10826                        id: s.id,
10827                        start: buffer.point_to_offset(start_point),
10828                        end: buffer.point_to_offset(end_point),
10829                        goal: s.goal,
10830                        reversed: s.reversed,
10831                    }
10832                })
10833                .collect();
10834
10835            this.change_selections(Default::default(), window, cx, |s| {
10836                s.select(new_selections);
10837            });
10838
10839            this.request_autoscroll(Autoscroll::fit(), cx);
10840        });
10841    }
10842
10843    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10844        self.manipulate_text(window, cx, |text| {
10845            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10846            if has_upper_case_characters {
10847                text.to_lowercase()
10848            } else {
10849                text.to_uppercase()
10850            }
10851        })
10852    }
10853
10854    fn manipulate_immutable_lines<Fn>(
10855        &mut self,
10856        window: &mut Window,
10857        cx: &mut Context<Self>,
10858        mut callback: Fn,
10859    ) where
10860        Fn: FnMut(&mut Vec<&str>),
10861    {
10862        self.manipulate_lines(window, cx, |text| {
10863            let mut lines: Vec<&str> = text.split('\n').collect();
10864            let line_count_before = lines.len();
10865
10866            callback(&mut lines);
10867
10868            LineManipulationResult {
10869                new_text: lines.join("\n"),
10870                line_count_before,
10871                line_count_after: lines.len(),
10872            }
10873        });
10874    }
10875
10876    fn manipulate_mutable_lines<Fn>(
10877        &mut self,
10878        window: &mut Window,
10879        cx: &mut Context<Self>,
10880        mut callback: Fn,
10881    ) where
10882        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10883    {
10884        self.manipulate_lines(window, cx, |text| {
10885            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10886            let line_count_before = lines.len();
10887
10888            callback(&mut lines);
10889
10890            LineManipulationResult {
10891                new_text: lines.join("\n"),
10892                line_count_before,
10893                line_count_after: lines.len(),
10894            }
10895        });
10896    }
10897
10898    pub fn convert_indentation_to_spaces(
10899        &mut self,
10900        _: &ConvertIndentationToSpaces,
10901        window: &mut Window,
10902        cx: &mut Context<Self>,
10903    ) {
10904        let settings = self.buffer.read(cx).language_settings(cx);
10905        let tab_size = settings.tab_size.get() as usize;
10906
10907        self.manipulate_mutable_lines(window, cx, |lines| {
10908            // Allocates a reasonably sized scratch buffer once for the whole loop
10909            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10910            // Avoids recomputing spaces that could be inserted many times
10911            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10912                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10913                .collect();
10914
10915            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10916                let mut chars = line.as_ref().chars();
10917                let mut col = 0;
10918                let mut changed = false;
10919
10920                while let Some(ch) = chars.next() {
10921                    match ch {
10922                        ' ' => {
10923                            reindented_line.push(' ');
10924                            col += 1;
10925                        }
10926                        '\t' => {
10927                            // \t are converted to spaces depending on the current column
10928                            let spaces_len = tab_size - (col % tab_size);
10929                            reindented_line.extend(&space_cache[spaces_len - 1]);
10930                            col += spaces_len;
10931                            changed = true;
10932                        }
10933                        _ => {
10934                            // If we dont append before break, the character is consumed
10935                            reindented_line.push(ch);
10936                            break;
10937                        }
10938                    }
10939                }
10940
10941                if !changed {
10942                    reindented_line.clear();
10943                    continue;
10944                }
10945                // Append the rest of the line and replace old reference with new one
10946                reindented_line.extend(chars);
10947                *line = Cow::Owned(reindented_line.clone());
10948                reindented_line.clear();
10949            }
10950        });
10951    }
10952
10953    pub fn convert_indentation_to_tabs(
10954        &mut self,
10955        _: &ConvertIndentationToTabs,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958    ) {
10959        let settings = self.buffer.read(cx).language_settings(cx);
10960        let tab_size = settings.tab_size.get() as usize;
10961
10962        self.manipulate_mutable_lines(window, cx, |lines| {
10963            // Allocates a reasonably sized buffer once for the whole loop
10964            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10965            // Avoids recomputing spaces that could be inserted many times
10966            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10967                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10968                .collect();
10969
10970            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10971                let mut chars = line.chars();
10972                let mut spaces_count = 0;
10973                let mut first_non_indent_char = None;
10974                let mut changed = false;
10975
10976                while let Some(ch) = chars.next() {
10977                    match ch {
10978                        ' ' => {
10979                            // Keep track of spaces. Append \t when we reach tab_size
10980                            spaces_count += 1;
10981                            changed = true;
10982                            if spaces_count == tab_size {
10983                                reindented_line.push('\t');
10984                                spaces_count = 0;
10985                            }
10986                        }
10987                        '\t' => {
10988                            reindented_line.push('\t');
10989                            spaces_count = 0;
10990                        }
10991                        _ => {
10992                            // Dont append it yet, we might have remaining spaces
10993                            first_non_indent_char = Some(ch);
10994                            break;
10995                        }
10996                    }
10997                }
10998
10999                if !changed {
11000                    reindented_line.clear();
11001                    continue;
11002                }
11003                // Remaining spaces that didn't make a full tab stop
11004                if spaces_count > 0 {
11005                    reindented_line.extend(&space_cache[spaces_count - 1]);
11006                }
11007                // If we consume an extra character that was not indentation, add it back
11008                if let Some(extra_char) = first_non_indent_char {
11009                    reindented_line.push(extra_char);
11010                }
11011                // Append the rest of the line and replace old reference with new one
11012                reindented_line.extend(chars);
11013                *line = Cow::Owned(reindented_line.clone());
11014                reindented_line.clear();
11015            }
11016        });
11017    }
11018
11019    pub fn convert_to_upper_case(
11020        &mut self,
11021        _: &ConvertToUpperCase,
11022        window: &mut Window,
11023        cx: &mut Context<Self>,
11024    ) {
11025        self.manipulate_text(window, cx, |text| text.to_uppercase())
11026    }
11027
11028    pub fn convert_to_lower_case(
11029        &mut self,
11030        _: &ConvertToLowerCase,
11031        window: &mut Window,
11032        cx: &mut Context<Self>,
11033    ) {
11034        self.manipulate_text(window, cx, |text| text.to_lowercase())
11035    }
11036
11037    pub fn convert_to_title_case(
11038        &mut self,
11039        _: &ConvertToTitleCase,
11040        window: &mut Window,
11041        cx: &mut Context<Self>,
11042    ) {
11043        self.manipulate_text(window, cx, |text| {
11044            text.split('\n')
11045                .map(|line| line.to_case(Case::Title))
11046                .join("\n")
11047        })
11048    }
11049
11050    pub fn convert_to_snake_case(
11051        &mut self,
11052        _: &ConvertToSnakeCase,
11053        window: &mut Window,
11054        cx: &mut Context<Self>,
11055    ) {
11056        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11057    }
11058
11059    pub fn convert_to_kebab_case(
11060        &mut self,
11061        _: &ConvertToKebabCase,
11062        window: &mut Window,
11063        cx: &mut Context<Self>,
11064    ) {
11065        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11066    }
11067
11068    pub fn convert_to_upper_camel_case(
11069        &mut self,
11070        _: &ConvertToUpperCamelCase,
11071        window: &mut Window,
11072        cx: &mut Context<Self>,
11073    ) {
11074        self.manipulate_text(window, cx, |text| {
11075            text.split('\n')
11076                .map(|line| line.to_case(Case::UpperCamel))
11077                .join("\n")
11078        })
11079    }
11080
11081    pub fn convert_to_lower_camel_case(
11082        &mut self,
11083        _: &ConvertToLowerCamelCase,
11084        window: &mut Window,
11085        cx: &mut Context<Self>,
11086    ) {
11087        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11088    }
11089
11090    pub fn convert_to_opposite_case(
11091        &mut self,
11092        _: &ConvertToOppositeCase,
11093        window: &mut Window,
11094        cx: &mut Context<Self>,
11095    ) {
11096        self.manipulate_text(window, cx, |text| {
11097            text.chars()
11098                .fold(String::with_capacity(text.len()), |mut t, c| {
11099                    if c.is_uppercase() {
11100                        t.extend(c.to_lowercase());
11101                    } else {
11102                        t.extend(c.to_uppercase());
11103                    }
11104                    t
11105                })
11106        })
11107    }
11108
11109    pub fn convert_to_rot13(
11110        &mut self,
11111        _: &ConvertToRot13,
11112        window: &mut Window,
11113        cx: &mut Context<Self>,
11114    ) {
11115        self.manipulate_text(window, cx, |text| {
11116            text.chars()
11117                .map(|c| match c {
11118                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11119                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11120                    _ => c,
11121                })
11122                .collect()
11123        })
11124    }
11125
11126    pub fn convert_to_rot47(
11127        &mut self,
11128        _: &ConvertToRot47,
11129        window: &mut Window,
11130        cx: &mut Context<Self>,
11131    ) {
11132        self.manipulate_text(window, cx, |text| {
11133            text.chars()
11134                .map(|c| {
11135                    let code_point = c as u32;
11136                    if code_point >= 33 && code_point <= 126 {
11137                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11138                    }
11139                    c
11140                })
11141                .collect()
11142        })
11143    }
11144
11145    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11146    where
11147        Fn: FnMut(&str) -> String,
11148    {
11149        let buffer = self.buffer.read(cx).snapshot(cx);
11150
11151        let mut new_selections = Vec::new();
11152        let mut edits = Vec::new();
11153        let mut selection_adjustment = 0i32;
11154
11155        for selection in self.selections.all::<usize>(cx) {
11156            let selection_is_empty = selection.is_empty();
11157
11158            let (start, end) = if selection_is_empty {
11159                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11160                (word_range.start, word_range.end)
11161            } else {
11162                (selection.start, selection.end)
11163            };
11164
11165            let text = buffer.text_for_range(start..end).collect::<String>();
11166            let old_length = text.len() as i32;
11167            let text = callback(&text);
11168
11169            new_selections.push(Selection {
11170                start: (start as i32 - selection_adjustment) as usize,
11171                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11172                goal: SelectionGoal::None,
11173                ..selection
11174            });
11175
11176            selection_adjustment += old_length - text.len() as i32;
11177
11178            edits.push((start..end, text));
11179        }
11180
11181        self.transact(window, cx, |this, window, cx| {
11182            this.buffer.update(cx, |buffer, cx| {
11183                buffer.edit(edits, None, cx);
11184            });
11185
11186            this.change_selections(Default::default(), window, cx, |s| {
11187                s.select(new_selections);
11188            });
11189
11190            this.request_autoscroll(Autoscroll::fit(), cx);
11191        });
11192    }
11193
11194    pub fn move_selection_on_drop(
11195        &mut self,
11196        selection: &Selection<Anchor>,
11197        target: DisplayPoint,
11198        is_cut: bool,
11199        window: &mut Window,
11200        cx: &mut Context<Self>,
11201    ) {
11202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11203        let buffer = &display_map.buffer_snapshot;
11204        let mut edits = Vec::new();
11205        let insert_point = display_map
11206            .clip_point(target, Bias::Left)
11207            .to_point(&display_map);
11208        let text = buffer
11209            .text_for_range(selection.start..selection.end)
11210            .collect::<String>();
11211        if is_cut {
11212            edits.push(((selection.start..selection.end), String::new()));
11213        }
11214        let insert_anchor = buffer.anchor_before(insert_point);
11215        edits.push(((insert_anchor..insert_anchor), text));
11216        let last_edit_start = insert_anchor.bias_left(buffer);
11217        let last_edit_end = insert_anchor.bias_right(buffer);
11218        self.transact(window, cx, |this, window, cx| {
11219            this.buffer.update(cx, |buffer, cx| {
11220                buffer.edit(edits, None, cx);
11221            });
11222            this.change_selections(Default::default(), window, cx, |s| {
11223                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11224            });
11225        });
11226    }
11227
11228    pub fn clear_selection_drag_state(&mut self) {
11229        self.selection_drag_state = SelectionDragState::None;
11230    }
11231
11232    pub fn duplicate(
11233        &mut self,
11234        upwards: bool,
11235        whole_lines: bool,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11240
11241        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11242        let buffer = &display_map.buffer_snapshot;
11243        let selections = self.selections.all::<Point>(cx);
11244
11245        let mut edits = Vec::new();
11246        let mut selections_iter = selections.iter().peekable();
11247        while let Some(selection) = selections_iter.next() {
11248            let mut rows = selection.spanned_rows(false, &display_map);
11249            // duplicate line-wise
11250            if whole_lines || selection.start == selection.end {
11251                // Avoid duplicating the same lines twice.
11252                while let Some(next_selection) = selections_iter.peek() {
11253                    let next_rows = next_selection.spanned_rows(false, &display_map);
11254                    if next_rows.start < rows.end {
11255                        rows.end = next_rows.end;
11256                        selections_iter.next().unwrap();
11257                    } else {
11258                        break;
11259                    }
11260                }
11261
11262                // Copy the text from the selected row region and splice it either at the start
11263                // or end of the region.
11264                let start = Point::new(rows.start.0, 0);
11265                let end = Point::new(
11266                    rows.end.previous_row().0,
11267                    buffer.line_len(rows.end.previous_row()),
11268                );
11269                let text = buffer
11270                    .text_for_range(start..end)
11271                    .chain(Some("\n"))
11272                    .collect::<String>();
11273                let insert_location = if upwards {
11274                    Point::new(rows.end.0, 0)
11275                } else {
11276                    start
11277                };
11278                edits.push((insert_location..insert_location, text));
11279            } else {
11280                // duplicate character-wise
11281                let start = selection.start;
11282                let end = selection.end;
11283                let text = buffer.text_for_range(start..end).collect::<String>();
11284                edits.push((selection.end..selection.end, text));
11285            }
11286        }
11287
11288        self.transact(window, cx, |this, _, cx| {
11289            this.buffer.update(cx, |buffer, cx| {
11290                buffer.edit(edits, None, cx);
11291            });
11292
11293            this.request_autoscroll(Autoscroll::fit(), cx);
11294        });
11295    }
11296
11297    pub fn duplicate_line_up(
11298        &mut self,
11299        _: &DuplicateLineUp,
11300        window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        self.duplicate(true, true, window, cx);
11304    }
11305
11306    pub fn duplicate_line_down(
11307        &mut self,
11308        _: &DuplicateLineDown,
11309        window: &mut Window,
11310        cx: &mut Context<Self>,
11311    ) {
11312        self.duplicate(false, true, window, cx);
11313    }
11314
11315    pub fn duplicate_selection(
11316        &mut self,
11317        _: &DuplicateSelection,
11318        window: &mut Window,
11319        cx: &mut Context<Self>,
11320    ) {
11321        self.duplicate(false, false, window, cx);
11322    }
11323
11324    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11326        if self.mode.is_single_line() {
11327            cx.propagate();
11328            return;
11329        }
11330
11331        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11332        let buffer = self.buffer.read(cx).snapshot(cx);
11333
11334        let mut edits = Vec::new();
11335        let mut unfold_ranges = Vec::new();
11336        let mut refold_creases = Vec::new();
11337
11338        let selections = self.selections.all::<Point>(cx);
11339        let mut selections = selections.iter().peekable();
11340        let mut contiguous_row_selections = Vec::new();
11341        let mut new_selections = Vec::new();
11342
11343        while let Some(selection) = selections.next() {
11344            // Find all the selections that span a contiguous row range
11345            let (start_row, end_row) = consume_contiguous_rows(
11346                &mut contiguous_row_selections,
11347                selection,
11348                &display_map,
11349                &mut selections,
11350            );
11351
11352            // Move the text spanned by the row range to be before the line preceding the row range
11353            if start_row.0 > 0 {
11354                let range_to_move = Point::new(
11355                    start_row.previous_row().0,
11356                    buffer.line_len(start_row.previous_row()),
11357                )
11358                    ..Point::new(
11359                        end_row.previous_row().0,
11360                        buffer.line_len(end_row.previous_row()),
11361                    );
11362                let insertion_point = display_map
11363                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11364                    .0;
11365
11366                // Don't move lines across excerpts
11367                if buffer
11368                    .excerpt_containing(insertion_point..range_to_move.end)
11369                    .is_some()
11370                {
11371                    let text = buffer
11372                        .text_for_range(range_to_move.clone())
11373                        .flat_map(|s| s.chars())
11374                        .skip(1)
11375                        .chain(['\n'])
11376                        .collect::<String>();
11377
11378                    edits.push((
11379                        buffer.anchor_after(range_to_move.start)
11380                            ..buffer.anchor_before(range_to_move.end),
11381                        String::new(),
11382                    ));
11383                    let insertion_anchor = buffer.anchor_after(insertion_point);
11384                    edits.push((insertion_anchor..insertion_anchor, text));
11385
11386                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11387
11388                    // Move selections up
11389                    new_selections.extend(contiguous_row_selections.drain(..).map(
11390                        |mut selection| {
11391                            selection.start.row -= row_delta;
11392                            selection.end.row -= row_delta;
11393                            selection
11394                        },
11395                    ));
11396
11397                    // Move folds up
11398                    unfold_ranges.push(range_to_move.clone());
11399                    for fold in display_map.folds_in_range(
11400                        buffer.anchor_before(range_to_move.start)
11401                            ..buffer.anchor_after(range_to_move.end),
11402                    ) {
11403                        let mut start = fold.range.start.to_point(&buffer);
11404                        let mut end = fold.range.end.to_point(&buffer);
11405                        start.row -= row_delta;
11406                        end.row -= row_delta;
11407                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11408                    }
11409                }
11410            }
11411
11412            // If we didn't move line(s), preserve the existing selections
11413            new_selections.append(&mut contiguous_row_selections);
11414        }
11415
11416        self.transact(window, cx, |this, window, cx| {
11417            this.unfold_ranges(&unfold_ranges, true, true, cx);
11418            this.buffer.update(cx, |buffer, cx| {
11419                for (range, text) in edits {
11420                    buffer.edit([(range, text)], None, cx);
11421                }
11422            });
11423            this.fold_creases(refold_creases, true, window, cx);
11424            this.change_selections(Default::default(), window, cx, |s| {
11425                s.select(new_selections);
11426            })
11427        });
11428    }
11429
11430    pub fn move_line_down(
11431        &mut self,
11432        _: &MoveLineDown,
11433        window: &mut Window,
11434        cx: &mut Context<Self>,
11435    ) {
11436        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11437        if self.mode.is_single_line() {
11438            cx.propagate();
11439            return;
11440        }
11441
11442        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11443        let buffer = self.buffer.read(cx).snapshot(cx);
11444
11445        let mut edits = Vec::new();
11446        let mut unfold_ranges = Vec::new();
11447        let mut refold_creases = Vec::new();
11448
11449        let selections = self.selections.all::<Point>(cx);
11450        let mut selections = selections.iter().peekable();
11451        let mut contiguous_row_selections = Vec::new();
11452        let mut new_selections = Vec::new();
11453
11454        while let Some(selection) = selections.next() {
11455            // Find all the selections that span a contiguous row range
11456            let (start_row, end_row) = consume_contiguous_rows(
11457                &mut contiguous_row_selections,
11458                selection,
11459                &display_map,
11460                &mut selections,
11461            );
11462
11463            // Move the text spanned by the row range to be after the last line of the row range
11464            if end_row.0 <= buffer.max_point().row {
11465                let range_to_move =
11466                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11467                let insertion_point = display_map
11468                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11469                    .0;
11470
11471                // Don't move lines across excerpt boundaries
11472                if buffer
11473                    .excerpt_containing(range_to_move.start..insertion_point)
11474                    .is_some()
11475                {
11476                    let mut text = String::from("\n");
11477                    text.extend(buffer.text_for_range(range_to_move.clone()));
11478                    text.pop(); // Drop trailing newline
11479                    edits.push((
11480                        buffer.anchor_after(range_to_move.start)
11481                            ..buffer.anchor_before(range_to_move.end),
11482                        String::new(),
11483                    ));
11484                    let insertion_anchor = buffer.anchor_after(insertion_point);
11485                    edits.push((insertion_anchor..insertion_anchor, text));
11486
11487                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11488
11489                    // Move selections down
11490                    new_selections.extend(contiguous_row_selections.drain(..).map(
11491                        |mut selection| {
11492                            selection.start.row += row_delta;
11493                            selection.end.row += row_delta;
11494                            selection
11495                        },
11496                    ));
11497
11498                    // Move folds down
11499                    unfold_ranges.push(range_to_move.clone());
11500                    for fold in display_map.folds_in_range(
11501                        buffer.anchor_before(range_to_move.start)
11502                            ..buffer.anchor_after(range_to_move.end),
11503                    ) {
11504                        let mut start = fold.range.start.to_point(&buffer);
11505                        let mut end = fold.range.end.to_point(&buffer);
11506                        start.row += row_delta;
11507                        end.row += row_delta;
11508                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11509                    }
11510                }
11511            }
11512
11513            // If we didn't move line(s), preserve the existing selections
11514            new_selections.append(&mut contiguous_row_selections);
11515        }
11516
11517        self.transact(window, cx, |this, window, cx| {
11518            this.unfold_ranges(&unfold_ranges, true, true, cx);
11519            this.buffer.update(cx, |buffer, cx| {
11520                for (range, text) in edits {
11521                    buffer.edit([(range, text)], None, cx);
11522                }
11523            });
11524            this.fold_creases(refold_creases, true, window, cx);
11525            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11526        });
11527    }
11528
11529    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11530        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11531        let text_layout_details = &self.text_layout_details(window);
11532        self.transact(window, cx, |this, window, cx| {
11533            let edits = this.change_selections(Default::default(), window, cx, |s| {
11534                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11535                s.move_with(|display_map, selection| {
11536                    if !selection.is_empty() {
11537                        return;
11538                    }
11539
11540                    let mut head = selection.head();
11541                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11542                    if head.column() == display_map.line_len(head.row()) {
11543                        transpose_offset = display_map
11544                            .buffer_snapshot
11545                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11546                    }
11547
11548                    if transpose_offset == 0 {
11549                        return;
11550                    }
11551
11552                    *head.column_mut() += 1;
11553                    head = display_map.clip_point(head, Bias::Right);
11554                    let goal = SelectionGoal::HorizontalPosition(
11555                        display_map
11556                            .x_for_display_point(head, text_layout_details)
11557                            .into(),
11558                    );
11559                    selection.collapse_to(head, goal);
11560
11561                    let transpose_start = display_map
11562                        .buffer_snapshot
11563                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11564                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11565                        let transpose_end = display_map
11566                            .buffer_snapshot
11567                            .clip_offset(transpose_offset + 1, Bias::Right);
11568                        if let Some(ch) =
11569                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11570                        {
11571                            edits.push((transpose_start..transpose_offset, String::new()));
11572                            edits.push((transpose_end..transpose_end, ch.to_string()));
11573                        }
11574                    }
11575                });
11576                edits
11577            });
11578            this.buffer
11579                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11580            let selections = this.selections.all::<usize>(cx);
11581            this.change_selections(Default::default(), window, cx, |s| {
11582                s.select(selections);
11583            });
11584        });
11585    }
11586
11587    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11589        if self.mode.is_single_line() {
11590            cx.propagate();
11591            return;
11592        }
11593
11594        self.rewrap_impl(RewrapOptions::default(), cx)
11595    }
11596
11597    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11598        let buffer = self.buffer.read(cx).snapshot(cx);
11599        let selections = self.selections.all::<Point>(cx);
11600
11601        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11602        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11603            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11604                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11605                .peekable();
11606
11607            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11608                row
11609            } else {
11610                return Vec::new();
11611            };
11612
11613            let language_settings = buffer.language_settings_at(selection.head(), cx);
11614            let language_scope = buffer.language_scope_at(selection.head());
11615
11616            let indent_and_prefix_for_row =
11617                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11618                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11619                    let (comment_prefix, rewrap_prefix) =
11620                        if let Some(language_scope) = &language_scope {
11621                            let indent_end = Point::new(row, indent.len);
11622                            let comment_prefix = language_scope
11623                                .line_comment_prefixes()
11624                                .iter()
11625                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11626                                .map(|prefix| prefix.to_string());
11627                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11628                            let line_text_after_indent = buffer
11629                                .text_for_range(indent_end..line_end)
11630                                .collect::<String>();
11631                            let rewrap_prefix = language_scope
11632                                .rewrap_prefixes()
11633                                .iter()
11634                                .find_map(|prefix_regex| {
11635                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11636                                        if mat.start() == 0 {
11637                                            Some(mat.as_str().to_string())
11638                                        } else {
11639                                            None
11640                                        }
11641                                    })
11642                                })
11643                                .flatten();
11644                            (comment_prefix, rewrap_prefix)
11645                        } else {
11646                            (None, None)
11647                        };
11648                    (indent, comment_prefix, rewrap_prefix)
11649                };
11650
11651            let mut ranges = Vec::new();
11652            let from_empty_selection = selection.is_empty();
11653
11654            let mut current_range_start = first_row;
11655            let mut prev_row = first_row;
11656            let (
11657                mut current_range_indent,
11658                mut current_range_comment_prefix,
11659                mut current_range_rewrap_prefix,
11660            ) = indent_and_prefix_for_row(first_row);
11661
11662            for row in non_blank_rows_iter.skip(1) {
11663                let has_paragraph_break = row > prev_row + 1;
11664
11665                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11666                    indent_and_prefix_for_row(row);
11667
11668                let has_indent_change = row_indent != current_range_indent;
11669                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11670
11671                let has_boundary_change = has_comment_change
11672                    || row_rewrap_prefix.is_some()
11673                    || (has_indent_change && current_range_comment_prefix.is_some());
11674
11675                if has_paragraph_break || has_boundary_change {
11676                    ranges.push((
11677                        language_settings.clone(),
11678                        Point::new(current_range_start, 0)
11679                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11680                        current_range_indent,
11681                        current_range_comment_prefix.clone(),
11682                        current_range_rewrap_prefix.clone(),
11683                        from_empty_selection,
11684                    ));
11685                    current_range_start = row;
11686                    current_range_indent = row_indent;
11687                    current_range_comment_prefix = row_comment_prefix;
11688                    current_range_rewrap_prefix = row_rewrap_prefix;
11689                }
11690                prev_row = row;
11691            }
11692
11693            ranges.push((
11694                language_settings.clone(),
11695                Point::new(current_range_start, 0)
11696                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11697                current_range_indent,
11698                current_range_comment_prefix,
11699                current_range_rewrap_prefix,
11700                from_empty_selection,
11701            ));
11702
11703            ranges
11704        });
11705
11706        let mut edits = Vec::new();
11707        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11708
11709        for (
11710            language_settings,
11711            wrap_range,
11712            indent_size,
11713            comment_prefix,
11714            rewrap_prefix,
11715            from_empty_selection,
11716        ) in wrap_ranges
11717        {
11718            let mut start_row = wrap_range.start.row;
11719            let mut end_row = wrap_range.end.row;
11720
11721            // Skip selections that overlap with a range that has already been rewrapped.
11722            let selection_range = start_row..end_row;
11723            if rewrapped_row_ranges
11724                .iter()
11725                .any(|range| range.overlaps(&selection_range))
11726            {
11727                continue;
11728            }
11729
11730            let tab_size = language_settings.tab_size;
11731
11732            let indent_prefix = indent_size.chars().collect::<String>();
11733            let mut line_prefix = indent_prefix.clone();
11734            let mut inside_comment = false;
11735            if let Some(prefix) = &comment_prefix {
11736                line_prefix.push_str(prefix);
11737                inside_comment = true;
11738            }
11739            if let Some(prefix) = &rewrap_prefix {
11740                line_prefix.push_str(prefix);
11741            }
11742
11743            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11744                RewrapBehavior::InComments => inside_comment,
11745                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11746                RewrapBehavior::Anywhere => true,
11747            };
11748
11749            let should_rewrap = options.override_language_settings
11750                || allow_rewrap_based_on_language
11751                || self.hard_wrap.is_some();
11752            if !should_rewrap {
11753                continue;
11754            }
11755
11756            if from_empty_selection {
11757                'expand_upwards: while start_row > 0 {
11758                    let prev_row = start_row - 1;
11759                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11760                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11761                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11762                    {
11763                        start_row = prev_row;
11764                    } else {
11765                        break 'expand_upwards;
11766                    }
11767                }
11768
11769                'expand_downwards: while end_row < buffer.max_point().row {
11770                    let next_row = end_row + 1;
11771                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11772                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11773                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11774                    {
11775                        end_row = next_row;
11776                    } else {
11777                        break 'expand_downwards;
11778                    }
11779                }
11780            }
11781
11782            let start = Point::new(start_row, 0);
11783            let start_offset = start.to_offset(&buffer);
11784            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11785            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11786            let Some(lines_without_prefixes) = selection_text
11787                .lines()
11788                .enumerate()
11789                .map(|(ix, line)| {
11790                    let line_trimmed = line.trim_start();
11791                    if rewrap_prefix.is_some() && ix > 0 {
11792                        Ok(line_trimmed)
11793                    } else {
11794                        line_trimmed
11795                            .strip_prefix(&line_prefix.trim_start())
11796                            .with_context(|| {
11797                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11798                            })
11799                    }
11800                })
11801                .collect::<Result<Vec<_>, _>>()
11802                .log_err()
11803            else {
11804                continue;
11805            };
11806
11807            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11808                buffer
11809                    .language_settings_at(Point::new(start_row, 0), cx)
11810                    .preferred_line_length as usize
11811            });
11812
11813            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11814                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11815            } else {
11816                line_prefix.clone()
11817            };
11818
11819            let wrapped_text = wrap_with_prefix(
11820                line_prefix,
11821                subsequent_lines_prefix,
11822                lines_without_prefixes.join("\n"),
11823                wrap_column,
11824                tab_size,
11825                options.preserve_existing_whitespace,
11826            );
11827
11828            // TODO: should always use char-based diff while still supporting cursor behavior that
11829            // matches vim.
11830            let mut diff_options = DiffOptions::default();
11831            if options.override_language_settings {
11832                diff_options.max_word_diff_len = 0;
11833                diff_options.max_word_diff_line_count = 0;
11834            } else {
11835                diff_options.max_word_diff_len = usize::MAX;
11836                diff_options.max_word_diff_line_count = usize::MAX;
11837            }
11838
11839            for (old_range, new_text) in
11840                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11841            {
11842                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11843                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11844                edits.push((edit_start..edit_end, new_text));
11845            }
11846
11847            rewrapped_row_ranges.push(start_row..=end_row);
11848        }
11849
11850        self.buffer
11851            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11852    }
11853
11854    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11855        let mut text = String::new();
11856        let buffer = self.buffer.read(cx).snapshot(cx);
11857        let mut selections = self.selections.all::<Point>(cx);
11858        let mut clipboard_selections = Vec::with_capacity(selections.len());
11859        {
11860            let max_point = buffer.max_point();
11861            let mut is_first = true;
11862            for selection in &mut selections {
11863                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11864                if is_entire_line {
11865                    selection.start = Point::new(selection.start.row, 0);
11866                    if !selection.is_empty() && selection.end.column == 0 {
11867                        selection.end = cmp::min(max_point, selection.end);
11868                    } else {
11869                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11870                    }
11871                    selection.goal = SelectionGoal::None;
11872                }
11873                if is_first {
11874                    is_first = false;
11875                } else {
11876                    text += "\n";
11877                }
11878                let mut len = 0;
11879                for chunk in buffer.text_for_range(selection.start..selection.end) {
11880                    text.push_str(chunk);
11881                    len += chunk.len();
11882                }
11883                clipboard_selections.push(ClipboardSelection {
11884                    len,
11885                    is_entire_line,
11886                    first_line_indent: buffer
11887                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11888                        .len,
11889                });
11890            }
11891        }
11892
11893        self.transact(window, cx, |this, window, cx| {
11894            this.change_selections(Default::default(), window, cx, |s| {
11895                s.select(selections);
11896            });
11897            this.insert("", window, cx);
11898        });
11899        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11900    }
11901
11902    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11904        let item = self.cut_common(window, cx);
11905        cx.write_to_clipboard(item);
11906    }
11907
11908    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11910        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11911            s.move_with(|snapshot, sel| {
11912                if sel.is_empty() {
11913                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11914                }
11915            });
11916        });
11917        let item = self.cut_common(window, cx);
11918        cx.set_global(KillRing(item))
11919    }
11920
11921    pub fn kill_ring_yank(
11922        &mut self,
11923        _: &KillRingYank,
11924        window: &mut Window,
11925        cx: &mut Context<Self>,
11926    ) {
11927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11928        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11929            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11930                (kill_ring.text().to_string(), kill_ring.metadata_json())
11931            } else {
11932                return;
11933            }
11934        } else {
11935            return;
11936        };
11937        self.do_paste(&text, metadata, false, window, cx);
11938    }
11939
11940    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11941        self.do_copy(true, cx);
11942    }
11943
11944    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11945        self.do_copy(false, cx);
11946    }
11947
11948    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11949        let selections = self.selections.all::<Point>(cx);
11950        let buffer = self.buffer.read(cx).read(cx);
11951        let mut text = String::new();
11952
11953        let mut clipboard_selections = Vec::with_capacity(selections.len());
11954        {
11955            let max_point = buffer.max_point();
11956            let mut is_first = true;
11957            for selection in &selections {
11958                let mut start = selection.start;
11959                let mut end = selection.end;
11960                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11961                if is_entire_line {
11962                    start = Point::new(start.row, 0);
11963                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11964                }
11965
11966                let mut trimmed_selections = Vec::new();
11967                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11968                    let row = MultiBufferRow(start.row);
11969                    let first_indent = buffer.indent_size_for_line(row);
11970                    if first_indent.len == 0 || start.column > first_indent.len {
11971                        trimmed_selections.push(start..end);
11972                    } else {
11973                        trimmed_selections.push(
11974                            Point::new(row.0, first_indent.len)
11975                                ..Point::new(row.0, buffer.line_len(row)),
11976                        );
11977                        for row in start.row + 1..=end.row {
11978                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11979                            if row == end.row {
11980                                line_len = end.column;
11981                            }
11982                            if line_len == 0 {
11983                                trimmed_selections
11984                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11985                                continue;
11986                            }
11987                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11988                            if row_indent_size.len >= first_indent.len {
11989                                trimmed_selections.push(
11990                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11991                                );
11992                            } else {
11993                                trimmed_selections.clear();
11994                                trimmed_selections.push(start..end);
11995                                break;
11996                            }
11997                        }
11998                    }
11999                } else {
12000                    trimmed_selections.push(start..end);
12001                }
12002
12003                for trimmed_range in trimmed_selections {
12004                    if is_first {
12005                        is_first = false;
12006                    } else {
12007                        text += "\n";
12008                    }
12009                    let mut len = 0;
12010                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12011                        text.push_str(chunk);
12012                        len += chunk.len();
12013                    }
12014                    clipboard_selections.push(ClipboardSelection {
12015                        len,
12016                        is_entire_line,
12017                        first_line_indent: buffer
12018                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12019                            .len,
12020                    });
12021                }
12022            }
12023        }
12024
12025        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12026            text,
12027            clipboard_selections,
12028        ));
12029    }
12030
12031    pub fn do_paste(
12032        &mut self,
12033        text: &String,
12034        clipboard_selections: Option<Vec<ClipboardSelection>>,
12035        handle_entire_lines: bool,
12036        window: &mut Window,
12037        cx: &mut Context<Self>,
12038    ) {
12039        if self.read_only(cx) {
12040            return;
12041        }
12042
12043        let clipboard_text = Cow::Borrowed(text);
12044
12045        self.transact(window, cx, |this, window, cx| {
12046            if let Some(mut clipboard_selections) = clipboard_selections {
12047                let old_selections = this.selections.all::<usize>(cx);
12048                let all_selections_were_entire_line =
12049                    clipboard_selections.iter().all(|s| s.is_entire_line);
12050                let first_selection_indent_column =
12051                    clipboard_selections.first().map(|s| s.first_line_indent);
12052                if clipboard_selections.len() != old_selections.len() {
12053                    clipboard_selections.drain(..);
12054                }
12055                let cursor_offset = this.selections.last::<usize>(cx).head();
12056                let mut auto_indent_on_paste = true;
12057
12058                this.buffer.update(cx, |buffer, cx| {
12059                    let snapshot = buffer.read(cx);
12060                    auto_indent_on_paste = snapshot
12061                        .language_settings_at(cursor_offset, cx)
12062                        .auto_indent_on_paste;
12063
12064                    let mut start_offset = 0;
12065                    let mut edits = Vec::new();
12066                    let mut original_indent_columns = Vec::new();
12067                    for (ix, selection) in old_selections.iter().enumerate() {
12068                        let to_insert;
12069                        let entire_line;
12070                        let original_indent_column;
12071                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12072                            let end_offset = start_offset + clipboard_selection.len;
12073                            to_insert = &clipboard_text[start_offset..end_offset];
12074                            entire_line = clipboard_selection.is_entire_line;
12075                            start_offset = end_offset + 1;
12076                            original_indent_column = Some(clipboard_selection.first_line_indent);
12077                        } else {
12078                            to_insert = clipboard_text.as_str();
12079                            entire_line = all_selections_were_entire_line;
12080                            original_indent_column = first_selection_indent_column
12081                        }
12082
12083                        // If the corresponding selection was empty when this slice of the
12084                        // clipboard text was written, then the entire line containing the
12085                        // selection was copied. If this selection is also currently empty,
12086                        // then paste the line before the current line of the buffer.
12087                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12088                            let column = selection.start.to_point(&snapshot).column as usize;
12089                            let line_start = selection.start - column;
12090                            line_start..line_start
12091                        } else {
12092                            selection.range()
12093                        };
12094
12095                        edits.push((range, to_insert));
12096                        original_indent_columns.push(original_indent_column);
12097                    }
12098                    drop(snapshot);
12099
12100                    buffer.edit(
12101                        edits,
12102                        if auto_indent_on_paste {
12103                            Some(AutoindentMode::Block {
12104                                original_indent_columns,
12105                            })
12106                        } else {
12107                            None
12108                        },
12109                        cx,
12110                    );
12111                });
12112
12113                let selections = this.selections.all::<usize>(cx);
12114                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12115            } else {
12116                this.insert(&clipboard_text, window, cx);
12117            }
12118        });
12119    }
12120
12121    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12122        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12123        if let Some(item) = cx.read_from_clipboard() {
12124            let entries = item.entries();
12125
12126            match entries.first() {
12127                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12128                // of all the pasted entries.
12129                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12130                    .do_paste(
12131                        clipboard_string.text(),
12132                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12133                        true,
12134                        window,
12135                        cx,
12136                    ),
12137                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12138            }
12139        }
12140    }
12141
12142    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12143        if self.read_only(cx) {
12144            return;
12145        }
12146
12147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12148
12149        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12150            if let Some((selections, _)) =
12151                self.selection_history.transaction(transaction_id).cloned()
12152            {
12153                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12154                    s.select_anchors(selections.to_vec());
12155                });
12156            } else {
12157                log::error!(
12158                    "No entry in selection_history found for undo. \
12159                     This may correspond to a bug where undo does not update the selection. \
12160                     If this is occurring, please add details to \
12161                     https://github.com/zed-industries/zed/issues/22692"
12162                );
12163            }
12164            self.request_autoscroll(Autoscroll::fit(), cx);
12165            self.unmark_text(window, cx);
12166            self.refresh_inline_completion(true, false, window, cx);
12167            cx.emit(EditorEvent::Edited { transaction_id });
12168            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12169        }
12170    }
12171
12172    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12173        if self.read_only(cx) {
12174            return;
12175        }
12176
12177        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12178
12179        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12180            if let Some((_, Some(selections))) =
12181                self.selection_history.transaction(transaction_id).cloned()
12182            {
12183                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12184                    s.select_anchors(selections.to_vec());
12185                });
12186            } else {
12187                log::error!(
12188                    "No entry in selection_history found for redo. \
12189                     This may correspond to a bug where undo does not update the selection. \
12190                     If this is occurring, please add details to \
12191                     https://github.com/zed-industries/zed/issues/22692"
12192                );
12193            }
12194            self.request_autoscroll(Autoscroll::fit(), cx);
12195            self.unmark_text(window, cx);
12196            self.refresh_inline_completion(true, false, window, cx);
12197            cx.emit(EditorEvent::Edited { transaction_id });
12198        }
12199    }
12200
12201    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12202        self.buffer
12203            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12204    }
12205
12206    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12207        self.buffer
12208            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12209    }
12210
12211    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12213        self.change_selections(Default::default(), window, cx, |s| {
12214            s.move_with(|map, selection| {
12215                let cursor = if selection.is_empty() {
12216                    movement::left(map, selection.start)
12217                } else {
12218                    selection.start
12219                };
12220                selection.collapse_to(cursor, SelectionGoal::None);
12221            });
12222        })
12223    }
12224
12225    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12227        self.change_selections(Default::default(), window, cx, |s| {
12228            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12229        })
12230    }
12231
12232    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12233        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12234        self.change_selections(Default::default(), window, cx, |s| {
12235            s.move_with(|map, selection| {
12236                let cursor = if selection.is_empty() {
12237                    movement::right(map, selection.end)
12238                } else {
12239                    selection.end
12240                };
12241                selection.collapse_to(cursor, SelectionGoal::None)
12242            });
12243        })
12244    }
12245
12246    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12248        self.change_selections(Default::default(), window, cx, |s| {
12249            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12250        })
12251    }
12252
12253    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12254        if self.take_rename(true, window, cx).is_some() {
12255            return;
12256        }
12257
12258        if self.mode.is_single_line() {
12259            cx.propagate();
12260            return;
12261        }
12262
12263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12264
12265        let text_layout_details = &self.text_layout_details(window);
12266        let selection_count = self.selections.count();
12267        let first_selection = self.selections.first_anchor();
12268
12269        self.change_selections(Default::default(), window, cx, |s| {
12270            s.move_with(|map, selection| {
12271                if !selection.is_empty() {
12272                    selection.goal = SelectionGoal::None;
12273                }
12274                let (cursor, goal) = movement::up(
12275                    map,
12276                    selection.start,
12277                    selection.goal,
12278                    false,
12279                    text_layout_details,
12280                );
12281                selection.collapse_to(cursor, goal);
12282            });
12283        });
12284
12285        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12286        {
12287            cx.propagate();
12288        }
12289    }
12290
12291    pub fn move_up_by_lines(
12292        &mut self,
12293        action: &MoveUpByLines,
12294        window: &mut Window,
12295        cx: &mut Context<Self>,
12296    ) {
12297        if self.take_rename(true, window, cx).is_some() {
12298            return;
12299        }
12300
12301        if self.mode.is_single_line() {
12302            cx.propagate();
12303            return;
12304        }
12305
12306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12307
12308        let text_layout_details = &self.text_layout_details(window);
12309
12310        self.change_selections(Default::default(), window, cx, |s| {
12311            s.move_with(|map, selection| {
12312                if !selection.is_empty() {
12313                    selection.goal = SelectionGoal::None;
12314                }
12315                let (cursor, goal) = movement::up_by_rows(
12316                    map,
12317                    selection.start,
12318                    action.lines,
12319                    selection.goal,
12320                    false,
12321                    text_layout_details,
12322                );
12323                selection.collapse_to(cursor, goal);
12324            });
12325        })
12326    }
12327
12328    pub fn move_down_by_lines(
12329        &mut self,
12330        action: &MoveDownByLines,
12331        window: &mut Window,
12332        cx: &mut Context<Self>,
12333    ) {
12334        if self.take_rename(true, window, cx).is_some() {
12335            return;
12336        }
12337
12338        if self.mode.is_single_line() {
12339            cx.propagate();
12340            return;
12341        }
12342
12343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12344
12345        let text_layout_details = &self.text_layout_details(window);
12346
12347        self.change_selections(Default::default(), window, cx, |s| {
12348            s.move_with(|map, selection| {
12349                if !selection.is_empty() {
12350                    selection.goal = SelectionGoal::None;
12351                }
12352                let (cursor, goal) = movement::down_by_rows(
12353                    map,
12354                    selection.start,
12355                    action.lines,
12356                    selection.goal,
12357                    false,
12358                    text_layout_details,
12359                );
12360                selection.collapse_to(cursor, goal);
12361            });
12362        })
12363    }
12364
12365    pub fn select_down_by_lines(
12366        &mut self,
12367        action: &SelectDownByLines,
12368        window: &mut Window,
12369        cx: &mut Context<Self>,
12370    ) {
12371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12372        let text_layout_details = &self.text_layout_details(window);
12373        self.change_selections(Default::default(), window, cx, |s| {
12374            s.move_heads_with(|map, head, goal| {
12375                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12376            })
12377        })
12378    }
12379
12380    pub fn select_up_by_lines(
12381        &mut self,
12382        action: &SelectUpByLines,
12383        window: &mut Window,
12384        cx: &mut Context<Self>,
12385    ) {
12386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12387        let text_layout_details = &self.text_layout_details(window);
12388        self.change_selections(Default::default(), window, cx, |s| {
12389            s.move_heads_with(|map, head, goal| {
12390                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12391            })
12392        })
12393    }
12394
12395    pub fn select_page_up(
12396        &mut self,
12397        _: &SelectPageUp,
12398        window: &mut Window,
12399        cx: &mut Context<Self>,
12400    ) {
12401        let Some(row_count) = self.visible_row_count() else {
12402            return;
12403        };
12404
12405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12406
12407        let text_layout_details = &self.text_layout_details(window);
12408
12409        self.change_selections(Default::default(), window, cx, |s| {
12410            s.move_heads_with(|map, head, goal| {
12411                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12412            })
12413        })
12414    }
12415
12416    pub fn move_page_up(
12417        &mut self,
12418        action: &MovePageUp,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        if self.take_rename(true, window, cx).is_some() {
12423            return;
12424        }
12425
12426        if self
12427            .context_menu
12428            .borrow_mut()
12429            .as_mut()
12430            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12431            .unwrap_or(false)
12432        {
12433            return;
12434        }
12435
12436        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12437            cx.propagate();
12438            return;
12439        }
12440
12441        let Some(row_count) = self.visible_row_count() else {
12442            return;
12443        };
12444
12445        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12446
12447        let effects = if action.center_cursor {
12448            SelectionEffects::scroll(Autoscroll::center())
12449        } else {
12450            SelectionEffects::default()
12451        };
12452
12453        let text_layout_details = &self.text_layout_details(window);
12454
12455        self.change_selections(effects, window, cx, |s| {
12456            s.move_with(|map, selection| {
12457                if !selection.is_empty() {
12458                    selection.goal = SelectionGoal::None;
12459                }
12460                let (cursor, goal) = movement::up_by_rows(
12461                    map,
12462                    selection.end,
12463                    row_count,
12464                    selection.goal,
12465                    false,
12466                    text_layout_details,
12467                );
12468                selection.collapse_to(cursor, goal);
12469            });
12470        });
12471    }
12472
12473    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12474        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12475        let text_layout_details = &self.text_layout_details(window);
12476        self.change_selections(Default::default(), window, cx, |s| {
12477            s.move_heads_with(|map, head, goal| {
12478                movement::up(map, head, goal, false, text_layout_details)
12479            })
12480        })
12481    }
12482
12483    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12484        self.take_rename(true, window, cx);
12485
12486        if self.mode.is_single_line() {
12487            cx.propagate();
12488            return;
12489        }
12490
12491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12492
12493        let text_layout_details = &self.text_layout_details(window);
12494        let selection_count = self.selections.count();
12495        let first_selection = self.selections.first_anchor();
12496
12497        self.change_selections(Default::default(), window, cx, |s| {
12498            s.move_with(|map, selection| {
12499                if !selection.is_empty() {
12500                    selection.goal = SelectionGoal::None;
12501                }
12502                let (cursor, goal) = movement::down(
12503                    map,
12504                    selection.end,
12505                    selection.goal,
12506                    false,
12507                    text_layout_details,
12508                );
12509                selection.collapse_to(cursor, goal);
12510            });
12511        });
12512
12513        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12514        {
12515            cx.propagate();
12516        }
12517    }
12518
12519    pub fn select_page_down(
12520        &mut self,
12521        _: &SelectPageDown,
12522        window: &mut Window,
12523        cx: &mut Context<Self>,
12524    ) {
12525        let Some(row_count) = self.visible_row_count() else {
12526            return;
12527        };
12528
12529        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12530
12531        let text_layout_details = &self.text_layout_details(window);
12532
12533        self.change_selections(Default::default(), window, cx, |s| {
12534            s.move_heads_with(|map, head, goal| {
12535                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12536            })
12537        })
12538    }
12539
12540    pub fn move_page_down(
12541        &mut self,
12542        action: &MovePageDown,
12543        window: &mut Window,
12544        cx: &mut Context<Self>,
12545    ) {
12546        if self.take_rename(true, window, cx).is_some() {
12547            return;
12548        }
12549
12550        if self
12551            .context_menu
12552            .borrow_mut()
12553            .as_mut()
12554            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12555            .unwrap_or(false)
12556        {
12557            return;
12558        }
12559
12560        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12561            cx.propagate();
12562            return;
12563        }
12564
12565        let Some(row_count) = self.visible_row_count() else {
12566            return;
12567        };
12568
12569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12570
12571        let effects = if action.center_cursor {
12572            SelectionEffects::scroll(Autoscroll::center())
12573        } else {
12574            SelectionEffects::default()
12575        };
12576
12577        let text_layout_details = &self.text_layout_details(window);
12578        self.change_selections(effects, window, cx, |s| {
12579            s.move_with(|map, selection| {
12580                if !selection.is_empty() {
12581                    selection.goal = SelectionGoal::None;
12582                }
12583                let (cursor, goal) = movement::down_by_rows(
12584                    map,
12585                    selection.end,
12586                    row_count,
12587                    selection.goal,
12588                    false,
12589                    text_layout_details,
12590                );
12591                selection.collapse_to(cursor, goal);
12592            });
12593        });
12594    }
12595
12596    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12598        let text_layout_details = &self.text_layout_details(window);
12599        self.change_selections(Default::default(), window, cx, |s| {
12600            s.move_heads_with(|map, head, goal| {
12601                movement::down(map, head, goal, false, text_layout_details)
12602            })
12603        });
12604    }
12605
12606    pub fn context_menu_first(
12607        &mut self,
12608        _: &ContextMenuFirst,
12609        window: &mut Window,
12610        cx: &mut Context<Self>,
12611    ) {
12612        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12613            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12614        }
12615    }
12616
12617    pub fn context_menu_prev(
12618        &mut self,
12619        _: &ContextMenuPrevious,
12620        window: &mut Window,
12621        cx: &mut Context<Self>,
12622    ) {
12623        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12624            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12625        }
12626    }
12627
12628    pub fn context_menu_next(
12629        &mut self,
12630        _: &ContextMenuNext,
12631        window: &mut Window,
12632        cx: &mut Context<Self>,
12633    ) {
12634        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12635            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12636        }
12637    }
12638
12639    pub fn context_menu_last(
12640        &mut self,
12641        _: &ContextMenuLast,
12642        window: &mut Window,
12643        cx: &mut Context<Self>,
12644    ) {
12645        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12646            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12647        }
12648    }
12649
12650    pub fn signature_help_prev(
12651        &mut self,
12652        _: &SignatureHelpPrevious,
12653        _: &mut Window,
12654        cx: &mut Context<Self>,
12655    ) {
12656        if let Some(popover) = self.signature_help_state.popover_mut() {
12657            if popover.current_signature == 0 {
12658                popover.current_signature = popover.signatures.len() - 1;
12659            } else {
12660                popover.current_signature -= 1;
12661            }
12662            cx.notify();
12663        }
12664    }
12665
12666    pub fn signature_help_next(
12667        &mut self,
12668        _: &SignatureHelpNext,
12669        _: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        if let Some(popover) = self.signature_help_state.popover_mut() {
12673            if popover.current_signature + 1 == popover.signatures.len() {
12674                popover.current_signature = 0;
12675            } else {
12676                popover.current_signature += 1;
12677            }
12678            cx.notify();
12679        }
12680    }
12681
12682    pub fn move_to_previous_word_start(
12683        &mut self,
12684        _: &MoveToPreviousWordStart,
12685        window: &mut Window,
12686        cx: &mut Context<Self>,
12687    ) {
12688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12689        self.change_selections(Default::default(), window, cx, |s| {
12690            s.move_cursors_with(|map, head, _| {
12691                (
12692                    movement::previous_word_start(map, head),
12693                    SelectionGoal::None,
12694                )
12695            });
12696        })
12697    }
12698
12699    pub fn move_to_previous_subword_start(
12700        &mut self,
12701        _: &MoveToPreviousSubwordStart,
12702        window: &mut Window,
12703        cx: &mut Context<Self>,
12704    ) {
12705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12706        self.change_selections(Default::default(), window, cx, |s| {
12707            s.move_cursors_with(|map, head, _| {
12708                (
12709                    movement::previous_subword_start(map, head),
12710                    SelectionGoal::None,
12711                )
12712            });
12713        })
12714    }
12715
12716    pub fn select_to_previous_word_start(
12717        &mut self,
12718        _: &SelectToPreviousWordStart,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12723        self.change_selections(Default::default(), window, cx, |s| {
12724            s.move_heads_with(|map, head, _| {
12725                (
12726                    movement::previous_word_start(map, head),
12727                    SelectionGoal::None,
12728                )
12729            });
12730        })
12731    }
12732
12733    pub fn select_to_previous_subword_start(
12734        &mut self,
12735        _: &SelectToPreviousSubwordStart,
12736        window: &mut Window,
12737        cx: &mut Context<Self>,
12738    ) {
12739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12740        self.change_selections(Default::default(), window, cx, |s| {
12741            s.move_heads_with(|map, head, _| {
12742                (
12743                    movement::previous_subword_start(map, head),
12744                    SelectionGoal::None,
12745                )
12746            });
12747        })
12748    }
12749
12750    pub fn delete_to_previous_word_start(
12751        &mut self,
12752        action: &DeleteToPreviousWordStart,
12753        window: &mut Window,
12754        cx: &mut Context<Self>,
12755    ) {
12756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12757        self.transact(window, cx, |this, window, cx| {
12758            this.select_autoclose_pair(window, cx);
12759            this.change_selections(Default::default(), window, cx, |s| {
12760                s.move_with(|map, selection| {
12761                    if selection.is_empty() {
12762                        let cursor = if action.ignore_newlines {
12763                            movement::previous_word_start(map, selection.head())
12764                        } else {
12765                            movement::previous_word_start_or_newline(map, selection.head())
12766                        };
12767                        selection.set_head(cursor, SelectionGoal::None);
12768                    }
12769                });
12770            });
12771            this.insert("", window, cx);
12772        });
12773    }
12774
12775    pub fn delete_to_previous_subword_start(
12776        &mut self,
12777        _: &DeleteToPreviousSubwordStart,
12778        window: &mut Window,
12779        cx: &mut Context<Self>,
12780    ) {
12781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12782        self.transact(window, cx, |this, window, cx| {
12783            this.select_autoclose_pair(window, cx);
12784            this.change_selections(Default::default(), window, cx, |s| {
12785                s.move_with(|map, selection| {
12786                    if selection.is_empty() {
12787                        let cursor = movement::previous_subword_start(map, selection.head());
12788                        selection.set_head(cursor, SelectionGoal::None);
12789                    }
12790                });
12791            });
12792            this.insert("", window, cx);
12793        });
12794    }
12795
12796    pub fn move_to_next_word_end(
12797        &mut self,
12798        _: &MoveToNextWordEnd,
12799        window: &mut Window,
12800        cx: &mut Context<Self>,
12801    ) {
12802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12803        self.change_selections(Default::default(), window, cx, |s| {
12804            s.move_cursors_with(|map, head, _| {
12805                (movement::next_word_end(map, head), SelectionGoal::None)
12806            });
12807        })
12808    }
12809
12810    pub fn move_to_next_subword_end(
12811        &mut self,
12812        _: &MoveToNextSubwordEnd,
12813        window: &mut Window,
12814        cx: &mut Context<Self>,
12815    ) {
12816        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12817        self.change_selections(Default::default(), window, cx, |s| {
12818            s.move_cursors_with(|map, head, _| {
12819                (movement::next_subword_end(map, head), SelectionGoal::None)
12820            });
12821        })
12822    }
12823
12824    pub fn select_to_next_word_end(
12825        &mut self,
12826        _: &SelectToNextWordEnd,
12827        window: &mut Window,
12828        cx: &mut Context<Self>,
12829    ) {
12830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12831        self.change_selections(Default::default(), window, cx, |s| {
12832            s.move_heads_with(|map, head, _| {
12833                (movement::next_word_end(map, head), SelectionGoal::None)
12834            });
12835        })
12836    }
12837
12838    pub fn select_to_next_subword_end(
12839        &mut self,
12840        _: &SelectToNextSubwordEnd,
12841        window: &mut Window,
12842        cx: &mut Context<Self>,
12843    ) {
12844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12845        self.change_selections(Default::default(), window, cx, |s| {
12846            s.move_heads_with(|map, head, _| {
12847                (movement::next_subword_end(map, head), SelectionGoal::None)
12848            });
12849        })
12850    }
12851
12852    pub fn delete_to_next_word_end(
12853        &mut self,
12854        action: &DeleteToNextWordEnd,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12859        self.transact(window, cx, |this, window, cx| {
12860            this.change_selections(Default::default(), window, cx, |s| {
12861                s.move_with(|map, selection| {
12862                    if selection.is_empty() {
12863                        let cursor = if action.ignore_newlines {
12864                            movement::next_word_end(map, selection.head())
12865                        } else {
12866                            movement::next_word_end_or_newline(map, selection.head())
12867                        };
12868                        selection.set_head(cursor, SelectionGoal::None);
12869                    }
12870                });
12871            });
12872            this.insert("", window, cx);
12873        });
12874    }
12875
12876    pub fn delete_to_next_subword_end(
12877        &mut self,
12878        _: &DeleteToNextSubwordEnd,
12879        window: &mut Window,
12880        cx: &mut Context<Self>,
12881    ) {
12882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12883        self.transact(window, cx, |this, window, cx| {
12884            this.change_selections(Default::default(), window, cx, |s| {
12885                s.move_with(|map, selection| {
12886                    if selection.is_empty() {
12887                        let cursor = movement::next_subword_end(map, selection.head());
12888                        selection.set_head(cursor, SelectionGoal::None);
12889                    }
12890                });
12891            });
12892            this.insert("", window, cx);
12893        });
12894    }
12895
12896    pub fn move_to_beginning_of_line(
12897        &mut self,
12898        action: &MoveToBeginningOfLine,
12899        window: &mut Window,
12900        cx: &mut Context<Self>,
12901    ) {
12902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12903        self.change_selections(Default::default(), window, cx, |s| {
12904            s.move_cursors_with(|map, head, _| {
12905                (
12906                    movement::indented_line_beginning(
12907                        map,
12908                        head,
12909                        action.stop_at_soft_wraps,
12910                        action.stop_at_indent,
12911                    ),
12912                    SelectionGoal::None,
12913                )
12914            });
12915        })
12916    }
12917
12918    pub fn select_to_beginning_of_line(
12919        &mut self,
12920        action: &SelectToBeginningOfLine,
12921        window: &mut Window,
12922        cx: &mut Context<Self>,
12923    ) {
12924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12925        self.change_selections(Default::default(), window, cx, |s| {
12926            s.move_heads_with(|map, head, _| {
12927                (
12928                    movement::indented_line_beginning(
12929                        map,
12930                        head,
12931                        action.stop_at_soft_wraps,
12932                        action.stop_at_indent,
12933                    ),
12934                    SelectionGoal::None,
12935                )
12936            });
12937        });
12938    }
12939
12940    pub fn delete_to_beginning_of_line(
12941        &mut self,
12942        action: &DeleteToBeginningOfLine,
12943        window: &mut Window,
12944        cx: &mut Context<Self>,
12945    ) {
12946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12947        self.transact(window, cx, |this, window, cx| {
12948            this.change_selections(Default::default(), window, cx, |s| {
12949                s.move_with(|_, selection| {
12950                    selection.reversed = true;
12951                });
12952            });
12953
12954            this.select_to_beginning_of_line(
12955                &SelectToBeginningOfLine {
12956                    stop_at_soft_wraps: false,
12957                    stop_at_indent: action.stop_at_indent,
12958                },
12959                window,
12960                cx,
12961            );
12962            this.backspace(&Backspace, window, cx);
12963        });
12964    }
12965
12966    pub fn move_to_end_of_line(
12967        &mut self,
12968        action: &MoveToEndOfLine,
12969        window: &mut Window,
12970        cx: &mut Context<Self>,
12971    ) {
12972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12973        self.change_selections(Default::default(), window, cx, |s| {
12974            s.move_cursors_with(|map, head, _| {
12975                (
12976                    movement::line_end(map, head, action.stop_at_soft_wraps),
12977                    SelectionGoal::None,
12978                )
12979            });
12980        })
12981    }
12982
12983    pub fn select_to_end_of_line(
12984        &mut self,
12985        action: &SelectToEndOfLine,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_heads_with(|map, head, _| {
12992                (
12993                    movement::line_end(map, head, action.stop_at_soft_wraps),
12994                    SelectionGoal::None,
12995                )
12996            });
12997        })
12998    }
12999
13000    pub fn delete_to_end_of_line(
13001        &mut self,
13002        _: &DeleteToEndOfLine,
13003        window: &mut Window,
13004        cx: &mut Context<Self>,
13005    ) {
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13007        self.transact(window, cx, |this, window, cx| {
13008            this.select_to_end_of_line(
13009                &SelectToEndOfLine {
13010                    stop_at_soft_wraps: false,
13011                },
13012                window,
13013                cx,
13014            );
13015            this.delete(&Delete, window, cx);
13016        });
13017    }
13018
13019    pub fn cut_to_end_of_line(
13020        &mut self,
13021        _: &CutToEndOfLine,
13022        window: &mut Window,
13023        cx: &mut Context<Self>,
13024    ) {
13025        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13026        self.transact(window, cx, |this, window, cx| {
13027            this.select_to_end_of_line(
13028                &SelectToEndOfLine {
13029                    stop_at_soft_wraps: false,
13030                },
13031                window,
13032                cx,
13033            );
13034            this.cut(&Cut, window, cx);
13035        });
13036    }
13037
13038    pub fn move_to_start_of_paragraph(
13039        &mut self,
13040        _: &MoveToStartOfParagraph,
13041        window: &mut Window,
13042        cx: &mut Context<Self>,
13043    ) {
13044        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13045            cx.propagate();
13046            return;
13047        }
13048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13049        self.change_selections(Default::default(), window, cx, |s| {
13050            s.move_with(|map, selection| {
13051                selection.collapse_to(
13052                    movement::start_of_paragraph(map, selection.head(), 1),
13053                    SelectionGoal::None,
13054                )
13055            });
13056        })
13057    }
13058
13059    pub fn move_to_end_of_paragraph(
13060        &mut self,
13061        _: &MoveToEndOfParagraph,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13066            cx.propagate();
13067            return;
13068        }
13069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13070        self.change_selections(Default::default(), window, cx, |s| {
13071            s.move_with(|map, selection| {
13072                selection.collapse_to(
13073                    movement::end_of_paragraph(map, selection.head(), 1),
13074                    SelectionGoal::None,
13075                )
13076            });
13077        })
13078    }
13079
13080    pub fn select_to_start_of_paragraph(
13081        &mut self,
13082        _: &SelectToStartOfParagraph,
13083        window: &mut Window,
13084        cx: &mut Context<Self>,
13085    ) {
13086        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13087            cx.propagate();
13088            return;
13089        }
13090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13091        self.change_selections(Default::default(), window, cx, |s| {
13092            s.move_heads_with(|map, head, _| {
13093                (
13094                    movement::start_of_paragraph(map, head, 1),
13095                    SelectionGoal::None,
13096                )
13097            });
13098        })
13099    }
13100
13101    pub fn select_to_end_of_paragraph(
13102        &mut self,
13103        _: &SelectToEndOfParagraph,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13108            cx.propagate();
13109            return;
13110        }
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112        self.change_selections(Default::default(), window, cx, |s| {
13113            s.move_heads_with(|map, head, _| {
13114                (
13115                    movement::end_of_paragraph(map, head, 1),
13116                    SelectionGoal::None,
13117                )
13118            });
13119        })
13120    }
13121
13122    pub fn move_to_start_of_excerpt(
13123        &mut self,
13124        _: &MoveToStartOfExcerpt,
13125        window: &mut Window,
13126        cx: &mut Context<Self>,
13127    ) {
13128        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13129            cx.propagate();
13130            return;
13131        }
13132        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13133        self.change_selections(Default::default(), window, cx, |s| {
13134            s.move_with(|map, selection| {
13135                selection.collapse_to(
13136                    movement::start_of_excerpt(
13137                        map,
13138                        selection.head(),
13139                        workspace::searchable::Direction::Prev,
13140                    ),
13141                    SelectionGoal::None,
13142                )
13143            });
13144        })
13145    }
13146
13147    pub fn move_to_start_of_next_excerpt(
13148        &mut self,
13149        _: &MoveToStartOfNextExcerpt,
13150        window: &mut Window,
13151        cx: &mut Context<Self>,
13152    ) {
13153        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13154            cx.propagate();
13155            return;
13156        }
13157
13158        self.change_selections(Default::default(), window, cx, |s| {
13159            s.move_with(|map, selection| {
13160                selection.collapse_to(
13161                    movement::start_of_excerpt(
13162                        map,
13163                        selection.head(),
13164                        workspace::searchable::Direction::Next,
13165                    ),
13166                    SelectionGoal::None,
13167                )
13168            });
13169        })
13170    }
13171
13172    pub fn move_to_end_of_excerpt(
13173        &mut self,
13174        _: &MoveToEndOfExcerpt,
13175        window: &mut Window,
13176        cx: &mut Context<Self>,
13177    ) {
13178        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13179            cx.propagate();
13180            return;
13181        }
13182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13183        self.change_selections(Default::default(), window, cx, |s| {
13184            s.move_with(|map, selection| {
13185                selection.collapse_to(
13186                    movement::end_of_excerpt(
13187                        map,
13188                        selection.head(),
13189                        workspace::searchable::Direction::Next,
13190                    ),
13191                    SelectionGoal::None,
13192                )
13193            });
13194        })
13195    }
13196
13197    pub fn move_to_end_of_previous_excerpt(
13198        &mut self,
13199        _: &MoveToEndOfPreviousExcerpt,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) {
13203        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13204            cx.propagate();
13205            return;
13206        }
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13208        self.change_selections(Default::default(), window, cx, |s| {
13209            s.move_with(|map, selection| {
13210                selection.collapse_to(
13211                    movement::end_of_excerpt(
13212                        map,
13213                        selection.head(),
13214                        workspace::searchable::Direction::Prev,
13215                    ),
13216                    SelectionGoal::None,
13217                )
13218            });
13219        })
13220    }
13221
13222    pub fn select_to_start_of_excerpt(
13223        &mut self,
13224        _: &SelectToStartOfExcerpt,
13225        window: &mut Window,
13226        cx: &mut Context<Self>,
13227    ) {
13228        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13229            cx.propagate();
13230            return;
13231        }
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_heads_with(|map, head, _| {
13235                (
13236                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13237                    SelectionGoal::None,
13238                )
13239            });
13240        })
13241    }
13242
13243    pub fn select_to_start_of_next_excerpt(
13244        &mut self,
13245        _: &SelectToStartOfNextExcerpt,
13246        window: &mut Window,
13247        cx: &mut Context<Self>,
13248    ) {
13249        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13250            cx.propagate();
13251            return;
13252        }
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_heads_with(|map, head, _| {
13256                (
13257                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn select_to_end_of_excerpt(
13265        &mut self,
13266        _: &SelectToEndOfExcerpt,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13271            cx.propagate();
13272            return;
13273        }
13274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13275        self.change_selections(Default::default(), window, cx, |s| {
13276            s.move_heads_with(|map, head, _| {
13277                (
13278                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13279                    SelectionGoal::None,
13280                )
13281            });
13282        })
13283    }
13284
13285    pub fn select_to_end_of_previous_excerpt(
13286        &mut self,
13287        _: &SelectToEndOfPreviousExcerpt,
13288        window: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13292            cx.propagate();
13293            return;
13294        }
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296        self.change_selections(Default::default(), window, cx, |s| {
13297            s.move_heads_with(|map, head, _| {
13298                (
13299                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13300                    SelectionGoal::None,
13301                )
13302            });
13303        })
13304    }
13305
13306    pub fn move_to_beginning(
13307        &mut self,
13308        _: &MoveToBeginning,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13313            cx.propagate();
13314            return;
13315        }
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13317        self.change_selections(Default::default(), window, cx, |s| {
13318            s.select_ranges(vec![0..0]);
13319        });
13320    }
13321
13322    pub fn select_to_beginning(
13323        &mut self,
13324        _: &SelectToBeginning,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        let mut selection = self.selections.last::<Point>(cx);
13329        selection.set_head(Point::zero(), SelectionGoal::None);
13330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13331        self.change_selections(Default::default(), window, cx, |s| {
13332            s.select(vec![selection]);
13333        });
13334    }
13335
13336    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13337        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13338            cx.propagate();
13339            return;
13340        }
13341        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13342        let cursor = self.buffer.read(cx).read(cx).len();
13343        self.change_selections(Default::default(), window, cx, |s| {
13344            s.select_ranges(vec![cursor..cursor])
13345        });
13346    }
13347
13348    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13349        self.nav_history = nav_history;
13350    }
13351
13352    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13353        self.nav_history.as_ref()
13354    }
13355
13356    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13357        self.push_to_nav_history(
13358            self.selections.newest_anchor().head(),
13359            None,
13360            false,
13361            true,
13362            cx,
13363        );
13364    }
13365
13366    fn push_to_nav_history(
13367        &mut self,
13368        cursor_anchor: Anchor,
13369        new_position: Option<Point>,
13370        is_deactivate: bool,
13371        always: bool,
13372        cx: &mut Context<Self>,
13373    ) {
13374        if let Some(nav_history) = self.nav_history.as_mut() {
13375            let buffer = self.buffer.read(cx).read(cx);
13376            let cursor_position = cursor_anchor.to_point(&buffer);
13377            let scroll_state = self.scroll_manager.anchor();
13378            let scroll_top_row = scroll_state.top_row(&buffer);
13379            drop(buffer);
13380
13381            if let Some(new_position) = new_position {
13382                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13383                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13384                    return;
13385                }
13386            }
13387
13388            nav_history.push(
13389                Some(NavigationData {
13390                    cursor_anchor,
13391                    cursor_position,
13392                    scroll_anchor: scroll_state,
13393                    scroll_top_row,
13394                }),
13395                cx,
13396            );
13397            cx.emit(EditorEvent::PushedToNavHistory {
13398                anchor: cursor_anchor,
13399                is_deactivate,
13400            })
13401        }
13402    }
13403
13404    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13406        let buffer = self.buffer.read(cx).snapshot(cx);
13407        let mut selection = self.selections.first::<usize>(cx);
13408        selection.set_head(buffer.len(), SelectionGoal::None);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.select(vec![selection]);
13411        });
13412    }
13413
13414    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13416        let end = self.buffer.read(cx).read(cx).len();
13417        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13418            s.select_ranges(vec![0..end]);
13419        });
13420    }
13421
13422    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13424        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13425        let mut selections = self.selections.all::<Point>(cx);
13426        let max_point = display_map.buffer_snapshot.max_point();
13427        for selection in &mut selections {
13428            let rows = selection.spanned_rows(true, &display_map);
13429            selection.start = Point::new(rows.start.0, 0);
13430            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13431            selection.reversed = false;
13432        }
13433        self.change_selections(Default::default(), window, cx, |s| {
13434            s.select(selections);
13435        });
13436    }
13437
13438    pub fn split_selection_into_lines(
13439        &mut self,
13440        _: &SplitSelectionIntoLines,
13441        window: &mut Window,
13442        cx: &mut Context<Self>,
13443    ) {
13444        let selections = self
13445            .selections
13446            .all::<Point>(cx)
13447            .into_iter()
13448            .map(|selection| selection.start..selection.end)
13449            .collect::<Vec<_>>();
13450        self.unfold_ranges(&selections, true, true, cx);
13451
13452        let mut new_selection_ranges = Vec::new();
13453        {
13454            let buffer = self.buffer.read(cx).read(cx);
13455            for selection in selections {
13456                for row in selection.start.row..selection.end.row {
13457                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13458                    new_selection_ranges.push(cursor..cursor);
13459                }
13460
13461                let is_multiline_selection = selection.start.row != selection.end.row;
13462                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13463                // so this action feels more ergonomic when paired with other selection operations
13464                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13465                if !should_skip_last {
13466                    new_selection_ranges.push(selection.end..selection.end);
13467                }
13468            }
13469        }
13470        self.change_selections(Default::default(), window, cx, |s| {
13471            s.select_ranges(new_selection_ranges);
13472        });
13473    }
13474
13475    pub fn add_selection_above(
13476        &mut self,
13477        _: &AddSelectionAbove,
13478        window: &mut Window,
13479        cx: &mut Context<Self>,
13480    ) {
13481        self.add_selection(true, window, cx);
13482    }
13483
13484    pub fn add_selection_below(
13485        &mut self,
13486        _: &AddSelectionBelow,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.add_selection(false, window, cx);
13491    }
13492
13493    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13494        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13495
13496        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13497        let all_selections = self.selections.all::<Point>(cx);
13498        let text_layout_details = self.text_layout_details(window);
13499
13500        let (mut columnar_selections, new_selections_to_columnarize) = {
13501            if let Some(state) = self.add_selections_state.as_ref() {
13502                let columnar_selection_ids: HashSet<_> = state
13503                    .groups
13504                    .iter()
13505                    .flat_map(|group| group.stack.iter())
13506                    .copied()
13507                    .collect();
13508
13509                all_selections
13510                    .into_iter()
13511                    .partition(|s| columnar_selection_ids.contains(&s.id))
13512            } else {
13513                (Vec::new(), all_selections)
13514            }
13515        };
13516
13517        let mut state = self
13518            .add_selections_state
13519            .take()
13520            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13521
13522        for selection in new_selections_to_columnarize {
13523            let range = selection.display_range(&display_map).sorted();
13524            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13525            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13526            let positions = start_x.min(end_x)..start_x.max(end_x);
13527            let mut stack = Vec::new();
13528            for row in range.start.row().0..=range.end.row().0 {
13529                if let Some(selection) = self.selections.build_columnar_selection(
13530                    &display_map,
13531                    DisplayRow(row),
13532                    &positions,
13533                    selection.reversed,
13534                    &text_layout_details,
13535                ) {
13536                    stack.push(selection.id);
13537                    columnar_selections.push(selection);
13538                }
13539            }
13540            if !stack.is_empty() {
13541                if above {
13542                    stack.reverse();
13543                }
13544                state.groups.push(AddSelectionsGroup { above, stack });
13545            }
13546        }
13547
13548        let mut final_selections = Vec::new();
13549        let end_row = if above {
13550            DisplayRow(0)
13551        } else {
13552            display_map.max_point().row()
13553        };
13554
13555        let mut last_added_item_per_group = HashMap::default();
13556        for group in state.groups.iter_mut() {
13557            if let Some(last_id) = group.stack.last() {
13558                last_added_item_per_group.insert(*last_id, group);
13559            }
13560        }
13561
13562        for selection in columnar_selections {
13563            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13564                if above == group.above {
13565                    let range = selection.display_range(&display_map).sorted();
13566                    debug_assert_eq!(range.start.row(), range.end.row());
13567                    let mut row = range.start.row();
13568                    let positions =
13569                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13570                            px(start)..px(end)
13571                        } else {
13572                            let start_x =
13573                                display_map.x_for_display_point(range.start, &text_layout_details);
13574                            let end_x =
13575                                display_map.x_for_display_point(range.end, &text_layout_details);
13576                            start_x.min(end_x)..start_x.max(end_x)
13577                        };
13578
13579                    let mut maybe_new_selection = None;
13580                    while row != end_row {
13581                        if above {
13582                            row.0 -= 1;
13583                        } else {
13584                            row.0 += 1;
13585                        }
13586                        if let Some(new_selection) = self.selections.build_columnar_selection(
13587                            &display_map,
13588                            row,
13589                            &positions,
13590                            selection.reversed,
13591                            &text_layout_details,
13592                        ) {
13593                            maybe_new_selection = Some(new_selection);
13594                            break;
13595                        }
13596                    }
13597
13598                    if let Some(new_selection) = maybe_new_selection {
13599                        group.stack.push(new_selection.id);
13600                        if above {
13601                            final_selections.push(new_selection);
13602                            final_selections.push(selection);
13603                        } else {
13604                            final_selections.push(selection);
13605                            final_selections.push(new_selection);
13606                        }
13607                    } else {
13608                        final_selections.push(selection);
13609                    }
13610                } else {
13611                    group.stack.pop();
13612                }
13613            } else {
13614                final_selections.push(selection);
13615            }
13616        }
13617
13618        self.change_selections(Default::default(), window, cx, |s| {
13619            s.select(final_selections);
13620        });
13621
13622        let final_selection_ids: HashSet<_> = self
13623            .selections
13624            .all::<Point>(cx)
13625            .iter()
13626            .map(|s| s.id)
13627            .collect();
13628        state.groups.retain_mut(|group| {
13629            // selections might get merged above so we remove invalid items from stacks
13630            group.stack.retain(|id| final_selection_ids.contains(id));
13631
13632            // single selection in stack can be treated as initial state
13633            group.stack.len() > 1
13634        });
13635
13636        if !state.groups.is_empty() {
13637            self.add_selections_state = Some(state);
13638        }
13639    }
13640
13641    fn select_match_ranges(
13642        &mut self,
13643        range: Range<usize>,
13644        reversed: bool,
13645        replace_newest: bool,
13646        auto_scroll: Option<Autoscroll>,
13647        window: &mut Window,
13648        cx: &mut Context<Editor>,
13649    ) {
13650        self.unfold_ranges(
13651            std::slice::from_ref(&range),
13652            false,
13653            auto_scroll.is_some(),
13654            cx,
13655        );
13656        let effects = if let Some(scroll) = auto_scroll {
13657            SelectionEffects::scroll(scroll)
13658        } else {
13659            SelectionEffects::no_scroll()
13660        };
13661        self.change_selections(effects, window, cx, |s| {
13662            if replace_newest {
13663                s.delete(s.newest_anchor().id);
13664            }
13665            if reversed {
13666                s.insert_range(range.end..range.start);
13667            } else {
13668                s.insert_range(range);
13669            }
13670        });
13671    }
13672
13673    pub fn select_next_match_internal(
13674        &mut self,
13675        display_map: &DisplaySnapshot,
13676        replace_newest: bool,
13677        autoscroll: Option<Autoscroll>,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) -> Result<()> {
13681        let buffer = &display_map.buffer_snapshot;
13682        let mut selections = self.selections.all::<usize>(cx);
13683        if let Some(mut select_next_state) = self.select_next_state.take() {
13684            let query = &select_next_state.query;
13685            if !select_next_state.done {
13686                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13687                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13688                let mut next_selected_range = None;
13689
13690                let bytes_after_last_selection =
13691                    buffer.bytes_in_range(last_selection.end..buffer.len());
13692                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13693                let query_matches = query
13694                    .stream_find_iter(bytes_after_last_selection)
13695                    .map(|result| (last_selection.end, result))
13696                    .chain(
13697                        query
13698                            .stream_find_iter(bytes_before_first_selection)
13699                            .map(|result| (0, result)),
13700                    );
13701
13702                for (start_offset, query_match) in query_matches {
13703                    let query_match = query_match.unwrap(); // can only fail due to I/O
13704                    let offset_range =
13705                        start_offset + query_match.start()..start_offset + query_match.end();
13706
13707                    if !select_next_state.wordwise
13708                        || (!buffer.is_inside_word(offset_range.start, false)
13709                            && !buffer.is_inside_word(offset_range.end, false))
13710                    {
13711                        // TODO: This is n^2, because we might check all the selections
13712                        if !selections
13713                            .iter()
13714                            .any(|selection| selection.range().overlaps(&offset_range))
13715                        {
13716                            next_selected_range = Some(offset_range);
13717                            break;
13718                        }
13719                    }
13720                }
13721
13722                if let Some(next_selected_range) = next_selected_range {
13723                    self.select_match_ranges(
13724                        next_selected_range,
13725                        last_selection.reversed,
13726                        replace_newest,
13727                        autoscroll,
13728                        window,
13729                        cx,
13730                    );
13731                } else {
13732                    select_next_state.done = true;
13733                }
13734            }
13735
13736            self.select_next_state = Some(select_next_state);
13737        } else {
13738            let mut only_carets = true;
13739            let mut same_text_selected = true;
13740            let mut selected_text = None;
13741
13742            let mut selections_iter = selections.iter().peekable();
13743            while let Some(selection) = selections_iter.next() {
13744                if selection.start != selection.end {
13745                    only_carets = false;
13746                }
13747
13748                if same_text_selected {
13749                    if selected_text.is_none() {
13750                        selected_text =
13751                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13752                    }
13753
13754                    if let Some(next_selection) = selections_iter.peek() {
13755                        if next_selection.range().len() == selection.range().len() {
13756                            let next_selected_text = buffer
13757                                .text_for_range(next_selection.range())
13758                                .collect::<String>();
13759                            if Some(next_selected_text) != selected_text {
13760                                same_text_selected = false;
13761                                selected_text = None;
13762                            }
13763                        } else {
13764                            same_text_selected = false;
13765                            selected_text = None;
13766                        }
13767                    }
13768                }
13769            }
13770
13771            if only_carets {
13772                for selection in &mut selections {
13773                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13774                    selection.start = word_range.start;
13775                    selection.end = word_range.end;
13776                    selection.goal = SelectionGoal::None;
13777                    selection.reversed = false;
13778                    self.select_match_ranges(
13779                        selection.start..selection.end,
13780                        selection.reversed,
13781                        replace_newest,
13782                        autoscroll,
13783                        window,
13784                        cx,
13785                    );
13786                }
13787
13788                if selections.len() == 1 {
13789                    let selection = selections
13790                        .last()
13791                        .expect("ensured that there's only one selection");
13792                    let query = buffer
13793                        .text_for_range(selection.start..selection.end)
13794                        .collect::<String>();
13795                    let is_empty = query.is_empty();
13796                    let select_state = SelectNextState {
13797                        query: AhoCorasick::new(&[query])?,
13798                        wordwise: true,
13799                        done: is_empty,
13800                    };
13801                    self.select_next_state = Some(select_state);
13802                } else {
13803                    self.select_next_state = None;
13804                }
13805            } else if let Some(selected_text) = selected_text {
13806                self.select_next_state = Some(SelectNextState {
13807                    query: AhoCorasick::new(&[selected_text])?,
13808                    wordwise: false,
13809                    done: false,
13810                });
13811                self.select_next_match_internal(
13812                    display_map,
13813                    replace_newest,
13814                    autoscroll,
13815                    window,
13816                    cx,
13817                )?;
13818            }
13819        }
13820        Ok(())
13821    }
13822
13823    pub fn select_all_matches(
13824        &mut self,
13825        _action: &SelectAllMatches,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) -> Result<()> {
13829        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13830
13831        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13832
13833        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13834        let Some(select_next_state) = self.select_next_state.as_mut() else {
13835            return Ok(());
13836        };
13837        if select_next_state.done {
13838            return Ok(());
13839        }
13840
13841        let mut new_selections = Vec::new();
13842
13843        let reversed = self.selections.oldest::<usize>(cx).reversed;
13844        let buffer = &display_map.buffer_snapshot;
13845        let query_matches = select_next_state
13846            .query
13847            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13848
13849        for query_match in query_matches.into_iter() {
13850            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13851            let offset_range = if reversed {
13852                query_match.end()..query_match.start()
13853            } else {
13854                query_match.start()..query_match.end()
13855            };
13856
13857            if !select_next_state.wordwise
13858                || (!buffer.is_inside_word(offset_range.start, false)
13859                    && !buffer.is_inside_word(offset_range.end, false))
13860            {
13861                new_selections.push(offset_range.start..offset_range.end);
13862            }
13863        }
13864
13865        select_next_state.done = true;
13866
13867        if new_selections.is_empty() {
13868            log::error!("bug: new_selections is empty in select_all_matches");
13869            return Ok(());
13870        }
13871
13872        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13873        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13874            selections.select_ranges(new_selections)
13875        });
13876
13877        Ok(())
13878    }
13879
13880    pub fn select_next(
13881        &mut self,
13882        action: &SelectNext,
13883        window: &mut Window,
13884        cx: &mut Context<Self>,
13885    ) -> Result<()> {
13886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13887        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13888        self.select_next_match_internal(
13889            &display_map,
13890            action.replace_newest,
13891            Some(Autoscroll::newest()),
13892            window,
13893            cx,
13894        )?;
13895        Ok(())
13896    }
13897
13898    pub fn select_previous(
13899        &mut self,
13900        action: &SelectPrevious,
13901        window: &mut Window,
13902        cx: &mut Context<Self>,
13903    ) -> Result<()> {
13904        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13905        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13906        let buffer = &display_map.buffer_snapshot;
13907        let mut selections = self.selections.all::<usize>(cx);
13908        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13909            let query = &select_prev_state.query;
13910            if !select_prev_state.done {
13911                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13912                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13913                let mut next_selected_range = None;
13914                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13915                let bytes_before_last_selection =
13916                    buffer.reversed_bytes_in_range(0..last_selection.start);
13917                let bytes_after_first_selection =
13918                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13919                let query_matches = query
13920                    .stream_find_iter(bytes_before_last_selection)
13921                    .map(|result| (last_selection.start, result))
13922                    .chain(
13923                        query
13924                            .stream_find_iter(bytes_after_first_selection)
13925                            .map(|result| (buffer.len(), result)),
13926                    );
13927                for (end_offset, query_match) in query_matches {
13928                    let query_match = query_match.unwrap(); // can only fail due to I/O
13929                    let offset_range =
13930                        end_offset - query_match.end()..end_offset - query_match.start();
13931
13932                    if !select_prev_state.wordwise
13933                        || (!buffer.is_inside_word(offset_range.start, false)
13934                            && !buffer.is_inside_word(offset_range.end, false))
13935                    {
13936                        next_selected_range = Some(offset_range);
13937                        break;
13938                    }
13939                }
13940
13941                if let Some(next_selected_range) = next_selected_range {
13942                    self.select_match_ranges(
13943                        next_selected_range,
13944                        last_selection.reversed,
13945                        action.replace_newest,
13946                        Some(Autoscroll::newest()),
13947                        window,
13948                        cx,
13949                    );
13950                } else {
13951                    select_prev_state.done = true;
13952                }
13953            }
13954
13955            self.select_prev_state = Some(select_prev_state);
13956        } else {
13957            let mut only_carets = true;
13958            let mut same_text_selected = true;
13959            let mut selected_text = None;
13960
13961            let mut selections_iter = selections.iter().peekable();
13962            while let Some(selection) = selections_iter.next() {
13963                if selection.start != selection.end {
13964                    only_carets = false;
13965                }
13966
13967                if same_text_selected {
13968                    if selected_text.is_none() {
13969                        selected_text =
13970                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13971                    }
13972
13973                    if let Some(next_selection) = selections_iter.peek() {
13974                        if next_selection.range().len() == selection.range().len() {
13975                            let next_selected_text = buffer
13976                                .text_for_range(next_selection.range())
13977                                .collect::<String>();
13978                            if Some(next_selected_text) != selected_text {
13979                                same_text_selected = false;
13980                                selected_text = None;
13981                            }
13982                        } else {
13983                            same_text_selected = false;
13984                            selected_text = None;
13985                        }
13986                    }
13987                }
13988            }
13989
13990            if only_carets {
13991                for selection in &mut selections {
13992                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13993                    selection.start = word_range.start;
13994                    selection.end = word_range.end;
13995                    selection.goal = SelectionGoal::None;
13996                    selection.reversed = false;
13997                    self.select_match_ranges(
13998                        selection.start..selection.end,
13999                        selection.reversed,
14000                        action.replace_newest,
14001                        Some(Autoscroll::newest()),
14002                        window,
14003                        cx,
14004                    );
14005                }
14006                if selections.len() == 1 {
14007                    let selection = selections
14008                        .last()
14009                        .expect("ensured that there's only one selection");
14010                    let query = buffer
14011                        .text_for_range(selection.start..selection.end)
14012                        .collect::<String>();
14013                    let is_empty = query.is_empty();
14014                    let select_state = SelectNextState {
14015                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14016                        wordwise: true,
14017                        done: is_empty,
14018                    };
14019                    self.select_prev_state = Some(select_state);
14020                } else {
14021                    self.select_prev_state = None;
14022                }
14023            } else if let Some(selected_text) = selected_text {
14024                self.select_prev_state = Some(SelectNextState {
14025                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14026                    wordwise: false,
14027                    done: false,
14028                });
14029                self.select_previous(action, window, cx)?;
14030            }
14031        }
14032        Ok(())
14033    }
14034
14035    pub fn find_next_match(
14036        &mut self,
14037        _: &FindNextMatch,
14038        window: &mut Window,
14039        cx: &mut Context<Self>,
14040    ) -> Result<()> {
14041        let selections = self.selections.disjoint_anchors();
14042        match selections.first() {
14043            Some(first) if selections.len() >= 2 => {
14044                self.change_selections(Default::default(), window, cx, |s| {
14045                    s.select_ranges([first.range()]);
14046                });
14047            }
14048            _ => self.select_next(
14049                &SelectNext {
14050                    replace_newest: true,
14051                },
14052                window,
14053                cx,
14054            )?,
14055        }
14056        Ok(())
14057    }
14058
14059    pub fn find_previous_match(
14060        &mut self,
14061        _: &FindPreviousMatch,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) -> Result<()> {
14065        let selections = self.selections.disjoint_anchors();
14066        match selections.last() {
14067            Some(last) if selections.len() >= 2 => {
14068                self.change_selections(Default::default(), window, cx, |s| {
14069                    s.select_ranges([last.range()]);
14070                });
14071            }
14072            _ => self.select_previous(
14073                &SelectPrevious {
14074                    replace_newest: true,
14075                },
14076                window,
14077                cx,
14078            )?,
14079        }
14080        Ok(())
14081    }
14082
14083    pub fn toggle_comments(
14084        &mut self,
14085        action: &ToggleComments,
14086        window: &mut Window,
14087        cx: &mut Context<Self>,
14088    ) {
14089        if self.read_only(cx) {
14090            return;
14091        }
14092        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14093        let text_layout_details = &self.text_layout_details(window);
14094        self.transact(window, cx, |this, window, cx| {
14095            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14096            let mut edits = Vec::new();
14097            let mut selection_edit_ranges = Vec::new();
14098            let mut last_toggled_row = None;
14099            let snapshot = this.buffer.read(cx).read(cx);
14100            let empty_str: Arc<str> = Arc::default();
14101            let mut suffixes_inserted = Vec::new();
14102            let ignore_indent = action.ignore_indent;
14103
14104            fn comment_prefix_range(
14105                snapshot: &MultiBufferSnapshot,
14106                row: MultiBufferRow,
14107                comment_prefix: &str,
14108                comment_prefix_whitespace: &str,
14109                ignore_indent: bool,
14110            ) -> Range<Point> {
14111                let indent_size = if ignore_indent {
14112                    0
14113                } else {
14114                    snapshot.indent_size_for_line(row).len
14115                };
14116
14117                let start = Point::new(row.0, indent_size);
14118
14119                let mut line_bytes = snapshot
14120                    .bytes_in_range(start..snapshot.max_point())
14121                    .flatten()
14122                    .copied();
14123
14124                // If this line currently begins with the line comment prefix, then record
14125                // the range containing the prefix.
14126                if line_bytes
14127                    .by_ref()
14128                    .take(comment_prefix.len())
14129                    .eq(comment_prefix.bytes())
14130                {
14131                    // Include any whitespace that matches the comment prefix.
14132                    let matching_whitespace_len = line_bytes
14133                        .zip(comment_prefix_whitespace.bytes())
14134                        .take_while(|(a, b)| a == b)
14135                        .count() as u32;
14136                    let end = Point::new(
14137                        start.row,
14138                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14139                    );
14140                    start..end
14141                } else {
14142                    start..start
14143                }
14144            }
14145
14146            fn comment_suffix_range(
14147                snapshot: &MultiBufferSnapshot,
14148                row: MultiBufferRow,
14149                comment_suffix: &str,
14150                comment_suffix_has_leading_space: bool,
14151            ) -> Range<Point> {
14152                let end = Point::new(row.0, snapshot.line_len(row));
14153                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14154
14155                let mut line_end_bytes = snapshot
14156                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14157                    .flatten()
14158                    .copied();
14159
14160                let leading_space_len = if suffix_start_column > 0
14161                    && line_end_bytes.next() == Some(b' ')
14162                    && comment_suffix_has_leading_space
14163                {
14164                    1
14165                } else {
14166                    0
14167                };
14168
14169                // If this line currently begins with the line comment prefix, then record
14170                // the range containing the prefix.
14171                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14172                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14173                    start..end
14174                } else {
14175                    end..end
14176                }
14177            }
14178
14179            // TODO: Handle selections that cross excerpts
14180            for selection in &mut selections {
14181                let start_column = snapshot
14182                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14183                    .len;
14184                let language = if let Some(language) =
14185                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14186                {
14187                    language
14188                } else {
14189                    continue;
14190                };
14191
14192                selection_edit_ranges.clear();
14193
14194                // If multiple selections contain a given row, avoid processing that
14195                // row more than once.
14196                let mut start_row = MultiBufferRow(selection.start.row);
14197                if last_toggled_row == Some(start_row) {
14198                    start_row = start_row.next_row();
14199                }
14200                let end_row =
14201                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14202                        MultiBufferRow(selection.end.row - 1)
14203                    } else {
14204                        MultiBufferRow(selection.end.row)
14205                    };
14206                last_toggled_row = Some(end_row);
14207
14208                if start_row > end_row {
14209                    continue;
14210                }
14211
14212                // If the language has line comments, toggle those.
14213                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14214
14215                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14216                if ignore_indent {
14217                    full_comment_prefixes = full_comment_prefixes
14218                        .into_iter()
14219                        .map(|s| Arc::from(s.trim_end()))
14220                        .collect();
14221                }
14222
14223                if !full_comment_prefixes.is_empty() {
14224                    let first_prefix = full_comment_prefixes
14225                        .first()
14226                        .expect("prefixes is non-empty");
14227                    let prefix_trimmed_lengths = full_comment_prefixes
14228                        .iter()
14229                        .map(|p| p.trim_end_matches(' ').len())
14230                        .collect::<SmallVec<[usize; 4]>>();
14231
14232                    let mut all_selection_lines_are_comments = true;
14233
14234                    for row in start_row.0..=end_row.0 {
14235                        let row = MultiBufferRow(row);
14236                        if start_row < end_row && snapshot.is_line_blank(row) {
14237                            continue;
14238                        }
14239
14240                        let prefix_range = full_comment_prefixes
14241                            .iter()
14242                            .zip(prefix_trimmed_lengths.iter().copied())
14243                            .map(|(prefix, trimmed_prefix_len)| {
14244                                comment_prefix_range(
14245                                    snapshot.deref(),
14246                                    row,
14247                                    &prefix[..trimmed_prefix_len],
14248                                    &prefix[trimmed_prefix_len..],
14249                                    ignore_indent,
14250                                )
14251                            })
14252                            .max_by_key(|range| range.end.column - range.start.column)
14253                            .expect("prefixes is non-empty");
14254
14255                        if prefix_range.is_empty() {
14256                            all_selection_lines_are_comments = false;
14257                        }
14258
14259                        selection_edit_ranges.push(prefix_range);
14260                    }
14261
14262                    if all_selection_lines_are_comments {
14263                        edits.extend(
14264                            selection_edit_ranges
14265                                .iter()
14266                                .cloned()
14267                                .map(|range| (range, empty_str.clone())),
14268                        );
14269                    } else {
14270                        let min_column = selection_edit_ranges
14271                            .iter()
14272                            .map(|range| range.start.column)
14273                            .min()
14274                            .unwrap_or(0);
14275                        edits.extend(selection_edit_ranges.iter().map(|range| {
14276                            let position = Point::new(range.start.row, min_column);
14277                            (position..position, first_prefix.clone())
14278                        }));
14279                    }
14280                } else if let Some((full_comment_prefix, comment_suffix)) =
14281                    language.block_comment_delimiters()
14282                {
14283                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14284                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14285                    let prefix_range = comment_prefix_range(
14286                        snapshot.deref(),
14287                        start_row,
14288                        comment_prefix,
14289                        comment_prefix_whitespace,
14290                        ignore_indent,
14291                    );
14292                    let suffix_range = comment_suffix_range(
14293                        snapshot.deref(),
14294                        end_row,
14295                        comment_suffix.trim_start_matches(' '),
14296                        comment_suffix.starts_with(' '),
14297                    );
14298
14299                    if prefix_range.is_empty() || suffix_range.is_empty() {
14300                        edits.push((
14301                            prefix_range.start..prefix_range.start,
14302                            full_comment_prefix.clone(),
14303                        ));
14304                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14305                        suffixes_inserted.push((end_row, comment_suffix.len()));
14306                    } else {
14307                        edits.push((prefix_range, empty_str.clone()));
14308                        edits.push((suffix_range, empty_str.clone()));
14309                    }
14310                } else {
14311                    continue;
14312                }
14313            }
14314
14315            drop(snapshot);
14316            this.buffer.update(cx, |buffer, cx| {
14317                buffer.edit(edits, None, cx);
14318            });
14319
14320            // Adjust selections so that they end before any comment suffixes that
14321            // were inserted.
14322            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14323            let mut selections = this.selections.all::<Point>(cx);
14324            let snapshot = this.buffer.read(cx).read(cx);
14325            for selection in &mut selections {
14326                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14327                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14328                        Ordering::Less => {
14329                            suffixes_inserted.next();
14330                            continue;
14331                        }
14332                        Ordering::Greater => break,
14333                        Ordering::Equal => {
14334                            if selection.end.column == snapshot.line_len(row) {
14335                                if selection.is_empty() {
14336                                    selection.start.column -= suffix_len as u32;
14337                                }
14338                                selection.end.column -= suffix_len as u32;
14339                            }
14340                            break;
14341                        }
14342                    }
14343                }
14344            }
14345
14346            drop(snapshot);
14347            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14348
14349            let selections = this.selections.all::<Point>(cx);
14350            let selections_on_single_row = selections.windows(2).all(|selections| {
14351                selections[0].start.row == selections[1].start.row
14352                    && selections[0].end.row == selections[1].end.row
14353                    && selections[0].start.row == selections[0].end.row
14354            });
14355            let selections_selecting = selections
14356                .iter()
14357                .any(|selection| selection.start != selection.end);
14358            let advance_downwards = action.advance_downwards
14359                && selections_on_single_row
14360                && !selections_selecting
14361                && !matches!(this.mode, EditorMode::SingleLine { .. });
14362
14363            if advance_downwards {
14364                let snapshot = this.buffer.read(cx).snapshot(cx);
14365
14366                this.change_selections(Default::default(), window, cx, |s| {
14367                    s.move_cursors_with(|display_snapshot, display_point, _| {
14368                        let mut point = display_point.to_point(display_snapshot);
14369                        point.row += 1;
14370                        point = snapshot.clip_point(point, Bias::Left);
14371                        let display_point = point.to_display_point(display_snapshot);
14372                        let goal = SelectionGoal::HorizontalPosition(
14373                            display_snapshot
14374                                .x_for_display_point(display_point, text_layout_details)
14375                                .into(),
14376                        );
14377                        (display_point, goal)
14378                    })
14379                });
14380            }
14381        });
14382    }
14383
14384    pub fn select_enclosing_symbol(
14385        &mut self,
14386        _: &SelectEnclosingSymbol,
14387        window: &mut Window,
14388        cx: &mut Context<Self>,
14389    ) {
14390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14391
14392        let buffer = self.buffer.read(cx).snapshot(cx);
14393        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14394
14395        fn update_selection(
14396            selection: &Selection<usize>,
14397            buffer_snap: &MultiBufferSnapshot,
14398        ) -> Option<Selection<usize>> {
14399            let cursor = selection.head();
14400            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14401            for symbol in symbols.iter().rev() {
14402                let start = symbol.range.start.to_offset(buffer_snap);
14403                let end = symbol.range.end.to_offset(buffer_snap);
14404                let new_range = start..end;
14405                if start < selection.start || end > selection.end {
14406                    return Some(Selection {
14407                        id: selection.id,
14408                        start: new_range.start,
14409                        end: new_range.end,
14410                        goal: SelectionGoal::None,
14411                        reversed: selection.reversed,
14412                    });
14413                }
14414            }
14415            None
14416        }
14417
14418        let mut selected_larger_symbol = false;
14419        let new_selections = old_selections
14420            .iter()
14421            .map(|selection| match update_selection(selection, &buffer) {
14422                Some(new_selection) => {
14423                    if new_selection.range() != selection.range() {
14424                        selected_larger_symbol = true;
14425                    }
14426                    new_selection
14427                }
14428                None => selection.clone(),
14429            })
14430            .collect::<Vec<_>>();
14431
14432        if selected_larger_symbol {
14433            self.change_selections(Default::default(), window, cx, |s| {
14434                s.select(new_selections);
14435            });
14436        }
14437    }
14438
14439    pub fn select_larger_syntax_node(
14440        &mut self,
14441        _: &SelectLargerSyntaxNode,
14442        window: &mut Window,
14443        cx: &mut Context<Self>,
14444    ) {
14445        let Some(visible_row_count) = self.visible_row_count() else {
14446            return;
14447        };
14448        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14449        if old_selections.is_empty() {
14450            return;
14451        }
14452
14453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14454
14455        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14456        let buffer = self.buffer.read(cx).snapshot(cx);
14457
14458        let mut selected_larger_node = false;
14459        let mut new_selections = old_selections
14460            .iter()
14461            .map(|selection| {
14462                let old_range = selection.start..selection.end;
14463
14464                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14465                    // manually select word at selection
14466                    if ["string_content", "inline"].contains(&node.kind()) {
14467                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14468                        // ignore if word is already selected
14469                        if !word_range.is_empty() && old_range != word_range {
14470                            let (last_word_range, _) =
14471                                buffer.surrounding_word(old_range.end, false);
14472                            // only select word if start and end point belongs to same word
14473                            if word_range == last_word_range {
14474                                selected_larger_node = true;
14475                                return Selection {
14476                                    id: selection.id,
14477                                    start: word_range.start,
14478                                    end: word_range.end,
14479                                    goal: SelectionGoal::None,
14480                                    reversed: selection.reversed,
14481                                };
14482                            }
14483                        }
14484                    }
14485                }
14486
14487                let mut new_range = old_range.clone();
14488                while let Some((_node, containing_range)) =
14489                    buffer.syntax_ancestor(new_range.clone())
14490                {
14491                    new_range = match containing_range {
14492                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14493                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14494                    };
14495                    if !display_map.intersects_fold(new_range.start)
14496                        && !display_map.intersects_fold(new_range.end)
14497                    {
14498                        break;
14499                    }
14500                }
14501
14502                selected_larger_node |= new_range != old_range;
14503                Selection {
14504                    id: selection.id,
14505                    start: new_range.start,
14506                    end: new_range.end,
14507                    goal: SelectionGoal::None,
14508                    reversed: selection.reversed,
14509                }
14510            })
14511            .collect::<Vec<_>>();
14512
14513        if !selected_larger_node {
14514            return; // don't put this call in the history
14515        }
14516
14517        // scroll based on transformation done to the last selection created by the user
14518        let (last_old, last_new) = old_selections
14519            .last()
14520            .zip(new_selections.last().cloned())
14521            .expect("old_selections isn't empty");
14522
14523        // revert selection
14524        let is_selection_reversed = {
14525            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14526            new_selections.last_mut().expect("checked above").reversed =
14527                should_newest_selection_be_reversed;
14528            should_newest_selection_be_reversed
14529        };
14530
14531        if selected_larger_node {
14532            self.select_syntax_node_history.disable_clearing = true;
14533            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14534                s.select(new_selections.clone());
14535            });
14536            self.select_syntax_node_history.disable_clearing = false;
14537        }
14538
14539        let start_row = last_new.start.to_display_point(&display_map).row().0;
14540        let end_row = last_new.end.to_display_point(&display_map).row().0;
14541        let selection_height = end_row - start_row + 1;
14542        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14543
14544        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14545        let scroll_behavior = if fits_on_the_screen {
14546            self.request_autoscroll(Autoscroll::fit(), cx);
14547            SelectSyntaxNodeScrollBehavior::FitSelection
14548        } else if is_selection_reversed {
14549            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14550            SelectSyntaxNodeScrollBehavior::CursorTop
14551        } else {
14552            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14553            SelectSyntaxNodeScrollBehavior::CursorBottom
14554        };
14555
14556        self.select_syntax_node_history.push((
14557            old_selections,
14558            scroll_behavior,
14559            is_selection_reversed,
14560        ));
14561    }
14562
14563    pub fn select_smaller_syntax_node(
14564        &mut self,
14565        _: &SelectSmallerSyntaxNode,
14566        window: &mut Window,
14567        cx: &mut Context<Self>,
14568    ) {
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570
14571        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14572            self.select_syntax_node_history.pop()
14573        {
14574            if let Some(selection) = selections.last_mut() {
14575                selection.reversed = is_selection_reversed;
14576            }
14577
14578            self.select_syntax_node_history.disable_clearing = true;
14579            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14580                s.select(selections.to_vec());
14581            });
14582            self.select_syntax_node_history.disable_clearing = false;
14583
14584            match scroll_behavior {
14585                SelectSyntaxNodeScrollBehavior::CursorTop => {
14586                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14587                }
14588                SelectSyntaxNodeScrollBehavior::FitSelection => {
14589                    self.request_autoscroll(Autoscroll::fit(), cx);
14590                }
14591                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14592                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14593                }
14594            }
14595        }
14596    }
14597
14598    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14599        if !EditorSettings::get_global(cx).gutter.runnables {
14600            self.clear_tasks();
14601            return Task::ready(());
14602        }
14603        let project = self.project.as_ref().map(Entity::downgrade);
14604        let task_sources = self.lsp_task_sources(cx);
14605        let multi_buffer = self.buffer.downgrade();
14606        cx.spawn_in(window, async move |editor, cx| {
14607            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14608            let Some(project) = project.and_then(|p| p.upgrade()) else {
14609                return;
14610            };
14611            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14612                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14613            }) else {
14614                return;
14615            };
14616
14617            let hide_runnables = project
14618                .update(cx, |project, cx| {
14619                    // Do not display any test indicators in non-dev server remote projects.
14620                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14621                })
14622                .unwrap_or(true);
14623            if hide_runnables {
14624                return;
14625            }
14626            let new_rows =
14627                cx.background_spawn({
14628                    let snapshot = display_snapshot.clone();
14629                    async move {
14630                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14631                    }
14632                })
14633                    .await;
14634            let Ok(lsp_tasks) =
14635                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14636            else {
14637                return;
14638            };
14639            let lsp_tasks = lsp_tasks.await;
14640
14641            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14642                lsp_tasks
14643                    .into_iter()
14644                    .flat_map(|(kind, tasks)| {
14645                        tasks.into_iter().filter_map(move |(location, task)| {
14646                            Some((kind.clone(), location?, task))
14647                        })
14648                    })
14649                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14650                        let buffer = location.target.buffer;
14651                        let buffer_snapshot = buffer.read(cx).snapshot();
14652                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14653                            |(excerpt_id, snapshot, _)| {
14654                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14655                                    display_snapshot
14656                                        .buffer_snapshot
14657                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14658                                } else {
14659                                    None
14660                                }
14661                            },
14662                        );
14663                        if let Some(offset) = offset {
14664                            let task_buffer_range =
14665                                location.target.range.to_point(&buffer_snapshot);
14666                            let context_buffer_range =
14667                                task_buffer_range.to_offset(&buffer_snapshot);
14668                            let context_range = BufferOffset(context_buffer_range.start)
14669                                ..BufferOffset(context_buffer_range.end);
14670
14671                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14672                                .or_insert_with(|| RunnableTasks {
14673                                    templates: Vec::new(),
14674                                    offset,
14675                                    column: task_buffer_range.start.column,
14676                                    extra_variables: HashMap::default(),
14677                                    context_range,
14678                                })
14679                                .templates
14680                                .push((kind, task.original_task().clone()));
14681                        }
14682
14683                        acc
14684                    })
14685            }) else {
14686                return;
14687            };
14688
14689            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14690                buffer.language_settings(cx).tasks.prefer_lsp
14691            }) else {
14692                return;
14693            };
14694
14695            let rows = Self::runnable_rows(
14696                project,
14697                display_snapshot,
14698                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14699                new_rows,
14700                cx.clone(),
14701            )
14702            .await;
14703            editor
14704                .update(cx, |editor, _| {
14705                    editor.clear_tasks();
14706                    for (key, mut value) in rows {
14707                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14708                            value.templates.extend(lsp_tasks.templates);
14709                        }
14710
14711                        editor.insert_tasks(key, value);
14712                    }
14713                    for (key, value) in lsp_tasks_by_rows {
14714                        editor.insert_tasks(key, value);
14715                    }
14716                })
14717                .ok();
14718        })
14719    }
14720    fn fetch_runnable_ranges(
14721        snapshot: &DisplaySnapshot,
14722        range: Range<Anchor>,
14723    ) -> Vec<language::RunnableRange> {
14724        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14725    }
14726
14727    fn runnable_rows(
14728        project: Entity<Project>,
14729        snapshot: DisplaySnapshot,
14730        prefer_lsp: bool,
14731        runnable_ranges: Vec<RunnableRange>,
14732        cx: AsyncWindowContext,
14733    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14734        cx.spawn(async move |cx| {
14735            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14736            for mut runnable in runnable_ranges {
14737                let Some(tasks) = cx
14738                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14739                    .ok()
14740                else {
14741                    continue;
14742                };
14743                let mut tasks = tasks.await;
14744
14745                if prefer_lsp {
14746                    tasks.retain(|(task_kind, _)| {
14747                        !matches!(task_kind, TaskSourceKind::Language { .. })
14748                    });
14749                }
14750                if tasks.is_empty() {
14751                    continue;
14752                }
14753
14754                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14755                let Some(row) = snapshot
14756                    .buffer_snapshot
14757                    .buffer_line_for_row(MultiBufferRow(point.row))
14758                    .map(|(_, range)| range.start.row)
14759                else {
14760                    continue;
14761                };
14762
14763                let context_range =
14764                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14765                runnable_rows.push((
14766                    (runnable.buffer_id, row),
14767                    RunnableTasks {
14768                        templates: tasks,
14769                        offset: snapshot
14770                            .buffer_snapshot
14771                            .anchor_before(runnable.run_range.start),
14772                        context_range,
14773                        column: point.column,
14774                        extra_variables: runnable.extra_captures,
14775                    },
14776                ));
14777            }
14778            runnable_rows
14779        })
14780    }
14781
14782    fn templates_with_tags(
14783        project: &Entity<Project>,
14784        runnable: &mut Runnable,
14785        cx: &mut App,
14786    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14787        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14788            let (worktree_id, file) = project
14789                .buffer_for_id(runnable.buffer, cx)
14790                .and_then(|buffer| buffer.read(cx).file())
14791                .map(|file| (file.worktree_id(cx), file.clone()))
14792                .unzip();
14793
14794            (
14795                project.task_store().read(cx).task_inventory().cloned(),
14796                worktree_id,
14797                file,
14798            )
14799        });
14800
14801        let tags = mem::take(&mut runnable.tags);
14802        let language = runnable.language.clone();
14803        cx.spawn(async move |cx| {
14804            let mut templates_with_tags = Vec::new();
14805            if let Some(inventory) = inventory {
14806                for RunnableTag(tag) in tags {
14807                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14808                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14809                    }) else {
14810                        return templates_with_tags;
14811                    };
14812                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14813                        move |(_, template)| {
14814                            template.tags.iter().any(|source_tag| source_tag == &tag)
14815                        },
14816                    ));
14817                }
14818            }
14819            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14820
14821            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14822                // Strongest source wins; if we have worktree tag binding, prefer that to
14823                // global and language bindings;
14824                // if we have a global binding, prefer that to language binding.
14825                let first_mismatch = templates_with_tags
14826                    .iter()
14827                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14828                if let Some(index) = first_mismatch {
14829                    templates_with_tags.truncate(index);
14830                }
14831            }
14832
14833            templates_with_tags
14834        })
14835    }
14836
14837    pub fn move_to_enclosing_bracket(
14838        &mut self,
14839        _: &MoveToEnclosingBracket,
14840        window: &mut Window,
14841        cx: &mut Context<Self>,
14842    ) {
14843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14844        self.change_selections(Default::default(), window, cx, |s| {
14845            s.move_offsets_with(|snapshot, selection| {
14846                let Some(enclosing_bracket_ranges) =
14847                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14848                else {
14849                    return;
14850                };
14851
14852                let mut best_length = usize::MAX;
14853                let mut best_inside = false;
14854                let mut best_in_bracket_range = false;
14855                let mut best_destination = None;
14856                for (open, close) in enclosing_bracket_ranges {
14857                    let close = close.to_inclusive();
14858                    let length = close.end() - open.start;
14859                    let inside = selection.start >= open.end && selection.end <= *close.start();
14860                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14861                        || close.contains(&selection.head());
14862
14863                    // If best is next to a bracket and current isn't, skip
14864                    if !in_bracket_range && best_in_bracket_range {
14865                        continue;
14866                    }
14867
14868                    // Prefer smaller lengths unless best is inside and current isn't
14869                    if length > best_length && (best_inside || !inside) {
14870                        continue;
14871                    }
14872
14873                    best_length = length;
14874                    best_inside = inside;
14875                    best_in_bracket_range = in_bracket_range;
14876                    best_destination = Some(
14877                        if close.contains(&selection.start) && close.contains(&selection.end) {
14878                            if inside { open.end } else { open.start }
14879                        } else if inside {
14880                            *close.start()
14881                        } else {
14882                            *close.end()
14883                        },
14884                    );
14885                }
14886
14887                if let Some(destination) = best_destination {
14888                    selection.collapse_to(destination, SelectionGoal::None);
14889                }
14890            })
14891        });
14892    }
14893
14894    pub fn undo_selection(
14895        &mut self,
14896        _: &UndoSelection,
14897        window: &mut Window,
14898        cx: &mut Context<Self>,
14899    ) {
14900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14901        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14902            self.selection_history.mode = SelectionHistoryMode::Undoing;
14903            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14904                this.end_selection(window, cx);
14905                this.change_selections(
14906                    SelectionEffects::scroll(Autoscroll::newest()),
14907                    window,
14908                    cx,
14909                    |s| s.select_anchors(entry.selections.to_vec()),
14910                );
14911            });
14912            self.selection_history.mode = SelectionHistoryMode::Normal;
14913
14914            self.select_next_state = entry.select_next_state;
14915            self.select_prev_state = entry.select_prev_state;
14916            self.add_selections_state = entry.add_selections_state;
14917        }
14918    }
14919
14920    pub fn redo_selection(
14921        &mut self,
14922        _: &RedoSelection,
14923        window: &mut Window,
14924        cx: &mut Context<Self>,
14925    ) {
14926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14927        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14928            self.selection_history.mode = SelectionHistoryMode::Redoing;
14929            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14930                this.end_selection(window, cx);
14931                this.change_selections(
14932                    SelectionEffects::scroll(Autoscroll::newest()),
14933                    window,
14934                    cx,
14935                    |s| s.select_anchors(entry.selections.to_vec()),
14936                );
14937            });
14938            self.selection_history.mode = SelectionHistoryMode::Normal;
14939
14940            self.select_next_state = entry.select_next_state;
14941            self.select_prev_state = entry.select_prev_state;
14942            self.add_selections_state = entry.add_selections_state;
14943        }
14944    }
14945
14946    pub fn expand_excerpts(
14947        &mut self,
14948        action: &ExpandExcerpts,
14949        _: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) {
14952        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14953    }
14954
14955    pub fn expand_excerpts_down(
14956        &mut self,
14957        action: &ExpandExcerptsDown,
14958        _: &mut Window,
14959        cx: &mut Context<Self>,
14960    ) {
14961        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14962    }
14963
14964    pub fn expand_excerpts_up(
14965        &mut self,
14966        action: &ExpandExcerptsUp,
14967        _: &mut Window,
14968        cx: &mut Context<Self>,
14969    ) {
14970        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14971    }
14972
14973    pub fn expand_excerpts_for_direction(
14974        &mut self,
14975        lines: u32,
14976        direction: ExpandExcerptDirection,
14977
14978        cx: &mut Context<Self>,
14979    ) {
14980        let selections = self.selections.disjoint_anchors();
14981
14982        let lines = if lines == 0 {
14983            EditorSettings::get_global(cx).expand_excerpt_lines
14984        } else {
14985            lines
14986        };
14987
14988        self.buffer.update(cx, |buffer, cx| {
14989            let snapshot = buffer.snapshot(cx);
14990            let mut excerpt_ids = selections
14991                .iter()
14992                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14993                .collect::<Vec<_>>();
14994            excerpt_ids.sort();
14995            excerpt_ids.dedup();
14996            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14997        })
14998    }
14999
15000    pub fn expand_excerpt(
15001        &mut self,
15002        excerpt: ExcerptId,
15003        direction: ExpandExcerptDirection,
15004        window: &mut Window,
15005        cx: &mut Context<Self>,
15006    ) {
15007        let current_scroll_position = self.scroll_position(cx);
15008        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15009        let mut should_scroll_up = false;
15010
15011        if direction == ExpandExcerptDirection::Down {
15012            let multi_buffer = self.buffer.read(cx);
15013            let snapshot = multi_buffer.snapshot(cx);
15014            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15015                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15016                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15017                        let buffer_snapshot = buffer.read(cx).snapshot();
15018                        let excerpt_end_row =
15019                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15020                        let last_row = buffer_snapshot.max_point().row;
15021                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15022                        should_scroll_up = lines_below >= lines_to_expand;
15023                    }
15024                }
15025            }
15026        }
15027
15028        self.buffer.update(cx, |buffer, cx| {
15029            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15030        });
15031
15032        if should_scroll_up {
15033            let new_scroll_position =
15034                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15035            self.set_scroll_position(new_scroll_position, window, cx);
15036        }
15037    }
15038
15039    pub fn go_to_singleton_buffer_point(
15040        &mut self,
15041        point: Point,
15042        window: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) {
15045        self.go_to_singleton_buffer_range(point..point, window, cx);
15046    }
15047
15048    pub fn go_to_singleton_buffer_range(
15049        &mut self,
15050        range: Range<Point>,
15051        window: &mut Window,
15052        cx: &mut Context<Self>,
15053    ) {
15054        let multibuffer = self.buffer().read(cx);
15055        let Some(buffer) = multibuffer.as_singleton() else {
15056            return;
15057        };
15058        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15059            return;
15060        };
15061        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15062            return;
15063        };
15064        self.change_selections(
15065            SelectionEffects::default().nav_history(true),
15066            window,
15067            cx,
15068            |s| s.select_anchor_ranges([start..end]),
15069        );
15070    }
15071
15072    pub fn go_to_diagnostic(
15073        &mut self,
15074        action: &GoToDiagnostic,
15075        window: &mut Window,
15076        cx: &mut Context<Self>,
15077    ) {
15078        if !self.diagnostics_enabled() {
15079            return;
15080        }
15081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15082        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15083    }
15084
15085    pub fn go_to_prev_diagnostic(
15086        &mut self,
15087        action: &GoToPreviousDiagnostic,
15088        window: &mut Window,
15089        cx: &mut Context<Self>,
15090    ) {
15091        if !self.diagnostics_enabled() {
15092            return;
15093        }
15094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15095        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15096    }
15097
15098    pub fn go_to_diagnostic_impl(
15099        &mut self,
15100        direction: Direction,
15101        severity: GoToDiagnosticSeverityFilter,
15102        window: &mut Window,
15103        cx: &mut Context<Self>,
15104    ) {
15105        let buffer = self.buffer.read(cx).snapshot(cx);
15106        let selection = self.selections.newest::<usize>(cx);
15107
15108        let mut active_group_id = None;
15109        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15110            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15111                active_group_id = Some(active_group.group_id);
15112            }
15113        }
15114
15115        fn filtered(
15116            snapshot: EditorSnapshot,
15117            severity: GoToDiagnosticSeverityFilter,
15118            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15119        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15120            diagnostics
15121                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15122                .filter(|entry| entry.range.start != entry.range.end)
15123                .filter(|entry| !entry.diagnostic.is_unnecessary)
15124                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15125        }
15126
15127        let snapshot = self.snapshot(window, cx);
15128        let before = filtered(
15129            snapshot.clone(),
15130            severity,
15131            buffer
15132                .diagnostics_in_range(0..selection.start)
15133                .filter(|entry| entry.range.start <= selection.start),
15134        );
15135        let after = filtered(
15136            snapshot,
15137            severity,
15138            buffer
15139                .diagnostics_in_range(selection.start..buffer.len())
15140                .filter(|entry| entry.range.start >= selection.start),
15141        );
15142
15143        let mut found: Option<DiagnosticEntry<usize>> = None;
15144        if direction == Direction::Prev {
15145            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15146            {
15147                for diagnostic in prev_diagnostics.into_iter().rev() {
15148                    if diagnostic.range.start != selection.start
15149                        || active_group_id
15150                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15151                    {
15152                        found = Some(diagnostic);
15153                        break 'outer;
15154                    }
15155                }
15156            }
15157        } else {
15158            for diagnostic in after.chain(before) {
15159                if diagnostic.range.start != selection.start
15160                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15161                {
15162                    found = Some(diagnostic);
15163                    break;
15164                }
15165            }
15166        }
15167        let Some(next_diagnostic) = found else {
15168            return;
15169        };
15170
15171        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15172            return;
15173        };
15174        self.change_selections(Default::default(), window, cx, |s| {
15175            s.select_ranges(vec![
15176                next_diagnostic.range.start..next_diagnostic.range.start,
15177            ])
15178        });
15179        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15180        self.refresh_inline_completion(false, true, window, cx);
15181    }
15182
15183    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15185        let snapshot = self.snapshot(window, cx);
15186        let selection = self.selections.newest::<Point>(cx);
15187        self.go_to_hunk_before_or_after_position(
15188            &snapshot,
15189            selection.head(),
15190            Direction::Next,
15191            window,
15192            cx,
15193        );
15194    }
15195
15196    pub fn go_to_hunk_before_or_after_position(
15197        &mut self,
15198        snapshot: &EditorSnapshot,
15199        position: Point,
15200        direction: Direction,
15201        window: &mut Window,
15202        cx: &mut Context<Editor>,
15203    ) {
15204        let row = if direction == Direction::Next {
15205            self.hunk_after_position(snapshot, position)
15206                .map(|hunk| hunk.row_range.start)
15207        } else {
15208            self.hunk_before_position(snapshot, position)
15209        };
15210
15211        if let Some(row) = row {
15212            let destination = Point::new(row.0, 0);
15213            let autoscroll = Autoscroll::center();
15214
15215            self.unfold_ranges(&[destination..destination], false, false, cx);
15216            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15217                s.select_ranges([destination..destination]);
15218            });
15219        }
15220    }
15221
15222    fn hunk_after_position(
15223        &mut self,
15224        snapshot: &EditorSnapshot,
15225        position: Point,
15226    ) -> Option<MultiBufferDiffHunk> {
15227        snapshot
15228            .buffer_snapshot
15229            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15230            .find(|hunk| hunk.row_range.start.0 > position.row)
15231            .or_else(|| {
15232                snapshot
15233                    .buffer_snapshot
15234                    .diff_hunks_in_range(Point::zero()..position)
15235                    .find(|hunk| hunk.row_range.end.0 < position.row)
15236            })
15237    }
15238
15239    fn go_to_prev_hunk(
15240        &mut self,
15241        _: &GoToPreviousHunk,
15242        window: &mut Window,
15243        cx: &mut Context<Self>,
15244    ) {
15245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15246        let snapshot = self.snapshot(window, cx);
15247        let selection = self.selections.newest::<Point>(cx);
15248        self.go_to_hunk_before_or_after_position(
15249            &snapshot,
15250            selection.head(),
15251            Direction::Prev,
15252            window,
15253            cx,
15254        );
15255    }
15256
15257    fn hunk_before_position(
15258        &mut self,
15259        snapshot: &EditorSnapshot,
15260        position: Point,
15261    ) -> Option<MultiBufferRow> {
15262        snapshot
15263            .buffer_snapshot
15264            .diff_hunk_before(position)
15265            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15266    }
15267
15268    fn go_to_next_change(
15269        &mut self,
15270        _: &GoToNextChange,
15271        window: &mut Window,
15272        cx: &mut Context<Self>,
15273    ) {
15274        if let Some(selections) = self
15275            .change_list
15276            .next_change(1, Direction::Next)
15277            .map(|s| s.to_vec())
15278        {
15279            self.change_selections(Default::default(), window, cx, |s| {
15280                let map = s.display_map();
15281                s.select_display_ranges(selections.iter().map(|a| {
15282                    let point = a.to_display_point(&map);
15283                    point..point
15284                }))
15285            })
15286        }
15287    }
15288
15289    fn go_to_previous_change(
15290        &mut self,
15291        _: &GoToPreviousChange,
15292        window: &mut Window,
15293        cx: &mut Context<Self>,
15294    ) {
15295        if let Some(selections) = self
15296            .change_list
15297            .next_change(1, Direction::Prev)
15298            .map(|s| s.to_vec())
15299        {
15300            self.change_selections(Default::default(), window, cx, |s| {
15301                let map = s.display_map();
15302                s.select_display_ranges(selections.iter().map(|a| {
15303                    let point = a.to_display_point(&map);
15304                    point..point
15305                }))
15306            })
15307        }
15308    }
15309
15310    fn go_to_line<T: 'static>(
15311        &mut self,
15312        position: Anchor,
15313        highlight_color: Option<Hsla>,
15314        window: &mut Window,
15315        cx: &mut Context<Self>,
15316    ) {
15317        let snapshot = self.snapshot(window, cx).display_snapshot;
15318        let position = position.to_point(&snapshot.buffer_snapshot);
15319        let start = snapshot
15320            .buffer_snapshot
15321            .clip_point(Point::new(position.row, 0), Bias::Left);
15322        let end = start + Point::new(1, 0);
15323        let start = snapshot.buffer_snapshot.anchor_before(start);
15324        let end = snapshot.buffer_snapshot.anchor_before(end);
15325
15326        self.highlight_rows::<T>(
15327            start..end,
15328            highlight_color
15329                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15330            Default::default(),
15331            cx,
15332        );
15333
15334        if self.buffer.read(cx).is_singleton() {
15335            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15336        }
15337    }
15338
15339    pub fn go_to_definition(
15340        &mut self,
15341        _: &GoToDefinition,
15342        window: &mut Window,
15343        cx: &mut Context<Self>,
15344    ) -> Task<Result<Navigated>> {
15345        let definition =
15346            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15347        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15348        cx.spawn_in(window, async move |editor, cx| {
15349            if definition.await? == Navigated::Yes {
15350                return Ok(Navigated::Yes);
15351            }
15352            match fallback_strategy {
15353                GoToDefinitionFallback::None => Ok(Navigated::No),
15354                GoToDefinitionFallback::FindAllReferences => {
15355                    match editor.update_in(cx, |editor, window, cx| {
15356                        editor.find_all_references(&FindAllReferences, window, cx)
15357                    })? {
15358                        Some(references) => references.await,
15359                        None => Ok(Navigated::No),
15360                    }
15361                }
15362            }
15363        })
15364    }
15365
15366    pub fn go_to_declaration(
15367        &mut self,
15368        _: &GoToDeclaration,
15369        window: &mut Window,
15370        cx: &mut Context<Self>,
15371    ) -> Task<Result<Navigated>> {
15372        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15373    }
15374
15375    pub fn go_to_declaration_split(
15376        &mut self,
15377        _: &GoToDeclaration,
15378        window: &mut Window,
15379        cx: &mut Context<Self>,
15380    ) -> Task<Result<Navigated>> {
15381        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15382    }
15383
15384    pub fn go_to_implementation(
15385        &mut self,
15386        _: &GoToImplementation,
15387        window: &mut Window,
15388        cx: &mut Context<Self>,
15389    ) -> Task<Result<Navigated>> {
15390        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15391    }
15392
15393    pub fn go_to_implementation_split(
15394        &mut self,
15395        _: &GoToImplementationSplit,
15396        window: &mut Window,
15397        cx: &mut Context<Self>,
15398    ) -> Task<Result<Navigated>> {
15399        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15400    }
15401
15402    pub fn go_to_type_definition(
15403        &mut self,
15404        _: &GoToTypeDefinition,
15405        window: &mut Window,
15406        cx: &mut Context<Self>,
15407    ) -> Task<Result<Navigated>> {
15408        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15409    }
15410
15411    pub fn go_to_definition_split(
15412        &mut self,
15413        _: &GoToDefinitionSplit,
15414        window: &mut Window,
15415        cx: &mut Context<Self>,
15416    ) -> Task<Result<Navigated>> {
15417        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15418    }
15419
15420    pub fn go_to_type_definition_split(
15421        &mut self,
15422        _: &GoToTypeDefinitionSplit,
15423        window: &mut Window,
15424        cx: &mut Context<Self>,
15425    ) -> Task<Result<Navigated>> {
15426        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15427    }
15428
15429    fn go_to_definition_of_kind(
15430        &mut self,
15431        kind: GotoDefinitionKind,
15432        split: bool,
15433        window: &mut Window,
15434        cx: &mut Context<Self>,
15435    ) -> Task<Result<Navigated>> {
15436        let Some(provider) = self.semantics_provider.clone() else {
15437            return Task::ready(Ok(Navigated::No));
15438        };
15439        let head = self.selections.newest::<usize>(cx).head();
15440        let buffer = self.buffer.read(cx);
15441        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15442            text_anchor
15443        } else {
15444            return Task::ready(Ok(Navigated::No));
15445        };
15446
15447        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15448            return Task::ready(Ok(Navigated::No));
15449        };
15450
15451        cx.spawn_in(window, async move |editor, cx| {
15452            let definitions = definitions.await?;
15453            let navigated = editor
15454                .update_in(cx, |editor, window, cx| {
15455                    editor.navigate_to_hover_links(
15456                        Some(kind),
15457                        definitions
15458                            .into_iter()
15459                            .filter(|location| {
15460                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15461                            })
15462                            .map(HoverLink::Text)
15463                            .collect::<Vec<_>>(),
15464                        split,
15465                        window,
15466                        cx,
15467                    )
15468                })?
15469                .await?;
15470            anyhow::Ok(navigated)
15471        })
15472    }
15473
15474    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15475        let selection = self.selections.newest_anchor();
15476        let head = selection.head();
15477        let tail = selection.tail();
15478
15479        let Some((buffer, start_position)) =
15480            self.buffer.read(cx).text_anchor_for_position(head, cx)
15481        else {
15482            return;
15483        };
15484
15485        let end_position = if head != tail {
15486            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15487                return;
15488            };
15489            Some(pos)
15490        } else {
15491            None
15492        };
15493
15494        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15495            let url = if let Some(end_pos) = end_position {
15496                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15497            } else {
15498                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15499            };
15500
15501            if let Some(url) = url {
15502                editor.update(cx, |_, cx| {
15503                    cx.open_url(&url);
15504                })
15505            } else {
15506                Ok(())
15507            }
15508        });
15509
15510        url_finder.detach();
15511    }
15512
15513    pub fn open_selected_filename(
15514        &mut self,
15515        _: &OpenSelectedFilename,
15516        window: &mut Window,
15517        cx: &mut Context<Self>,
15518    ) {
15519        let Some(workspace) = self.workspace() else {
15520            return;
15521        };
15522
15523        let position = self.selections.newest_anchor().head();
15524
15525        let Some((buffer, buffer_position)) =
15526            self.buffer.read(cx).text_anchor_for_position(position, cx)
15527        else {
15528            return;
15529        };
15530
15531        let project = self.project.clone();
15532
15533        cx.spawn_in(window, async move |_, cx| {
15534            let result = find_file(&buffer, project, buffer_position, cx).await;
15535
15536            if let Some((_, path)) = result {
15537                workspace
15538                    .update_in(cx, |workspace, window, cx| {
15539                        workspace.open_resolved_path(path, window, cx)
15540                    })?
15541                    .await?;
15542            }
15543            anyhow::Ok(())
15544        })
15545        .detach();
15546    }
15547
15548    pub(crate) fn navigate_to_hover_links(
15549        &mut self,
15550        kind: Option<GotoDefinitionKind>,
15551        mut definitions: Vec<HoverLink>,
15552        split: bool,
15553        window: &mut Window,
15554        cx: &mut Context<Editor>,
15555    ) -> Task<Result<Navigated>> {
15556        // If there is one definition, just open it directly
15557        if definitions.len() == 1 {
15558            let definition = definitions.pop().unwrap();
15559
15560            enum TargetTaskResult {
15561                Location(Option<Location>),
15562                AlreadyNavigated,
15563            }
15564
15565            let target_task = match definition {
15566                HoverLink::Text(link) => {
15567                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15568                }
15569                HoverLink::InlayHint(lsp_location, server_id) => {
15570                    let computation =
15571                        self.compute_target_location(lsp_location, server_id, window, cx);
15572                    cx.background_spawn(async move {
15573                        let location = computation.await?;
15574                        Ok(TargetTaskResult::Location(location))
15575                    })
15576                }
15577                HoverLink::Url(url) => {
15578                    cx.open_url(&url);
15579                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15580                }
15581                HoverLink::File(path) => {
15582                    if let Some(workspace) = self.workspace() {
15583                        cx.spawn_in(window, async move |_, cx| {
15584                            workspace
15585                                .update_in(cx, |workspace, window, cx| {
15586                                    workspace.open_resolved_path(path, window, cx)
15587                                })?
15588                                .await
15589                                .map(|_| TargetTaskResult::AlreadyNavigated)
15590                        })
15591                    } else {
15592                        Task::ready(Ok(TargetTaskResult::Location(None)))
15593                    }
15594                }
15595            };
15596            cx.spawn_in(window, async move |editor, cx| {
15597                let target = match target_task.await.context("target resolution task")? {
15598                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15599                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15600                    TargetTaskResult::Location(Some(target)) => target,
15601                };
15602
15603                editor.update_in(cx, |editor, window, cx| {
15604                    let Some(workspace) = editor.workspace() else {
15605                        return Navigated::No;
15606                    };
15607                    let pane = workspace.read(cx).active_pane().clone();
15608
15609                    let range = target.range.to_point(target.buffer.read(cx));
15610                    let range = editor.range_for_match(&range);
15611                    let range = collapse_multiline_range(range);
15612
15613                    if !split
15614                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15615                    {
15616                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15617                    } else {
15618                        window.defer(cx, move |window, cx| {
15619                            let target_editor: Entity<Self> =
15620                                workspace.update(cx, |workspace, cx| {
15621                                    let pane = if split {
15622                                        workspace.adjacent_pane(window, cx)
15623                                    } else {
15624                                        workspace.active_pane().clone()
15625                                    };
15626
15627                                    workspace.open_project_item(
15628                                        pane,
15629                                        target.buffer.clone(),
15630                                        true,
15631                                        true,
15632                                        window,
15633                                        cx,
15634                                    )
15635                                });
15636                            target_editor.update(cx, |target_editor, cx| {
15637                                // When selecting a definition in a different buffer, disable the nav history
15638                                // to avoid creating a history entry at the previous cursor location.
15639                                pane.update(cx, |pane, _| pane.disable_history());
15640                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15641                                pane.update(cx, |pane, _| pane.enable_history());
15642                            });
15643                        });
15644                    }
15645                    Navigated::Yes
15646                })
15647            })
15648        } else if !definitions.is_empty() {
15649            cx.spawn_in(window, async move |editor, cx| {
15650                let (title, location_tasks, workspace) = editor
15651                    .update_in(cx, |editor, window, cx| {
15652                        let tab_kind = match kind {
15653                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15654                            _ => "Definitions",
15655                        };
15656                        let title = definitions
15657                            .iter()
15658                            .find_map(|definition| match definition {
15659                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15660                                    let buffer = origin.buffer.read(cx);
15661                                    format!(
15662                                        "{} for {}",
15663                                        tab_kind,
15664                                        buffer
15665                                            .text_for_range(origin.range.clone())
15666                                            .collect::<String>()
15667                                    )
15668                                }),
15669                                HoverLink::InlayHint(_, _) => None,
15670                                HoverLink::Url(_) => None,
15671                                HoverLink::File(_) => None,
15672                            })
15673                            .unwrap_or(tab_kind.to_string());
15674                        let location_tasks = definitions
15675                            .into_iter()
15676                            .map(|definition| match definition {
15677                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15678                                HoverLink::InlayHint(lsp_location, server_id) => editor
15679                                    .compute_target_location(lsp_location, server_id, window, cx),
15680                                HoverLink::Url(_) => Task::ready(Ok(None)),
15681                                HoverLink::File(_) => Task::ready(Ok(None)),
15682                            })
15683                            .collect::<Vec<_>>();
15684                        (title, location_tasks, editor.workspace().clone())
15685                    })
15686                    .context("location tasks preparation")?;
15687
15688                let locations: Vec<Location> = future::join_all(location_tasks)
15689                    .await
15690                    .into_iter()
15691                    .filter_map(|location| location.transpose())
15692                    .collect::<Result<_>>()
15693                    .context("location tasks")?;
15694
15695                if locations.is_empty() {
15696                    return Ok(Navigated::No);
15697                }
15698
15699                let Some(workspace) = workspace else {
15700                    return Ok(Navigated::No);
15701                };
15702
15703                let opened = workspace
15704                    .update_in(cx, |workspace, window, cx| {
15705                        Self::open_locations_in_multibuffer(
15706                            workspace,
15707                            locations,
15708                            title,
15709                            split,
15710                            MultibufferSelectionMode::First,
15711                            window,
15712                            cx,
15713                        )
15714                    })
15715                    .ok();
15716
15717                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15718            })
15719        } else {
15720            Task::ready(Ok(Navigated::No))
15721        }
15722    }
15723
15724    fn compute_target_location(
15725        &self,
15726        lsp_location: lsp::Location,
15727        server_id: LanguageServerId,
15728        window: &mut Window,
15729        cx: &mut Context<Self>,
15730    ) -> Task<anyhow::Result<Option<Location>>> {
15731        let Some(project) = self.project.clone() else {
15732            return Task::ready(Ok(None));
15733        };
15734
15735        cx.spawn_in(window, async move |editor, cx| {
15736            let location_task = editor.update(cx, |_, cx| {
15737                project.update(cx, |project, cx| {
15738                    let language_server_name = project
15739                        .language_server_statuses(cx)
15740                        .find(|(id, _)| server_id == *id)
15741                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15742                    language_server_name.map(|language_server_name| {
15743                        project.open_local_buffer_via_lsp(
15744                            lsp_location.uri.clone(),
15745                            server_id,
15746                            language_server_name,
15747                            cx,
15748                        )
15749                    })
15750                })
15751            })?;
15752            let location = match location_task {
15753                Some(task) => Some({
15754                    let target_buffer_handle = task.await.context("open local buffer")?;
15755                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15756                        let target_start = target_buffer
15757                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15758                        let target_end = target_buffer
15759                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15760                        target_buffer.anchor_after(target_start)
15761                            ..target_buffer.anchor_before(target_end)
15762                    })?;
15763                    Location {
15764                        buffer: target_buffer_handle,
15765                        range,
15766                    }
15767                }),
15768                None => None,
15769            };
15770            Ok(location)
15771        })
15772    }
15773
15774    pub fn find_all_references(
15775        &mut self,
15776        _: &FindAllReferences,
15777        window: &mut Window,
15778        cx: &mut Context<Self>,
15779    ) -> Option<Task<Result<Navigated>>> {
15780        let selection = self.selections.newest::<usize>(cx);
15781        let multi_buffer = self.buffer.read(cx);
15782        let head = selection.head();
15783
15784        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15785        let head_anchor = multi_buffer_snapshot.anchor_at(
15786            head,
15787            if head < selection.tail() {
15788                Bias::Right
15789            } else {
15790                Bias::Left
15791            },
15792        );
15793
15794        match self
15795            .find_all_references_task_sources
15796            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15797        {
15798            Ok(_) => {
15799                log::info!(
15800                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15801                );
15802                return None;
15803            }
15804            Err(i) => {
15805                self.find_all_references_task_sources.insert(i, head_anchor);
15806            }
15807        }
15808
15809        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15810        let workspace = self.workspace()?;
15811        let project = workspace.read(cx).project().clone();
15812        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15813        Some(cx.spawn_in(window, async move |editor, cx| {
15814            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15815                if let Ok(i) = editor
15816                    .find_all_references_task_sources
15817                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15818                {
15819                    editor.find_all_references_task_sources.remove(i);
15820                }
15821            });
15822
15823            let locations = references.await?;
15824            if locations.is_empty() {
15825                return anyhow::Ok(Navigated::No);
15826            }
15827
15828            workspace.update_in(cx, |workspace, window, cx| {
15829                let title = locations
15830                    .first()
15831                    .as_ref()
15832                    .map(|location| {
15833                        let buffer = location.buffer.read(cx);
15834                        format!(
15835                            "References to `{}`",
15836                            buffer
15837                                .text_for_range(location.range.clone())
15838                                .collect::<String>()
15839                        )
15840                    })
15841                    .unwrap();
15842                Self::open_locations_in_multibuffer(
15843                    workspace,
15844                    locations,
15845                    title,
15846                    false,
15847                    MultibufferSelectionMode::First,
15848                    window,
15849                    cx,
15850                );
15851                Navigated::Yes
15852            })
15853        }))
15854    }
15855
15856    /// Opens a multibuffer with the given project locations in it
15857    pub fn open_locations_in_multibuffer(
15858        workspace: &mut Workspace,
15859        mut locations: Vec<Location>,
15860        title: String,
15861        split: bool,
15862        multibuffer_selection_mode: MultibufferSelectionMode,
15863        window: &mut Window,
15864        cx: &mut Context<Workspace>,
15865    ) {
15866        if locations.is_empty() {
15867            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15868            return;
15869        }
15870
15871        // If there are multiple definitions, open them in a multibuffer
15872        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15873        let mut locations = locations.into_iter().peekable();
15874        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15875        let capability = workspace.project().read(cx).capability();
15876
15877        let excerpt_buffer = cx.new(|cx| {
15878            let mut multibuffer = MultiBuffer::new(capability);
15879            while let Some(location) = locations.next() {
15880                let buffer = location.buffer.read(cx);
15881                let mut ranges_for_buffer = Vec::new();
15882                let range = location.range.to_point(buffer);
15883                ranges_for_buffer.push(range.clone());
15884
15885                while let Some(next_location) = locations.peek() {
15886                    if next_location.buffer == location.buffer {
15887                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15888                        locations.next();
15889                    } else {
15890                        break;
15891                    }
15892                }
15893
15894                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15895                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15896                    PathKey::for_buffer(&location.buffer, cx),
15897                    location.buffer.clone(),
15898                    ranges_for_buffer,
15899                    DEFAULT_MULTIBUFFER_CONTEXT,
15900                    cx,
15901                );
15902                ranges.extend(new_ranges)
15903            }
15904
15905            multibuffer.with_title(title)
15906        });
15907
15908        let editor = cx.new(|cx| {
15909            Editor::for_multibuffer(
15910                excerpt_buffer,
15911                Some(workspace.project().clone()),
15912                window,
15913                cx,
15914            )
15915        });
15916        editor.update(cx, |editor, cx| {
15917            match multibuffer_selection_mode {
15918                MultibufferSelectionMode::First => {
15919                    if let Some(first_range) = ranges.first() {
15920                        editor.change_selections(
15921                            SelectionEffects::no_scroll(),
15922                            window,
15923                            cx,
15924                            |selections| {
15925                                selections.clear_disjoint();
15926                                selections
15927                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15928                            },
15929                        );
15930                    }
15931                    editor.highlight_background::<Self>(
15932                        &ranges,
15933                        |theme| theme.colors().editor_highlighted_line_background,
15934                        cx,
15935                    );
15936                }
15937                MultibufferSelectionMode::All => {
15938                    editor.change_selections(
15939                        SelectionEffects::no_scroll(),
15940                        window,
15941                        cx,
15942                        |selections| {
15943                            selections.clear_disjoint();
15944                            selections.select_anchor_ranges(ranges);
15945                        },
15946                    );
15947                }
15948            }
15949            editor.register_buffers_with_language_servers(cx);
15950        });
15951
15952        let item = Box::new(editor);
15953        let item_id = item.item_id();
15954
15955        if split {
15956            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15957        } else {
15958            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15959                let (preview_item_id, preview_item_idx) =
15960                    workspace.active_pane().read_with(cx, |pane, _| {
15961                        (pane.preview_item_id(), pane.preview_item_idx())
15962                    });
15963
15964                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15965
15966                if let Some(preview_item_id) = preview_item_id {
15967                    workspace.active_pane().update(cx, |pane, cx| {
15968                        pane.remove_item(preview_item_id, false, false, window, cx);
15969                    });
15970                }
15971            } else {
15972                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15973            }
15974        }
15975        workspace.active_pane().update(cx, |pane, cx| {
15976            pane.set_preview_item_id(Some(item_id), cx);
15977        });
15978    }
15979
15980    pub fn rename(
15981        &mut self,
15982        _: &Rename,
15983        window: &mut Window,
15984        cx: &mut Context<Self>,
15985    ) -> Option<Task<Result<()>>> {
15986        use language::ToOffset as _;
15987
15988        let provider = self.semantics_provider.clone()?;
15989        let selection = self.selections.newest_anchor().clone();
15990        let (cursor_buffer, cursor_buffer_position) = self
15991            .buffer
15992            .read(cx)
15993            .text_anchor_for_position(selection.head(), cx)?;
15994        let (tail_buffer, cursor_buffer_position_end) = self
15995            .buffer
15996            .read(cx)
15997            .text_anchor_for_position(selection.tail(), cx)?;
15998        if tail_buffer != cursor_buffer {
15999            return None;
16000        }
16001
16002        let snapshot = cursor_buffer.read(cx).snapshot();
16003        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16004        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16005        let prepare_rename = provider
16006            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16007            .unwrap_or_else(|| Task::ready(Ok(None)));
16008        drop(snapshot);
16009
16010        Some(cx.spawn_in(window, async move |this, cx| {
16011            let rename_range = if let Some(range) = prepare_rename.await? {
16012                Some(range)
16013            } else {
16014                this.update(cx, |this, cx| {
16015                    let buffer = this.buffer.read(cx).snapshot(cx);
16016                    let mut buffer_highlights = this
16017                        .document_highlights_for_position(selection.head(), &buffer)
16018                        .filter(|highlight| {
16019                            highlight.start.excerpt_id == selection.head().excerpt_id
16020                                && highlight.end.excerpt_id == selection.head().excerpt_id
16021                        });
16022                    buffer_highlights
16023                        .next()
16024                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16025                })?
16026            };
16027            if let Some(rename_range) = rename_range {
16028                this.update_in(cx, |this, window, cx| {
16029                    let snapshot = cursor_buffer.read(cx).snapshot();
16030                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16031                    let cursor_offset_in_rename_range =
16032                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16033                    let cursor_offset_in_rename_range_end =
16034                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16035
16036                    this.take_rename(false, window, cx);
16037                    let buffer = this.buffer.read(cx).read(cx);
16038                    let cursor_offset = selection.head().to_offset(&buffer);
16039                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16040                    let rename_end = rename_start + rename_buffer_range.len();
16041                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16042                    let mut old_highlight_id = None;
16043                    let old_name: Arc<str> = buffer
16044                        .chunks(rename_start..rename_end, true)
16045                        .map(|chunk| {
16046                            if old_highlight_id.is_none() {
16047                                old_highlight_id = chunk.syntax_highlight_id;
16048                            }
16049                            chunk.text
16050                        })
16051                        .collect::<String>()
16052                        .into();
16053
16054                    drop(buffer);
16055
16056                    // Position the selection in the rename editor so that it matches the current selection.
16057                    this.show_local_selections = false;
16058                    let rename_editor = cx.new(|cx| {
16059                        let mut editor = Editor::single_line(window, cx);
16060                        editor.buffer.update(cx, |buffer, cx| {
16061                            buffer.edit([(0..0, old_name.clone())], None, cx)
16062                        });
16063                        let rename_selection_range = match cursor_offset_in_rename_range
16064                            .cmp(&cursor_offset_in_rename_range_end)
16065                        {
16066                            Ordering::Equal => {
16067                                editor.select_all(&SelectAll, window, cx);
16068                                return editor;
16069                            }
16070                            Ordering::Less => {
16071                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16072                            }
16073                            Ordering::Greater => {
16074                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16075                            }
16076                        };
16077                        if rename_selection_range.end > old_name.len() {
16078                            editor.select_all(&SelectAll, window, cx);
16079                        } else {
16080                            editor.change_selections(Default::default(), window, cx, |s| {
16081                                s.select_ranges([rename_selection_range]);
16082                            });
16083                        }
16084                        editor
16085                    });
16086                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16087                        if e == &EditorEvent::Focused {
16088                            cx.emit(EditorEvent::FocusedIn)
16089                        }
16090                    })
16091                    .detach();
16092
16093                    let write_highlights =
16094                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16095                    let read_highlights =
16096                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16097                    let ranges = write_highlights
16098                        .iter()
16099                        .flat_map(|(_, ranges)| ranges.iter())
16100                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16101                        .cloned()
16102                        .collect();
16103
16104                    this.highlight_text::<Rename>(
16105                        ranges,
16106                        HighlightStyle {
16107                            fade_out: Some(0.6),
16108                            ..Default::default()
16109                        },
16110                        cx,
16111                    );
16112                    let rename_focus_handle = rename_editor.focus_handle(cx);
16113                    window.focus(&rename_focus_handle);
16114                    let block_id = this.insert_blocks(
16115                        [BlockProperties {
16116                            style: BlockStyle::Flex,
16117                            placement: BlockPlacement::Below(range.start),
16118                            height: Some(1),
16119                            render: Arc::new({
16120                                let rename_editor = rename_editor.clone();
16121                                move |cx: &mut BlockContext| {
16122                                    let mut text_style = cx.editor_style.text.clone();
16123                                    if let Some(highlight_style) = old_highlight_id
16124                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16125                                    {
16126                                        text_style = text_style.highlight(highlight_style);
16127                                    }
16128                                    div()
16129                                        .block_mouse_except_scroll()
16130                                        .pl(cx.anchor_x)
16131                                        .child(EditorElement::new(
16132                                            &rename_editor,
16133                                            EditorStyle {
16134                                                background: cx.theme().system().transparent,
16135                                                local_player: cx.editor_style.local_player,
16136                                                text: text_style,
16137                                                scrollbar_width: cx.editor_style.scrollbar_width,
16138                                                syntax: cx.editor_style.syntax.clone(),
16139                                                status: cx.editor_style.status.clone(),
16140                                                inlay_hints_style: HighlightStyle {
16141                                                    font_weight: Some(FontWeight::BOLD),
16142                                                    ..make_inlay_hints_style(cx.app)
16143                                                },
16144                                                inline_completion_styles: make_suggestion_styles(
16145                                                    cx.app,
16146                                                ),
16147                                                ..EditorStyle::default()
16148                                            },
16149                                        ))
16150                                        .into_any_element()
16151                                }
16152                            }),
16153                            priority: 0,
16154                        }],
16155                        Some(Autoscroll::fit()),
16156                        cx,
16157                    )[0];
16158                    this.pending_rename = Some(RenameState {
16159                        range,
16160                        old_name,
16161                        editor: rename_editor,
16162                        block_id,
16163                    });
16164                })?;
16165            }
16166
16167            Ok(())
16168        }))
16169    }
16170
16171    pub fn confirm_rename(
16172        &mut self,
16173        _: &ConfirmRename,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) -> Option<Task<Result<()>>> {
16177        let rename = self.take_rename(false, window, cx)?;
16178        let workspace = self.workspace()?.downgrade();
16179        let (buffer, start) = self
16180            .buffer
16181            .read(cx)
16182            .text_anchor_for_position(rename.range.start, cx)?;
16183        let (end_buffer, _) = self
16184            .buffer
16185            .read(cx)
16186            .text_anchor_for_position(rename.range.end, cx)?;
16187        if buffer != end_buffer {
16188            return None;
16189        }
16190
16191        let old_name = rename.old_name;
16192        let new_name = rename.editor.read(cx).text(cx);
16193
16194        let rename = self.semantics_provider.as_ref()?.perform_rename(
16195            &buffer,
16196            start,
16197            new_name.clone(),
16198            cx,
16199        )?;
16200
16201        Some(cx.spawn_in(window, async move |editor, cx| {
16202            let project_transaction = rename.await?;
16203            Self::open_project_transaction(
16204                &editor,
16205                workspace,
16206                project_transaction,
16207                format!("Rename: {}{}", old_name, new_name),
16208                cx,
16209            )
16210            .await?;
16211
16212            editor.update(cx, |editor, cx| {
16213                editor.refresh_document_highlights(cx);
16214            })?;
16215            Ok(())
16216        }))
16217    }
16218
16219    fn take_rename(
16220        &mut self,
16221        moving_cursor: bool,
16222        window: &mut Window,
16223        cx: &mut Context<Self>,
16224    ) -> Option<RenameState> {
16225        let rename = self.pending_rename.take()?;
16226        if rename.editor.focus_handle(cx).is_focused(window) {
16227            window.focus(&self.focus_handle);
16228        }
16229
16230        self.remove_blocks(
16231            [rename.block_id].into_iter().collect(),
16232            Some(Autoscroll::fit()),
16233            cx,
16234        );
16235        self.clear_highlights::<Rename>(cx);
16236        self.show_local_selections = true;
16237
16238        if moving_cursor {
16239            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16240                editor.selections.newest::<usize>(cx).head()
16241            });
16242
16243            // Update the selection to match the position of the selection inside
16244            // the rename editor.
16245            let snapshot = self.buffer.read(cx).read(cx);
16246            let rename_range = rename.range.to_offset(&snapshot);
16247            let cursor_in_editor = snapshot
16248                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16249                .min(rename_range.end);
16250            drop(snapshot);
16251
16252            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16253                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16254            });
16255        } else {
16256            self.refresh_document_highlights(cx);
16257        }
16258
16259        Some(rename)
16260    }
16261
16262    pub fn pending_rename(&self) -> Option<&RenameState> {
16263        self.pending_rename.as_ref()
16264    }
16265
16266    fn format(
16267        &mut self,
16268        _: &Format,
16269        window: &mut Window,
16270        cx: &mut Context<Self>,
16271    ) -> Option<Task<Result<()>>> {
16272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16273
16274        let project = match &self.project {
16275            Some(project) => project.clone(),
16276            None => return None,
16277        };
16278
16279        Some(self.perform_format(
16280            project,
16281            FormatTrigger::Manual,
16282            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16283            window,
16284            cx,
16285        ))
16286    }
16287
16288    fn format_selections(
16289        &mut self,
16290        _: &FormatSelections,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) -> Option<Task<Result<()>>> {
16294        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16295
16296        let project = match &self.project {
16297            Some(project) => project.clone(),
16298            None => return None,
16299        };
16300
16301        let ranges = self
16302            .selections
16303            .all_adjusted(cx)
16304            .into_iter()
16305            .map(|selection| selection.range())
16306            .collect_vec();
16307
16308        Some(self.perform_format(
16309            project,
16310            FormatTrigger::Manual,
16311            FormatTarget::Ranges(ranges),
16312            window,
16313            cx,
16314        ))
16315    }
16316
16317    fn perform_format(
16318        &mut self,
16319        project: Entity<Project>,
16320        trigger: FormatTrigger,
16321        target: FormatTarget,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) -> Task<Result<()>> {
16325        let buffer = self.buffer.clone();
16326        let (buffers, target) = match target {
16327            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16328            FormatTarget::Ranges(selection_ranges) => {
16329                let multi_buffer = buffer.read(cx);
16330                let snapshot = multi_buffer.read(cx);
16331                let mut buffers = HashSet::default();
16332                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16333                    BTreeMap::new();
16334                for selection_range in selection_ranges {
16335                    for (buffer, buffer_range, _) in
16336                        snapshot.range_to_buffer_ranges(selection_range)
16337                    {
16338                        let buffer_id = buffer.remote_id();
16339                        let start = buffer.anchor_before(buffer_range.start);
16340                        let end = buffer.anchor_after(buffer_range.end);
16341                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16342                        buffer_id_to_ranges
16343                            .entry(buffer_id)
16344                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16345                            .or_insert_with(|| vec![start..end]);
16346                    }
16347                }
16348                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16349            }
16350        };
16351
16352        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16353        let selections_prev = transaction_id_prev
16354            .and_then(|transaction_id_prev| {
16355                // default to selections as they were after the last edit, if we have them,
16356                // instead of how they are now.
16357                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16358                // will take you back to where you made the last edit, instead of staying where you scrolled
16359                self.selection_history
16360                    .transaction(transaction_id_prev)
16361                    .map(|t| t.0.clone())
16362            })
16363            .unwrap_or_else(|| {
16364                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16365                self.selections.disjoint_anchors()
16366            });
16367
16368        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16369        let format = project.update(cx, |project, cx| {
16370            project.format(buffers, target, true, trigger, cx)
16371        });
16372
16373        cx.spawn_in(window, async move |editor, cx| {
16374            let transaction = futures::select_biased! {
16375                transaction = format.log_err().fuse() => transaction,
16376                () = timeout => {
16377                    log::warn!("timed out waiting for formatting");
16378                    None
16379                }
16380            };
16381
16382            buffer
16383                .update(cx, |buffer, cx| {
16384                    if let Some(transaction) = transaction {
16385                        if !buffer.is_singleton() {
16386                            buffer.push_transaction(&transaction.0, cx);
16387                        }
16388                    }
16389                    cx.notify();
16390                })
16391                .ok();
16392
16393            if let Some(transaction_id_now) =
16394                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16395            {
16396                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16397                if has_new_transaction {
16398                    _ = editor.update(cx, |editor, _| {
16399                        editor
16400                            .selection_history
16401                            .insert_transaction(transaction_id_now, selections_prev);
16402                    });
16403                }
16404            }
16405
16406            Ok(())
16407        })
16408    }
16409
16410    fn organize_imports(
16411        &mut self,
16412        _: &OrganizeImports,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) -> Option<Task<Result<()>>> {
16416        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16417        let project = match &self.project {
16418            Some(project) => project.clone(),
16419            None => return None,
16420        };
16421        Some(self.perform_code_action_kind(
16422            project,
16423            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16424            window,
16425            cx,
16426        ))
16427    }
16428
16429    fn perform_code_action_kind(
16430        &mut self,
16431        project: Entity<Project>,
16432        kind: CodeActionKind,
16433        window: &mut Window,
16434        cx: &mut Context<Self>,
16435    ) -> Task<Result<()>> {
16436        let buffer = self.buffer.clone();
16437        let buffers = buffer.read(cx).all_buffers();
16438        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16439        let apply_action = project.update(cx, |project, cx| {
16440            project.apply_code_action_kind(buffers, kind, true, cx)
16441        });
16442        cx.spawn_in(window, async move |_, cx| {
16443            let transaction = futures::select_biased! {
16444                () = timeout => {
16445                    log::warn!("timed out waiting for executing code action");
16446                    None
16447                }
16448                transaction = apply_action.log_err().fuse() => transaction,
16449            };
16450            buffer
16451                .update(cx, |buffer, cx| {
16452                    // check if we need this
16453                    if let Some(transaction) = transaction {
16454                        if !buffer.is_singleton() {
16455                            buffer.push_transaction(&transaction.0, cx);
16456                        }
16457                    }
16458                    cx.notify();
16459                })
16460                .ok();
16461            Ok(())
16462        })
16463    }
16464
16465    pub fn restart_language_server(
16466        &mut self,
16467        _: &RestartLanguageServer,
16468        _: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) {
16471        if let Some(project) = self.project.clone() {
16472            self.buffer.update(cx, |multi_buffer, cx| {
16473                project.update(cx, |project, cx| {
16474                    project.restart_language_servers_for_buffers(
16475                        multi_buffer.all_buffers().into_iter().collect(),
16476                        HashSet::default(),
16477                        cx,
16478                    );
16479                });
16480            })
16481        }
16482    }
16483
16484    pub fn stop_language_server(
16485        &mut self,
16486        _: &StopLanguageServer,
16487        _: &mut Window,
16488        cx: &mut Context<Self>,
16489    ) {
16490        if let Some(project) = self.project.clone() {
16491            self.buffer.update(cx, |multi_buffer, cx| {
16492                project.update(cx, |project, cx| {
16493                    project.stop_language_servers_for_buffers(
16494                        multi_buffer.all_buffers().into_iter().collect(),
16495                        HashSet::default(),
16496                        cx,
16497                    );
16498                    cx.emit(project::Event::RefreshInlayHints);
16499                });
16500            });
16501        }
16502    }
16503
16504    fn cancel_language_server_work(
16505        workspace: &mut Workspace,
16506        _: &actions::CancelLanguageServerWork,
16507        _: &mut Window,
16508        cx: &mut Context<Workspace>,
16509    ) {
16510        let project = workspace.project();
16511        let buffers = workspace
16512            .active_item(cx)
16513            .and_then(|item| item.act_as::<Editor>(cx))
16514            .map_or(HashSet::default(), |editor| {
16515                editor.read(cx).buffer.read(cx).all_buffers()
16516            });
16517        project.update(cx, |project, cx| {
16518            project.cancel_language_server_work_for_buffers(buffers, cx);
16519        });
16520    }
16521
16522    fn show_character_palette(
16523        &mut self,
16524        _: &ShowCharacterPalette,
16525        window: &mut Window,
16526        _: &mut Context<Self>,
16527    ) {
16528        window.show_character_palette();
16529    }
16530
16531    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16532        if !self.diagnostics_enabled() {
16533            return;
16534        }
16535
16536        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16537            let buffer = self.buffer.read(cx).snapshot(cx);
16538            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16539            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16540            let is_valid = buffer
16541                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16542                .any(|entry| {
16543                    entry.diagnostic.is_primary
16544                        && !entry.range.is_empty()
16545                        && entry.range.start == primary_range_start
16546                        && entry.diagnostic.message == active_diagnostics.active_message
16547                });
16548
16549            if !is_valid {
16550                self.dismiss_diagnostics(cx);
16551            }
16552        }
16553    }
16554
16555    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16556        match &self.active_diagnostics {
16557            ActiveDiagnostic::Group(group) => Some(group),
16558            _ => None,
16559        }
16560    }
16561
16562    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16563        if !self.diagnostics_enabled() {
16564            return;
16565        }
16566        self.dismiss_diagnostics(cx);
16567        self.active_diagnostics = ActiveDiagnostic::All;
16568    }
16569
16570    fn activate_diagnostics(
16571        &mut self,
16572        buffer_id: BufferId,
16573        diagnostic: DiagnosticEntry<usize>,
16574        window: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) {
16577        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16578            return;
16579        }
16580        self.dismiss_diagnostics(cx);
16581        let snapshot = self.snapshot(window, cx);
16582        let buffer = self.buffer.read(cx).snapshot(cx);
16583        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16584            return;
16585        };
16586
16587        let diagnostic_group = buffer
16588            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16589            .collect::<Vec<_>>();
16590
16591        let blocks =
16592            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16593
16594        let blocks = self.display_map.update(cx, |display_map, cx| {
16595            display_map.insert_blocks(blocks, cx).into_iter().collect()
16596        });
16597        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16598            active_range: buffer.anchor_before(diagnostic.range.start)
16599                ..buffer.anchor_after(diagnostic.range.end),
16600            active_message: diagnostic.diagnostic.message.clone(),
16601            group_id: diagnostic.diagnostic.group_id,
16602            blocks,
16603        });
16604        cx.notify();
16605    }
16606
16607    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16608        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16609            return;
16610        };
16611
16612        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16613        if let ActiveDiagnostic::Group(group) = prev {
16614            self.display_map.update(cx, |display_map, cx| {
16615                display_map.remove_blocks(group.blocks, cx);
16616            });
16617            cx.notify();
16618        }
16619    }
16620
16621    /// Disable inline diagnostics rendering for this editor.
16622    pub fn disable_inline_diagnostics(&mut self) {
16623        self.inline_diagnostics_enabled = false;
16624        self.inline_diagnostics_update = Task::ready(());
16625        self.inline_diagnostics.clear();
16626    }
16627
16628    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16629        self.diagnostics_enabled = false;
16630        self.dismiss_diagnostics(cx);
16631        self.inline_diagnostics_update = Task::ready(());
16632        self.inline_diagnostics.clear();
16633    }
16634
16635    pub fn diagnostics_enabled(&self) -> bool {
16636        self.diagnostics_enabled && self.mode.is_full()
16637    }
16638
16639    pub fn inline_diagnostics_enabled(&self) -> bool {
16640        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16641    }
16642
16643    pub fn show_inline_diagnostics(&self) -> bool {
16644        self.show_inline_diagnostics
16645    }
16646
16647    pub fn toggle_inline_diagnostics(
16648        &mut self,
16649        _: &ToggleInlineDiagnostics,
16650        window: &mut Window,
16651        cx: &mut Context<Editor>,
16652    ) {
16653        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16654        self.refresh_inline_diagnostics(false, window, cx);
16655    }
16656
16657    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16658        self.diagnostics_max_severity = severity;
16659        self.display_map.update(cx, |display_map, _| {
16660            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16661        });
16662    }
16663
16664    pub fn toggle_diagnostics(
16665        &mut self,
16666        _: &ToggleDiagnostics,
16667        window: &mut Window,
16668        cx: &mut Context<Editor>,
16669    ) {
16670        if !self.diagnostics_enabled() {
16671            return;
16672        }
16673
16674        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16675            EditorSettings::get_global(cx)
16676                .diagnostics_max_severity
16677                .filter(|severity| severity != &DiagnosticSeverity::Off)
16678                .unwrap_or(DiagnosticSeverity::Hint)
16679        } else {
16680            DiagnosticSeverity::Off
16681        };
16682        self.set_max_diagnostics_severity(new_severity, cx);
16683        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16684            self.active_diagnostics = ActiveDiagnostic::None;
16685            self.inline_diagnostics_update = Task::ready(());
16686            self.inline_diagnostics.clear();
16687        } else {
16688            self.refresh_inline_diagnostics(false, window, cx);
16689        }
16690
16691        cx.notify();
16692    }
16693
16694    pub fn toggle_minimap(
16695        &mut self,
16696        _: &ToggleMinimap,
16697        window: &mut Window,
16698        cx: &mut Context<Editor>,
16699    ) {
16700        if self.supports_minimap(cx) {
16701            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16702        }
16703    }
16704
16705    fn refresh_inline_diagnostics(
16706        &mut self,
16707        debounce: bool,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) {
16711        let max_severity = ProjectSettings::get_global(cx)
16712            .diagnostics
16713            .inline
16714            .max_severity
16715            .unwrap_or(self.diagnostics_max_severity);
16716
16717        if !self.inline_diagnostics_enabled()
16718            || !self.show_inline_diagnostics
16719            || max_severity == DiagnosticSeverity::Off
16720        {
16721            self.inline_diagnostics_update = Task::ready(());
16722            self.inline_diagnostics.clear();
16723            return;
16724        }
16725
16726        let debounce_ms = ProjectSettings::get_global(cx)
16727            .diagnostics
16728            .inline
16729            .update_debounce_ms;
16730        let debounce = if debounce && debounce_ms > 0 {
16731            Some(Duration::from_millis(debounce_ms))
16732        } else {
16733            None
16734        };
16735        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16736            if let Some(debounce) = debounce {
16737                cx.background_executor().timer(debounce).await;
16738            }
16739            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16740                editor
16741                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16742                    .ok()
16743            }) else {
16744                return;
16745            };
16746
16747            let new_inline_diagnostics = cx
16748                .background_spawn(async move {
16749                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16750                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16751                        let message = diagnostic_entry
16752                            .diagnostic
16753                            .message
16754                            .split_once('\n')
16755                            .map(|(line, _)| line)
16756                            .map(SharedString::new)
16757                            .unwrap_or_else(|| {
16758                                SharedString::from(diagnostic_entry.diagnostic.message)
16759                            });
16760                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16761                        let (Ok(i) | Err(i)) = inline_diagnostics
16762                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16763                        inline_diagnostics.insert(
16764                            i,
16765                            (
16766                                start_anchor,
16767                                InlineDiagnostic {
16768                                    message,
16769                                    group_id: diagnostic_entry.diagnostic.group_id,
16770                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16771                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16772                                    severity: diagnostic_entry.diagnostic.severity,
16773                                },
16774                            ),
16775                        );
16776                    }
16777                    inline_diagnostics
16778                })
16779                .await;
16780
16781            editor
16782                .update(cx, |editor, cx| {
16783                    editor.inline_diagnostics = new_inline_diagnostics;
16784                    cx.notify();
16785                })
16786                .ok();
16787        });
16788    }
16789
16790    fn pull_diagnostics(
16791        &mut self,
16792        buffer_id: Option<BufferId>,
16793        window: &Window,
16794        cx: &mut Context<Self>,
16795    ) -> Option<()> {
16796        if !self.mode().is_full() {
16797            return None;
16798        }
16799        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16800            .diagnostics
16801            .lsp_pull_diagnostics;
16802        if !pull_diagnostics_settings.enabled {
16803            return None;
16804        }
16805        let project = self.project.as_ref()?.downgrade();
16806        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16807        let mut buffers = self.buffer.read(cx).all_buffers();
16808        if let Some(buffer_id) = buffer_id {
16809            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16810        }
16811
16812        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16813            cx.background_executor().timer(debounce).await;
16814
16815            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16816                buffers
16817                    .into_iter()
16818                    .filter_map(|buffer| {
16819                        project
16820                            .update(cx, |project, cx| {
16821                                project.lsp_store().update(cx, |lsp_store, cx| {
16822                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16823                                })
16824                            })
16825                            .ok()
16826                    })
16827                    .collect::<FuturesUnordered<_>>()
16828            }) else {
16829                return;
16830            };
16831
16832            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16833                match pull_task {
16834                    Ok(()) => {
16835                        if editor
16836                            .update_in(cx, |editor, window, cx| {
16837                                editor.update_diagnostics_state(window, cx);
16838                            })
16839                            .is_err()
16840                        {
16841                            return;
16842                        }
16843                    }
16844                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16845                }
16846            }
16847        });
16848
16849        Some(())
16850    }
16851
16852    pub fn set_selections_from_remote(
16853        &mut self,
16854        selections: Vec<Selection<Anchor>>,
16855        pending_selection: Option<Selection<Anchor>>,
16856        window: &mut Window,
16857        cx: &mut Context<Self>,
16858    ) {
16859        let old_cursor_position = self.selections.newest_anchor().head();
16860        self.selections.change_with(cx, |s| {
16861            s.select_anchors(selections);
16862            if let Some(pending_selection) = pending_selection {
16863                s.set_pending(pending_selection, SelectMode::Character);
16864            } else {
16865                s.clear_pending();
16866            }
16867        });
16868        self.selections_did_change(
16869            false,
16870            &old_cursor_position,
16871            SelectionEffects::default(),
16872            window,
16873            cx,
16874        );
16875    }
16876
16877    pub fn transact(
16878        &mut self,
16879        window: &mut Window,
16880        cx: &mut Context<Self>,
16881        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16882    ) -> Option<TransactionId> {
16883        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16884            this.start_transaction_at(Instant::now(), window, cx);
16885            update(this, window, cx);
16886            this.end_transaction_at(Instant::now(), cx)
16887        })
16888    }
16889
16890    pub fn start_transaction_at(
16891        &mut self,
16892        now: Instant,
16893        window: &mut Window,
16894        cx: &mut Context<Self>,
16895    ) {
16896        self.end_selection(window, cx);
16897        if let Some(tx_id) = self
16898            .buffer
16899            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16900        {
16901            self.selection_history
16902                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16903            cx.emit(EditorEvent::TransactionBegun {
16904                transaction_id: tx_id,
16905            })
16906        }
16907    }
16908
16909    pub fn end_transaction_at(
16910        &mut self,
16911        now: Instant,
16912        cx: &mut Context<Self>,
16913    ) -> Option<TransactionId> {
16914        if let Some(transaction_id) = self
16915            .buffer
16916            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16917        {
16918            if let Some((_, end_selections)) =
16919                self.selection_history.transaction_mut(transaction_id)
16920            {
16921                *end_selections = Some(self.selections.disjoint_anchors());
16922            } else {
16923                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16924            }
16925
16926            cx.emit(EditorEvent::Edited { transaction_id });
16927            Some(transaction_id)
16928        } else {
16929            None
16930        }
16931    }
16932
16933    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16934        if self.selection_mark_mode {
16935            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16936                s.move_with(|_, sel| {
16937                    sel.collapse_to(sel.head(), SelectionGoal::None);
16938                });
16939            })
16940        }
16941        self.selection_mark_mode = true;
16942        cx.notify();
16943    }
16944
16945    pub fn swap_selection_ends(
16946        &mut self,
16947        _: &actions::SwapSelectionEnds,
16948        window: &mut Window,
16949        cx: &mut Context<Self>,
16950    ) {
16951        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16952            s.move_with(|_, sel| {
16953                if sel.start != sel.end {
16954                    sel.reversed = !sel.reversed
16955                }
16956            });
16957        });
16958        self.request_autoscroll(Autoscroll::newest(), cx);
16959        cx.notify();
16960    }
16961
16962    pub fn toggle_focus(
16963        workspace: &mut Workspace,
16964        _: &actions::ToggleFocus,
16965        window: &mut Window,
16966        cx: &mut Context<Workspace>,
16967    ) {
16968        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
16969            return;
16970        };
16971        workspace.activate_item(&item, true, true, window, cx);
16972    }
16973
16974    pub fn toggle_fold(
16975        &mut self,
16976        _: &actions::ToggleFold,
16977        window: &mut Window,
16978        cx: &mut Context<Self>,
16979    ) {
16980        if self.is_singleton(cx) {
16981            let selection = self.selections.newest::<Point>(cx);
16982
16983            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16984            let range = if selection.is_empty() {
16985                let point = selection.head().to_display_point(&display_map);
16986                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16987                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16988                    .to_point(&display_map);
16989                start..end
16990            } else {
16991                selection.range()
16992            };
16993            if display_map.folds_in_range(range).next().is_some() {
16994                self.unfold_lines(&Default::default(), window, cx)
16995            } else {
16996                self.fold(&Default::default(), window, cx)
16997            }
16998        } else {
16999            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17000            let buffer_ids: HashSet<_> = self
17001                .selections
17002                .disjoint_anchor_ranges()
17003                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17004                .collect();
17005
17006            let should_unfold = buffer_ids
17007                .iter()
17008                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17009
17010            for buffer_id in buffer_ids {
17011                if should_unfold {
17012                    self.unfold_buffer(buffer_id, cx);
17013                } else {
17014                    self.fold_buffer(buffer_id, cx);
17015                }
17016            }
17017        }
17018    }
17019
17020    pub fn toggle_fold_recursive(
17021        &mut self,
17022        _: &actions::ToggleFoldRecursive,
17023        window: &mut Window,
17024        cx: &mut Context<Self>,
17025    ) {
17026        let selection = self.selections.newest::<Point>(cx);
17027
17028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17029        let range = if selection.is_empty() {
17030            let point = selection.head().to_display_point(&display_map);
17031            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17032            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17033                .to_point(&display_map);
17034            start..end
17035        } else {
17036            selection.range()
17037        };
17038        if display_map.folds_in_range(range).next().is_some() {
17039            self.unfold_recursive(&Default::default(), window, cx)
17040        } else {
17041            self.fold_recursive(&Default::default(), window, cx)
17042        }
17043    }
17044
17045    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17046        if self.is_singleton(cx) {
17047            let mut to_fold = Vec::new();
17048            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17049            let selections = self.selections.all_adjusted(cx);
17050
17051            for selection in selections {
17052                let range = selection.range().sorted();
17053                let buffer_start_row = range.start.row;
17054
17055                if range.start.row != range.end.row {
17056                    let mut found = false;
17057                    let mut row = range.start.row;
17058                    while row <= range.end.row {
17059                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17060                        {
17061                            found = true;
17062                            row = crease.range().end.row + 1;
17063                            to_fold.push(crease);
17064                        } else {
17065                            row += 1
17066                        }
17067                    }
17068                    if found {
17069                        continue;
17070                    }
17071                }
17072
17073                for row in (0..=range.start.row).rev() {
17074                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17075                        if crease.range().end.row >= buffer_start_row {
17076                            to_fold.push(crease);
17077                            if row <= range.start.row {
17078                                break;
17079                            }
17080                        }
17081                    }
17082                }
17083            }
17084
17085            self.fold_creases(to_fold, true, window, cx);
17086        } else {
17087            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17088            let buffer_ids = self
17089                .selections
17090                .disjoint_anchor_ranges()
17091                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17092                .collect::<HashSet<_>>();
17093            for buffer_id in buffer_ids {
17094                self.fold_buffer(buffer_id, cx);
17095            }
17096        }
17097    }
17098
17099    pub fn toggle_fold_all(
17100        &mut self,
17101        _: &actions::ToggleFoldAll,
17102        window: &mut Window,
17103        cx: &mut Context<Self>,
17104    ) {
17105        if self.buffer.read(cx).is_singleton() {
17106            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17107            let has_folds = display_map
17108                .folds_in_range(0..display_map.buffer_snapshot.len())
17109                .next()
17110                .is_some();
17111
17112            if has_folds {
17113                self.unfold_all(&actions::UnfoldAll, window, cx);
17114            } else {
17115                self.fold_all(&actions::FoldAll, window, cx);
17116            }
17117        } else {
17118            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17119            let should_unfold = buffer_ids
17120                .iter()
17121                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17122
17123            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17124                editor
17125                    .update_in(cx, |editor, _, cx| {
17126                        for buffer_id in buffer_ids {
17127                            if should_unfold {
17128                                editor.unfold_buffer(buffer_id, cx);
17129                            } else {
17130                                editor.fold_buffer(buffer_id, cx);
17131                            }
17132                        }
17133                    })
17134                    .ok();
17135            });
17136        }
17137    }
17138
17139    fn fold_at_level(
17140        &mut self,
17141        fold_at: &FoldAtLevel,
17142        window: &mut Window,
17143        cx: &mut Context<Self>,
17144    ) {
17145        if !self.buffer.read(cx).is_singleton() {
17146            return;
17147        }
17148
17149        let fold_at_level = fold_at.0;
17150        let snapshot = self.buffer.read(cx).snapshot(cx);
17151        let mut to_fold = Vec::new();
17152        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17153
17154        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17155            while start_row < end_row {
17156                match self
17157                    .snapshot(window, cx)
17158                    .crease_for_buffer_row(MultiBufferRow(start_row))
17159                {
17160                    Some(crease) => {
17161                        let nested_start_row = crease.range().start.row + 1;
17162                        let nested_end_row = crease.range().end.row;
17163
17164                        if current_level < fold_at_level {
17165                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17166                        } else if current_level == fold_at_level {
17167                            to_fold.push(crease);
17168                        }
17169
17170                        start_row = nested_end_row + 1;
17171                    }
17172                    None => start_row += 1,
17173                }
17174            }
17175        }
17176
17177        self.fold_creases(to_fold, true, window, cx);
17178    }
17179
17180    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17181        if self.buffer.read(cx).is_singleton() {
17182            let mut fold_ranges = Vec::new();
17183            let snapshot = self.buffer.read(cx).snapshot(cx);
17184
17185            for row in 0..snapshot.max_row().0 {
17186                if let Some(foldable_range) = self
17187                    .snapshot(window, cx)
17188                    .crease_for_buffer_row(MultiBufferRow(row))
17189                {
17190                    fold_ranges.push(foldable_range);
17191                }
17192            }
17193
17194            self.fold_creases(fold_ranges, true, window, cx);
17195        } else {
17196            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17197                editor
17198                    .update_in(cx, |editor, _, cx| {
17199                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17200                            editor.fold_buffer(buffer_id, cx);
17201                        }
17202                    })
17203                    .ok();
17204            });
17205        }
17206    }
17207
17208    pub fn fold_function_bodies(
17209        &mut self,
17210        _: &actions::FoldFunctionBodies,
17211        window: &mut Window,
17212        cx: &mut Context<Self>,
17213    ) {
17214        let snapshot = self.buffer.read(cx).snapshot(cx);
17215
17216        let ranges = snapshot
17217            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17218            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17219            .collect::<Vec<_>>();
17220
17221        let creases = ranges
17222            .into_iter()
17223            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17224            .collect();
17225
17226        self.fold_creases(creases, true, window, cx);
17227    }
17228
17229    pub fn fold_recursive(
17230        &mut self,
17231        _: &actions::FoldRecursive,
17232        window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        let mut to_fold = Vec::new();
17236        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17237        let selections = self.selections.all_adjusted(cx);
17238
17239        for selection in selections {
17240            let range = selection.range().sorted();
17241            let buffer_start_row = range.start.row;
17242
17243            if range.start.row != range.end.row {
17244                let mut found = false;
17245                for row in range.start.row..=range.end.row {
17246                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17247                        found = true;
17248                        to_fold.push(crease);
17249                    }
17250                }
17251                if found {
17252                    continue;
17253                }
17254            }
17255
17256            for row in (0..=range.start.row).rev() {
17257                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17258                    if crease.range().end.row >= buffer_start_row {
17259                        to_fold.push(crease);
17260                    } else {
17261                        break;
17262                    }
17263                }
17264            }
17265        }
17266
17267        self.fold_creases(to_fold, true, window, cx);
17268    }
17269
17270    pub fn fold_at(
17271        &mut self,
17272        buffer_row: MultiBufferRow,
17273        window: &mut Window,
17274        cx: &mut Context<Self>,
17275    ) {
17276        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17277
17278        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17279            let autoscroll = self
17280                .selections
17281                .all::<Point>(cx)
17282                .iter()
17283                .any(|selection| crease.range().overlaps(&selection.range()));
17284
17285            self.fold_creases(vec![crease], autoscroll, window, cx);
17286        }
17287    }
17288
17289    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17290        if self.is_singleton(cx) {
17291            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17292            let buffer = &display_map.buffer_snapshot;
17293            let selections = self.selections.all::<Point>(cx);
17294            let ranges = selections
17295                .iter()
17296                .map(|s| {
17297                    let range = s.display_range(&display_map).sorted();
17298                    let mut start = range.start.to_point(&display_map);
17299                    let mut end = range.end.to_point(&display_map);
17300                    start.column = 0;
17301                    end.column = buffer.line_len(MultiBufferRow(end.row));
17302                    start..end
17303                })
17304                .collect::<Vec<_>>();
17305
17306            self.unfold_ranges(&ranges, true, true, cx);
17307        } else {
17308            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17309            let buffer_ids = self
17310                .selections
17311                .disjoint_anchor_ranges()
17312                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17313                .collect::<HashSet<_>>();
17314            for buffer_id in buffer_ids {
17315                self.unfold_buffer(buffer_id, cx);
17316            }
17317        }
17318    }
17319
17320    pub fn unfold_recursive(
17321        &mut self,
17322        _: &UnfoldRecursive,
17323        _window: &mut Window,
17324        cx: &mut Context<Self>,
17325    ) {
17326        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17327        let selections = self.selections.all::<Point>(cx);
17328        let ranges = selections
17329            .iter()
17330            .map(|s| {
17331                let mut range = s.display_range(&display_map).sorted();
17332                *range.start.column_mut() = 0;
17333                *range.end.column_mut() = display_map.line_len(range.end.row());
17334                let start = range.start.to_point(&display_map);
17335                let end = range.end.to_point(&display_map);
17336                start..end
17337            })
17338            .collect::<Vec<_>>();
17339
17340        self.unfold_ranges(&ranges, true, true, cx);
17341    }
17342
17343    pub fn unfold_at(
17344        &mut self,
17345        buffer_row: MultiBufferRow,
17346        _window: &mut Window,
17347        cx: &mut Context<Self>,
17348    ) {
17349        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17350
17351        let intersection_range = Point::new(buffer_row.0, 0)
17352            ..Point::new(
17353                buffer_row.0,
17354                display_map.buffer_snapshot.line_len(buffer_row),
17355            );
17356
17357        let autoscroll = self
17358            .selections
17359            .all::<Point>(cx)
17360            .iter()
17361            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17362
17363        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17364    }
17365
17366    pub fn unfold_all(
17367        &mut self,
17368        _: &actions::UnfoldAll,
17369        _window: &mut Window,
17370        cx: &mut Context<Self>,
17371    ) {
17372        if self.buffer.read(cx).is_singleton() {
17373            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17374            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17375        } else {
17376            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17377                editor
17378                    .update(cx, |editor, cx| {
17379                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17380                            editor.unfold_buffer(buffer_id, cx);
17381                        }
17382                    })
17383                    .ok();
17384            });
17385        }
17386    }
17387
17388    pub fn fold_selected_ranges(
17389        &mut self,
17390        _: &FoldSelectedRanges,
17391        window: &mut Window,
17392        cx: &mut Context<Self>,
17393    ) {
17394        let selections = self.selections.all_adjusted(cx);
17395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17396        let ranges = selections
17397            .into_iter()
17398            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17399            .collect::<Vec<_>>();
17400        self.fold_creases(ranges, true, window, cx);
17401    }
17402
17403    pub fn fold_ranges<T: ToOffset + Clone>(
17404        &mut self,
17405        ranges: Vec<Range<T>>,
17406        auto_scroll: bool,
17407        window: &mut Window,
17408        cx: &mut Context<Self>,
17409    ) {
17410        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17411        let ranges = ranges
17412            .into_iter()
17413            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17414            .collect::<Vec<_>>();
17415        self.fold_creases(ranges, auto_scroll, window, cx);
17416    }
17417
17418    pub fn fold_creases<T: ToOffset + Clone>(
17419        &mut self,
17420        creases: Vec<Crease<T>>,
17421        auto_scroll: bool,
17422        _window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) {
17425        if creases.is_empty() {
17426            return;
17427        }
17428
17429        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17430
17431        if auto_scroll {
17432            self.request_autoscroll(Autoscroll::fit(), cx);
17433        }
17434
17435        cx.notify();
17436
17437        self.scrollbar_marker_state.dirty = true;
17438        self.folds_did_change(cx);
17439    }
17440
17441    /// Removes any folds whose ranges intersect any of the given ranges.
17442    pub fn unfold_ranges<T: ToOffset + Clone>(
17443        &mut self,
17444        ranges: &[Range<T>],
17445        inclusive: bool,
17446        auto_scroll: bool,
17447        cx: &mut Context<Self>,
17448    ) {
17449        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17450            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17451        });
17452        self.folds_did_change(cx);
17453    }
17454
17455    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17456        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17457            return;
17458        }
17459        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17460        self.display_map.update(cx, |display_map, cx| {
17461            display_map.fold_buffers([buffer_id], cx)
17462        });
17463        cx.emit(EditorEvent::BufferFoldToggled {
17464            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17465            folded: true,
17466        });
17467        cx.notify();
17468    }
17469
17470    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17471        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17472            return;
17473        }
17474        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17475        self.display_map.update(cx, |display_map, cx| {
17476            display_map.unfold_buffers([buffer_id], cx);
17477        });
17478        cx.emit(EditorEvent::BufferFoldToggled {
17479            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17480            folded: false,
17481        });
17482        cx.notify();
17483    }
17484
17485    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17486        self.display_map.read(cx).is_buffer_folded(buffer)
17487    }
17488
17489    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17490        self.display_map.read(cx).folded_buffers()
17491    }
17492
17493    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17494        self.display_map.update(cx, |display_map, cx| {
17495            display_map.disable_header_for_buffer(buffer_id, cx);
17496        });
17497        cx.notify();
17498    }
17499
17500    /// Removes any folds with the given ranges.
17501    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17502        &mut self,
17503        ranges: &[Range<T>],
17504        type_id: TypeId,
17505        auto_scroll: bool,
17506        cx: &mut Context<Self>,
17507    ) {
17508        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17509            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17510        });
17511        self.folds_did_change(cx);
17512    }
17513
17514    fn remove_folds_with<T: ToOffset + Clone>(
17515        &mut self,
17516        ranges: &[Range<T>],
17517        auto_scroll: bool,
17518        cx: &mut Context<Self>,
17519        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17520    ) {
17521        if ranges.is_empty() {
17522            return;
17523        }
17524
17525        let mut buffers_affected = HashSet::default();
17526        let multi_buffer = self.buffer().read(cx);
17527        for range in ranges {
17528            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17529                buffers_affected.insert(buffer.read(cx).remote_id());
17530            };
17531        }
17532
17533        self.display_map.update(cx, update);
17534
17535        if auto_scroll {
17536            self.request_autoscroll(Autoscroll::fit(), cx);
17537        }
17538
17539        cx.notify();
17540        self.scrollbar_marker_state.dirty = true;
17541        self.active_indent_guides_state.dirty = true;
17542    }
17543
17544    pub fn update_renderer_widths(
17545        &mut self,
17546        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17547        cx: &mut Context<Self>,
17548    ) -> bool {
17549        self.display_map
17550            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17551    }
17552
17553    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17554        self.display_map.read(cx).fold_placeholder.clone()
17555    }
17556
17557    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17558        self.buffer.update(cx, |buffer, cx| {
17559            buffer.set_all_diff_hunks_expanded(cx);
17560        });
17561    }
17562
17563    pub fn expand_all_diff_hunks(
17564        &mut self,
17565        _: &ExpandAllDiffHunks,
17566        _window: &mut Window,
17567        cx: &mut Context<Self>,
17568    ) {
17569        self.buffer.update(cx, |buffer, cx| {
17570            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17571        });
17572    }
17573
17574    pub fn toggle_selected_diff_hunks(
17575        &mut self,
17576        _: &ToggleSelectedDiffHunks,
17577        _window: &mut Window,
17578        cx: &mut Context<Self>,
17579    ) {
17580        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17581        self.toggle_diff_hunks_in_ranges(ranges, cx);
17582    }
17583
17584    pub fn diff_hunks_in_ranges<'a>(
17585        &'a self,
17586        ranges: &'a [Range<Anchor>],
17587        buffer: &'a MultiBufferSnapshot,
17588    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17589        ranges.iter().flat_map(move |range| {
17590            let end_excerpt_id = range.end.excerpt_id;
17591            let range = range.to_point(buffer);
17592            let mut peek_end = range.end;
17593            if range.end.row < buffer.max_row().0 {
17594                peek_end = Point::new(range.end.row + 1, 0);
17595            }
17596            buffer
17597                .diff_hunks_in_range(range.start..peek_end)
17598                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17599        })
17600    }
17601
17602    pub fn has_stageable_diff_hunks_in_ranges(
17603        &self,
17604        ranges: &[Range<Anchor>],
17605        snapshot: &MultiBufferSnapshot,
17606    ) -> bool {
17607        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17608        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17609    }
17610
17611    pub fn toggle_staged_selected_diff_hunks(
17612        &mut self,
17613        _: &::git::ToggleStaged,
17614        _: &mut Window,
17615        cx: &mut Context<Self>,
17616    ) {
17617        let snapshot = self.buffer.read(cx).snapshot(cx);
17618        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17619        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17620        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17621    }
17622
17623    pub fn set_render_diff_hunk_controls(
17624        &mut self,
17625        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17626        cx: &mut Context<Self>,
17627    ) {
17628        self.render_diff_hunk_controls = render_diff_hunk_controls;
17629        cx.notify();
17630    }
17631
17632    pub fn stage_and_next(
17633        &mut self,
17634        _: &::git::StageAndNext,
17635        window: &mut Window,
17636        cx: &mut Context<Self>,
17637    ) {
17638        self.do_stage_or_unstage_and_next(true, window, cx);
17639    }
17640
17641    pub fn unstage_and_next(
17642        &mut self,
17643        _: &::git::UnstageAndNext,
17644        window: &mut Window,
17645        cx: &mut Context<Self>,
17646    ) {
17647        self.do_stage_or_unstage_and_next(false, window, cx);
17648    }
17649
17650    pub fn stage_or_unstage_diff_hunks(
17651        &mut self,
17652        stage: bool,
17653        ranges: Vec<Range<Anchor>>,
17654        cx: &mut Context<Self>,
17655    ) {
17656        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17657        cx.spawn(async move |this, cx| {
17658            task.await?;
17659            this.update(cx, |this, cx| {
17660                let snapshot = this.buffer.read(cx).snapshot(cx);
17661                let chunk_by = this
17662                    .diff_hunks_in_ranges(&ranges, &snapshot)
17663                    .chunk_by(|hunk| hunk.buffer_id);
17664                for (buffer_id, hunks) in &chunk_by {
17665                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17666                }
17667            })
17668        })
17669        .detach_and_log_err(cx);
17670    }
17671
17672    fn save_buffers_for_ranges_if_needed(
17673        &mut self,
17674        ranges: &[Range<Anchor>],
17675        cx: &mut Context<Editor>,
17676    ) -> Task<Result<()>> {
17677        let multibuffer = self.buffer.read(cx);
17678        let snapshot = multibuffer.read(cx);
17679        let buffer_ids: HashSet<_> = ranges
17680            .iter()
17681            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17682            .collect();
17683        drop(snapshot);
17684
17685        let mut buffers = HashSet::default();
17686        for buffer_id in buffer_ids {
17687            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17688                let buffer = buffer_entity.read(cx);
17689                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17690                {
17691                    buffers.insert(buffer_entity);
17692                }
17693            }
17694        }
17695
17696        if let Some(project) = &self.project {
17697            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17698        } else {
17699            Task::ready(Ok(()))
17700        }
17701    }
17702
17703    fn do_stage_or_unstage_and_next(
17704        &mut self,
17705        stage: bool,
17706        window: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) {
17709        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17710
17711        if ranges.iter().any(|range| range.start != range.end) {
17712            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17713            return;
17714        }
17715
17716        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17717        let snapshot = self.snapshot(window, cx);
17718        let position = self.selections.newest::<Point>(cx).head();
17719        let mut row = snapshot
17720            .buffer_snapshot
17721            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17722            .find(|hunk| hunk.row_range.start.0 > position.row)
17723            .map(|hunk| hunk.row_range.start);
17724
17725        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17726        // Outside of the project diff editor, wrap around to the beginning.
17727        if !all_diff_hunks_expanded {
17728            row = row.or_else(|| {
17729                snapshot
17730                    .buffer_snapshot
17731                    .diff_hunks_in_range(Point::zero()..position)
17732                    .find(|hunk| hunk.row_range.end.0 < position.row)
17733                    .map(|hunk| hunk.row_range.start)
17734            });
17735        }
17736
17737        if let Some(row) = row {
17738            let destination = Point::new(row.0, 0);
17739            let autoscroll = Autoscroll::center();
17740
17741            self.unfold_ranges(&[destination..destination], false, false, cx);
17742            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17743                s.select_ranges([destination..destination]);
17744            });
17745        }
17746    }
17747
17748    fn do_stage_or_unstage(
17749        &self,
17750        stage: bool,
17751        buffer_id: BufferId,
17752        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17753        cx: &mut App,
17754    ) -> Option<()> {
17755        let project = self.project.as_ref()?;
17756        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17757        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17758        let buffer_snapshot = buffer.read(cx).snapshot();
17759        let file_exists = buffer_snapshot
17760            .file()
17761            .is_some_and(|file| file.disk_state().exists());
17762        diff.update(cx, |diff, cx| {
17763            diff.stage_or_unstage_hunks(
17764                stage,
17765                &hunks
17766                    .map(|hunk| buffer_diff::DiffHunk {
17767                        buffer_range: hunk.buffer_range,
17768                        diff_base_byte_range: hunk.diff_base_byte_range,
17769                        secondary_status: hunk.secondary_status,
17770                        range: Point::zero()..Point::zero(), // unused
17771                    })
17772                    .collect::<Vec<_>>(),
17773                &buffer_snapshot,
17774                file_exists,
17775                cx,
17776            )
17777        });
17778        None
17779    }
17780
17781    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17782        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17783        self.buffer
17784            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17785    }
17786
17787    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17788        self.buffer.update(cx, |buffer, cx| {
17789            let ranges = vec![Anchor::min()..Anchor::max()];
17790            if !buffer.all_diff_hunks_expanded()
17791                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17792            {
17793                buffer.collapse_diff_hunks(ranges, cx);
17794                true
17795            } else {
17796                false
17797            }
17798        })
17799    }
17800
17801    fn toggle_diff_hunks_in_ranges(
17802        &mut self,
17803        ranges: Vec<Range<Anchor>>,
17804        cx: &mut Context<Editor>,
17805    ) {
17806        self.buffer.update(cx, |buffer, cx| {
17807            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17808            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17809        })
17810    }
17811
17812    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17813        self.buffer.update(cx, |buffer, cx| {
17814            let snapshot = buffer.snapshot(cx);
17815            let excerpt_id = range.end.excerpt_id;
17816            let point_range = range.to_point(&snapshot);
17817            let expand = !buffer.single_hunk_is_expanded(range, cx);
17818            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17819        })
17820    }
17821
17822    pub(crate) fn apply_all_diff_hunks(
17823        &mut self,
17824        _: &ApplyAllDiffHunks,
17825        window: &mut Window,
17826        cx: &mut Context<Self>,
17827    ) {
17828        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17829
17830        let buffers = self.buffer.read(cx).all_buffers();
17831        for branch_buffer in buffers {
17832            branch_buffer.update(cx, |branch_buffer, cx| {
17833                branch_buffer.merge_into_base(Vec::new(), cx);
17834            });
17835        }
17836
17837        if let Some(project) = self.project.clone() {
17838            self.save(
17839                SaveOptions {
17840                    format: true,
17841                    autosave: false,
17842                },
17843                project,
17844                window,
17845                cx,
17846            )
17847            .detach_and_log_err(cx);
17848        }
17849    }
17850
17851    pub(crate) fn apply_selected_diff_hunks(
17852        &mut self,
17853        _: &ApplyDiffHunk,
17854        window: &mut Window,
17855        cx: &mut Context<Self>,
17856    ) {
17857        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17858        let snapshot = self.snapshot(window, cx);
17859        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17860        let mut ranges_by_buffer = HashMap::default();
17861        self.transact(window, cx, |editor, _window, cx| {
17862            for hunk in hunks {
17863                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17864                    ranges_by_buffer
17865                        .entry(buffer.clone())
17866                        .or_insert_with(Vec::new)
17867                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17868                }
17869            }
17870
17871            for (buffer, ranges) in ranges_by_buffer {
17872                buffer.update(cx, |buffer, cx| {
17873                    buffer.merge_into_base(ranges, cx);
17874                });
17875            }
17876        });
17877
17878        if let Some(project) = self.project.clone() {
17879            self.save(
17880                SaveOptions {
17881                    format: true,
17882                    autosave: false,
17883                },
17884                project,
17885                window,
17886                cx,
17887            )
17888            .detach_and_log_err(cx);
17889        }
17890    }
17891
17892    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17893        if hovered != self.gutter_hovered {
17894            self.gutter_hovered = hovered;
17895            cx.notify();
17896        }
17897    }
17898
17899    pub fn insert_blocks(
17900        &mut self,
17901        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17902        autoscroll: Option<Autoscroll>,
17903        cx: &mut Context<Self>,
17904    ) -> Vec<CustomBlockId> {
17905        let blocks = self
17906            .display_map
17907            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17908        if let Some(autoscroll) = autoscroll {
17909            self.request_autoscroll(autoscroll, cx);
17910        }
17911        cx.notify();
17912        blocks
17913    }
17914
17915    pub fn resize_blocks(
17916        &mut self,
17917        heights: HashMap<CustomBlockId, u32>,
17918        autoscroll: Option<Autoscroll>,
17919        cx: &mut Context<Self>,
17920    ) {
17921        self.display_map
17922            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17923        if let Some(autoscroll) = autoscroll {
17924            self.request_autoscroll(autoscroll, cx);
17925        }
17926        cx.notify();
17927    }
17928
17929    pub fn replace_blocks(
17930        &mut self,
17931        renderers: HashMap<CustomBlockId, RenderBlock>,
17932        autoscroll: Option<Autoscroll>,
17933        cx: &mut Context<Self>,
17934    ) {
17935        self.display_map
17936            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17937        if let Some(autoscroll) = autoscroll {
17938            self.request_autoscroll(autoscroll, cx);
17939        }
17940        cx.notify();
17941    }
17942
17943    pub fn remove_blocks(
17944        &mut self,
17945        block_ids: HashSet<CustomBlockId>,
17946        autoscroll: Option<Autoscroll>,
17947        cx: &mut Context<Self>,
17948    ) {
17949        self.display_map.update(cx, |display_map, cx| {
17950            display_map.remove_blocks(block_ids, cx)
17951        });
17952        if let Some(autoscroll) = autoscroll {
17953            self.request_autoscroll(autoscroll, cx);
17954        }
17955        cx.notify();
17956    }
17957
17958    pub fn row_for_block(
17959        &self,
17960        block_id: CustomBlockId,
17961        cx: &mut Context<Self>,
17962    ) -> Option<DisplayRow> {
17963        self.display_map
17964            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17965    }
17966
17967    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17968        self.focused_block = Some(focused_block);
17969    }
17970
17971    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17972        self.focused_block.take()
17973    }
17974
17975    pub fn insert_creases(
17976        &mut self,
17977        creases: impl IntoIterator<Item = Crease<Anchor>>,
17978        cx: &mut Context<Self>,
17979    ) -> Vec<CreaseId> {
17980        self.display_map
17981            .update(cx, |map, cx| map.insert_creases(creases, cx))
17982    }
17983
17984    pub fn remove_creases(
17985        &mut self,
17986        ids: impl IntoIterator<Item = CreaseId>,
17987        cx: &mut Context<Self>,
17988    ) -> Vec<(CreaseId, Range<Anchor>)> {
17989        self.display_map
17990            .update(cx, |map, cx| map.remove_creases(ids, cx))
17991    }
17992
17993    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17994        self.display_map
17995            .update(cx, |map, cx| map.snapshot(cx))
17996            .longest_row()
17997    }
17998
17999    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18000        self.display_map
18001            .update(cx, |map, cx| map.snapshot(cx))
18002            .max_point()
18003    }
18004
18005    pub fn text(&self, cx: &App) -> String {
18006        self.buffer.read(cx).read(cx).text()
18007    }
18008
18009    pub fn is_empty(&self, cx: &App) -> bool {
18010        self.buffer.read(cx).read(cx).is_empty()
18011    }
18012
18013    pub fn text_option(&self, cx: &App) -> Option<String> {
18014        let text = self.text(cx);
18015        let text = text.trim();
18016
18017        if text.is_empty() {
18018            return None;
18019        }
18020
18021        Some(text.to_string())
18022    }
18023
18024    pub fn set_text(
18025        &mut self,
18026        text: impl Into<Arc<str>>,
18027        window: &mut Window,
18028        cx: &mut Context<Self>,
18029    ) {
18030        self.transact(window, cx, |this, _, cx| {
18031            this.buffer
18032                .read(cx)
18033                .as_singleton()
18034                .expect("you can only call set_text on editors for singleton buffers")
18035                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18036        });
18037    }
18038
18039    pub fn display_text(&self, cx: &mut App) -> String {
18040        self.display_map
18041            .update(cx, |map, cx| map.snapshot(cx))
18042            .text()
18043    }
18044
18045    fn create_minimap(
18046        &self,
18047        minimap_settings: MinimapSettings,
18048        window: &mut Window,
18049        cx: &mut Context<Self>,
18050    ) -> Option<Entity<Self>> {
18051        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18052            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18053    }
18054
18055    fn initialize_new_minimap(
18056        &self,
18057        minimap_settings: MinimapSettings,
18058        window: &mut Window,
18059        cx: &mut Context<Self>,
18060    ) -> Entity<Self> {
18061        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18062
18063        let mut minimap = Editor::new_internal(
18064            EditorMode::Minimap {
18065                parent: cx.weak_entity(),
18066            },
18067            self.buffer.clone(),
18068            None,
18069            Some(self.display_map.clone()),
18070            window,
18071            cx,
18072        );
18073        minimap.scroll_manager.clone_state(&self.scroll_manager);
18074        minimap.set_text_style_refinement(TextStyleRefinement {
18075            font_size: Some(MINIMAP_FONT_SIZE),
18076            font_weight: Some(MINIMAP_FONT_WEIGHT),
18077            ..Default::default()
18078        });
18079        minimap.update_minimap_configuration(minimap_settings, cx);
18080        cx.new(|_| minimap)
18081    }
18082
18083    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18084        let current_line_highlight = minimap_settings
18085            .current_line_highlight
18086            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18087        self.set_current_line_highlight(Some(current_line_highlight));
18088    }
18089
18090    pub fn minimap(&self) -> Option<&Entity<Self>> {
18091        self.minimap
18092            .as_ref()
18093            .filter(|_| self.minimap_visibility.visible())
18094    }
18095
18096    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18097        let mut wrap_guides = smallvec![];
18098
18099        if self.show_wrap_guides == Some(false) {
18100            return wrap_guides;
18101        }
18102
18103        let settings = self.buffer.read(cx).language_settings(cx);
18104        if settings.show_wrap_guides {
18105            match self.soft_wrap_mode(cx) {
18106                SoftWrap::Column(soft_wrap) => {
18107                    wrap_guides.push((soft_wrap as usize, true));
18108                }
18109                SoftWrap::Bounded(soft_wrap) => {
18110                    wrap_guides.push((soft_wrap as usize, true));
18111                }
18112                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18113            }
18114            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18115        }
18116
18117        wrap_guides
18118    }
18119
18120    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18121        let settings = self.buffer.read(cx).language_settings(cx);
18122        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18123        match mode {
18124            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18125                SoftWrap::None
18126            }
18127            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18128            language_settings::SoftWrap::PreferredLineLength => {
18129                SoftWrap::Column(settings.preferred_line_length)
18130            }
18131            language_settings::SoftWrap::Bounded => {
18132                SoftWrap::Bounded(settings.preferred_line_length)
18133            }
18134        }
18135    }
18136
18137    pub fn set_soft_wrap_mode(
18138        &mut self,
18139        mode: language_settings::SoftWrap,
18140
18141        cx: &mut Context<Self>,
18142    ) {
18143        self.soft_wrap_mode_override = Some(mode);
18144        cx.notify();
18145    }
18146
18147    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18148        self.hard_wrap = hard_wrap;
18149        cx.notify();
18150    }
18151
18152    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18153        self.text_style_refinement = Some(style);
18154    }
18155
18156    /// called by the Element so we know what style we were most recently rendered with.
18157    pub(crate) fn set_style(
18158        &mut self,
18159        style: EditorStyle,
18160        window: &mut Window,
18161        cx: &mut Context<Self>,
18162    ) {
18163        // We intentionally do not inform the display map about the minimap style
18164        // so that wrapping is not recalculated and stays consistent for the editor
18165        // and its linked minimap.
18166        if !self.mode.is_minimap() {
18167            let rem_size = window.rem_size();
18168            self.display_map.update(cx, |map, cx| {
18169                map.set_font(
18170                    style.text.font(),
18171                    style.text.font_size.to_pixels(rem_size),
18172                    cx,
18173                )
18174            });
18175        }
18176        self.style = Some(style);
18177    }
18178
18179    pub fn style(&self) -> Option<&EditorStyle> {
18180        self.style.as_ref()
18181    }
18182
18183    // Called by the element. This method is not designed to be called outside of the editor
18184    // element's layout code because it does not notify when rewrapping is computed synchronously.
18185    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18186        self.display_map
18187            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18188    }
18189
18190    pub fn set_soft_wrap(&mut self) {
18191        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18192    }
18193
18194    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18195        if self.soft_wrap_mode_override.is_some() {
18196            self.soft_wrap_mode_override.take();
18197        } else {
18198            let soft_wrap = match self.soft_wrap_mode(cx) {
18199                SoftWrap::GitDiff => return,
18200                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18201                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18202                    language_settings::SoftWrap::None
18203                }
18204            };
18205            self.soft_wrap_mode_override = Some(soft_wrap);
18206        }
18207        cx.notify();
18208    }
18209
18210    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18211        let Some(workspace) = self.workspace() else {
18212            return;
18213        };
18214        let fs = workspace.read(cx).app_state().fs.clone();
18215        let current_show = TabBarSettings::get_global(cx).show;
18216        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18217            setting.show = Some(!current_show);
18218        });
18219    }
18220
18221    pub fn toggle_indent_guides(
18222        &mut self,
18223        _: &ToggleIndentGuides,
18224        _: &mut Window,
18225        cx: &mut Context<Self>,
18226    ) {
18227        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18228            self.buffer
18229                .read(cx)
18230                .language_settings(cx)
18231                .indent_guides
18232                .enabled
18233        });
18234        self.show_indent_guides = Some(!currently_enabled);
18235        cx.notify();
18236    }
18237
18238    fn should_show_indent_guides(&self) -> Option<bool> {
18239        self.show_indent_guides
18240    }
18241
18242    pub fn toggle_line_numbers(
18243        &mut self,
18244        _: &ToggleLineNumbers,
18245        _: &mut Window,
18246        cx: &mut Context<Self>,
18247    ) {
18248        let mut editor_settings = EditorSettings::get_global(cx).clone();
18249        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18250        EditorSettings::override_global(editor_settings, cx);
18251    }
18252
18253    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18254        if let Some(show_line_numbers) = self.show_line_numbers {
18255            return show_line_numbers;
18256        }
18257        EditorSettings::get_global(cx).gutter.line_numbers
18258    }
18259
18260    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18261        self.use_relative_line_numbers
18262            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18263    }
18264
18265    pub fn toggle_relative_line_numbers(
18266        &mut self,
18267        _: &ToggleRelativeLineNumbers,
18268        _: &mut Window,
18269        cx: &mut Context<Self>,
18270    ) {
18271        let is_relative = self.should_use_relative_line_numbers(cx);
18272        self.set_relative_line_number(Some(!is_relative), cx)
18273    }
18274
18275    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18276        self.use_relative_line_numbers = is_relative;
18277        cx.notify();
18278    }
18279
18280    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18281        self.show_gutter = show_gutter;
18282        cx.notify();
18283    }
18284
18285    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18286        self.show_scrollbars = ScrollbarAxes {
18287            horizontal: show,
18288            vertical: show,
18289        };
18290        cx.notify();
18291    }
18292
18293    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18294        self.show_scrollbars.vertical = show;
18295        cx.notify();
18296    }
18297
18298    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18299        self.show_scrollbars.horizontal = show;
18300        cx.notify();
18301    }
18302
18303    pub fn set_minimap_visibility(
18304        &mut self,
18305        minimap_visibility: MinimapVisibility,
18306        window: &mut Window,
18307        cx: &mut Context<Self>,
18308    ) {
18309        if self.minimap_visibility != minimap_visibility {
18310            if minimap_visibility.visible() && self.minimap.is_none() {
18311                let minimap_settings = EditorSettings::get_global(cx).minimap;
18312                self.minimap =
18313                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18314            }
18315            self.minimap_visibility = minimap_visibility;
18316            cx.notify();
18317        }
18318    }
18319
18320    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18321        self.set_show_scrollbars(false, cx);
18322        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18323    }
18324
18325    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18326        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18327    }
18328
18329    /// Normally the text in full mode and auto height editors is padded on the
18330    /// left side by roughly half a character width for improved hit testing.
18331    ///
18332    /// Use this method to disable this for cases where this is not wanted (e.g.
18333    /// if you want to align the editor text with some other text above or below)
18334    /// or if you want to add this padding to single-line editors.
18335    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18336        self.offset_content = offset_content;
18337        cx.notify();
18338    }
18339
18340    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18341        self.show_line_numbers = Some(show_line_numbers);
18342        cx.notify();
18343    }
18344
18345    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18346        self.disable_expand_excerpt_buttons = true;
18347        cx.notify();
18348    }
18349
18350    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18351        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18352        cx.notify();
18353    }
18354
18355    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18356        self.show_code_actions = Some(show_code_actions);
18357        cx.notify();
18358    }
18359
18360    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18361        self.show_runnables = Some(show_runnables);
18362        cx.notify();
18363    }
18364
18365    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18366        self.show_breakpoints = Some(show_breakpoints);
18367        cx.notify();
18368    }
18369
18370    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18371        if self.display_map.read(cx).masked != masked {
18372            self.display_map.update(cx, |map, _| map.masked = masked);
18373        }
18374        cx.notify()
18375    }
18376
18377    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18378        self.show_wrap_guides = Some(show_wrap_guides);
18379        cx.notify();
18380    }
18381
18382    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18383        self.show_indent_guides = Some(show_indent_guides);
18384        cx.notify();
18385    }
18386
18387    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18388        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18389            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18390                if let Some(dir) = file.abs_path(cx).parent() {
18391                    return Some(dir.to_owned());
18392                }
18393            }
18394
18395            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18396                return Some(project_path.path.to_path_buf());
18397            }
18398        }
18399
18400        None
18401    }
18402
18403    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18404        self.active_excerpt(cx)?
18405            .1
18406            .read(cx)
18407            .file()
18408            .and_then(|f| f.as_local())
18409    }
18410
18411    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18412        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18413            let buffer = buffer.read(cx);
18414            if let Some(project_path) = buffer.project_path(cx) {
18415                let project = self.project.as_ref()?.read(cx);
18416                project.absolute_path(&project_path, cx)
18417            } else {
18418                buffer
18419                    .file()
18420                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18421            }
18422        })
18423    }
18424
18425    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18426        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18427            let project_path = buffer.read(cx).project_path(cx)?;
18428            let project = self.project.as_ref()?.read(cx);
18429            let entry = project.entry_for_path(&project_path, cx)?;
18430            let path = entry.path.to_path_buf();
18431            Some(path)
18432        })
18433    }
18434
18435    pub fn reveal_in_finder(
18436        &mut self,
18437        _: &RevealInFileManager,
18438        _window: &mut Window,
18439        cx: &mut Context<Self>,
18440    ) {
18441        if let Some(target) = self.target_file(cx) {
18442            cx.reveal_path(&target.abs_path(cx));
18443        }
18444    }
18445
18446    pub fn copy_path(
18447        &mut self,
18448        _: &zed_actions::workspace::CopyPath,
18449        _window: &mut Window,
18450        cx: &mut Context<Self>,
18451    ) {
18452        if let Some(path) = self.target_file_abs_path(cx) {
18453            if let Some(path) = path.to_str() {
18454                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18455            }
18456        }
18457    }
18458
18459    pub fn copy_relative_path(
18460        &mut self,
18461        _: &zed_actions::workspace::CopyRelativePath,
18462        _window: &mut Window,
18463        cx: &mut Context<Self>,
18464    ) {
18465        if let Some(path) = self.target_file_path(cx) {
18466            if let Some(path) = path.to_str() {
18467                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18468            }
18469        }
18470    }
18471
18472    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18473        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18474            buffer.read(cx).project_path(cx)
18475        } else {
18476            None
18477        }
18478    }
18479
18480    // Returns true if the editor handled a go-to-line request
18481    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18482        maybe!({
18483            let breakpoint_store = self.breakpoint_store.as_ref()?;
18484
18485            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18486            else {
18487                self.clear_row_highlights::<ActiveDebugLine>();
18488                return None;
18489            };
18490
18491            let position = active_stack_frame.position;
18492            let buffer_id = position.buffer_id?;
18493            let snapshot = self
18494                .project
18495                .as_ref()?
18496                .read(cx)
18497                .buffer_for_id(buffer_id, cx)?
18498                .read(cx)
18499                .snapshot();
18500
18501            let mut handled = false;
18502            for (id, ExcerptRange { context, .. }) in
18503                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18504            {
18505                if context.start.cmp(&position, &snapshot).is_ge()
18506                    || context.end.cmp(&position, &snapshot).is_lt()
18507                {
18508                    continue;
18509                }
18510                let snapshot = self.buffer.read(cx).snapshot(cx);
18511                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18512
18513                handled = true;
18514                self.clear_row_highlights::<ActiveDebugLine>();
18515
18516                self.go_to_line::<ActiveDebugLine>(
18517                    multibuffer_anchor,
18518                    Some(cx.theme().colors().editor_debugger_active_line_background),
18519                    window,
18520                    cx,
18521                );
18522
18523                cx.notify();
18524            }
18525
18526            handled.then_some(())
18527        })
18528        .is_some()
18529    }
18530
18531    pub fn copy_file_name_without_extension(
18532        &mut self,
18533        _: &CopyFileNameWithoutExtension,
18534        _: &mut Window,
18535        cx: &mut Context<Self>,
18536    ) {
18537        if let Some(file) = self.target_file(cx) {
18538            if let Some(file_stem) = file.path().file_stem() {
18539                if let Some(name) = file_stem.to_str() {
18540                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18541                }
18542            }
18543        }
18544    }
18545
18546    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18547        if let Some(file) = self.target_file(cx) {
18548            if let Some(file_name) = file.path().file_name() {
18549                if let Some(name) = file_name.to_str() {
18550                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18551                }
18552            }
18553        }
18554    }
18555
18556    pub fn toggle_git_blame(
18557        &mut self,
18558        _: &::git::Blame,
18559        window: &mut Window,
18560        cx: &mut Context<Self>,
18561    ) {
18562        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18563
18564        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18565            self.start_git_blame(true, window, cx);
18566        }
18567
18568        cx.notify();
18569    }
18570
18571    pub fn toggle_git_blame_inline(
18572        &mut self,
18573        _: &ToggleGitBlameInline,
18574        window: &mut Window,
18575        cx: &mut Context<Self>,
18576    ) {
18577        self.toggle_git_blame_inline_internal(true, window, cx);
18578        cx.notify();
18579    }
18580
18581    pub fn open_git_blame_commit(
18582        &mut self,
18583        _: &OpenGitBlameCommit,
18584        window: &mut Window,
18585        cx: &mut Context<Self>,
18586    ) {
18587        self.open_git_blame_commit_internal(window, cx);
18588    }
18589
18590    fn open_git_blame_commit_internal(
18591        &mut self,
18592        window: &mut Window,
18593        cx: &mut Context<Self>,
18594    ) -> Option<()> {
18595        let blame = self.blame.as_ref()?;
18596        let snapshot = self.snapshot(window, cx);
18597        let cursor = self.selections.newest::<Point>(cx).head();
18598        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18599        let blame_entry = blame
18600            .update(cx, |blame, cx| {
18601                blame
18602                    .blame_for_rows(
18603                        &[RowInfo {
18604                            buffer_id: Some(buffer.remote_id()),
18605                            buffer_row: Some(point.row),
18606                            ..Default::default()
18607                        }],
18608                        cx,
18609                    )
18610                    .next()
18611            })
18612            .flatten()?;
18613        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18614        let repo = blame.read(cx).repository(cx)?;
18615        let workspace = self.workspace()?.downgrade();
18616        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18617        None
18618    }
18619
18620    pub fn git_blame_inline_enabled(&self) -> bool {
18621        self.git_blame_inline_enabled
18622    }
18623
18624    pub fn toggle_selection_menu(
18625        &mut self,
18626        _: &ToggleSelectionMenu,
18627        _: &mut Window,
18628        cx: &mut Context<Self>,
18629    ) {
18630        self.show_selection_menu = self
18631            .show_selection_menu
18632            .map(|show_selections_menu| !show_selections_menu)
18633            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18634
18635        cx.notify();
18636    }
18637
18638    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18639        self.show_selection_menu
18640            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18641    }
18642
18643    fn start_git_blame(
18644        &mut self,
18645        user_triggered: bool,
18646        window: &mut Window,
18647        cx: &mut Context<Self>,
18648    ) {
18649        if let Some(project) = self.project.as_ref() {
18650            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18651                return;
18652            };
18653
18654            if buffer.read(cx).file().is_none() {
18655                return;
18656            }
18657
18658            let focused = self.focus_handle(cx).contains_focused(window, cx);
18659
18660            let project = project.clone();
18661            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18662            self.blame_subscription =
18663                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18664            self.blame = Some(blame);
18665        }
18666    }
18667
18668    fn toggle_git_blame_inline_internal(
18669        &mut self,
18670        user_triggered: bool,
18671        window: &mut Window,
18672        cx: &mut Context<Self>,
18673    ) {
18674        if self.git_blame_inline_enabled {
18675            self.git_blame_inline_enabled = false;
18676            self.show_git_blame_inline = false;
18677            self.show_git_blame_inline_delay_task.take();
18678        } else {
18679            self.git_blame_inline_enabled = true;
18680            self.start_git_blame_inline(user_triggered, window, cx);
18681        }
18682
18683        cx.notify();
18684    }
18685
18686    fn start_git_blame_inline(
18687        &mut self,
18688        user_triggered: bool,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        self.start_git_blame(user_triggered, window, cx);
18693
18694        if ProjectSettings::get_global(cx)
18695            .git
18696            .inline_blame_delay()
18697            .is_some()
18698        {
18699            self.start_inline_blame_timer(window, cx);
18700        } else {
18701            self.show_git_blame_inline = true
18702        }
18703    }
18704
18705    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18706        self.blame.as_ref()
18707    }
18708
18709    pub fn show_git_blame_gutter(&self) -> bool {
18710        self.show_git_blame_gutter
18711    }
18712
18713    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18714        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18715    }
18716
18717    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18718        self.show_git_blame_inline
18719            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18720            && !self.newest_selection_head_on_empty_line(cx)
18721            && self.has_blame_entries(cx)
18722    }
18723
18724    fn has_blame_entries(&self, cx: &App) -> bool {
18725        self.blame()
18726            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18727    }
18728
18729    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18730        let cursor_anchor = self.selections.newest_anchor().head();
18731
18732        let snapshot = self.buffer.read(cx).snapshot(cx);
18733        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18734
18735        snapshot.line_len(buffer_row) == 0
18736    }
18737
18738    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18739        let buffer_and_selection = maybe!({
18740            let selection = self.selections.newest::<Point>(cx);
18741            let selection_range = selection.range();
18742
18743            let multi_buffer = self.buffer().read(cx);
18744            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18745            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18746
18747            let (buffer, range, _) = if selection.reversed {
18748                buffer_ranges.first()
18749            } else {
18750                buffer_ranges.last()
18751            }?;
18752
18753            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18754                ..text::ToPoint::to_point(&range.end, &buffer).row;
18755            Some((
18756                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18757                selection,
18758            ))
18759        });
18760
18761        let Some((buffer, selection)) = buffer_and_selection else {
18762            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18763        };
18764
18765        let Some(project) = self.project.as_ref() else {
18766            return Task::ready(Err(anyhow!("editor does not have project")));
18767        };
18768
18769        project.update(cx, |project, cx| {
18770            project.get_permalink_to_line(&buffer, selection, cx)
18771        })
18772    }
18773
18774    pub fn copy_permalink_to_line(
18775        &mut self,
18776        _: &CopyPermalinkToLine,
18777        window: &mut Window,
18778        cx: &mut Context<Self>,
18779    ) {
18780        let permalink_task = self.get_permalink_to_line(cx);
18781        let workspace = self.workspace();
18782
18783        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18784            Ok(permalink) => {
18785                cx.update(|_, cx| {
18786                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18787                })
18788                .ok();
18789            }
18790            Err(err) => {
18791                let message = format!("Failed to copy permalink: {err}");
18792
18793                anyhow::Result::<()>::Err(err).log_err();
18794
18795                if let Some(workspace) = workspace {
18796                    workspace
18797                        .update_in(cx, |workspace, _, cx| {
18798                            struct CopyPermalinkToLine;
18799
18800                            workspace.show_toast(
18801                                Toast::new(
18802                                    NotificationId::unique::<CopyPermalinkToLine>(),
18803                                    message,
18804                                ),
18805                                cx,
18806                            )
18807                        })
18808                        .ok();
18809                }
18810            }
18811        })
18812        .detach();
18813    }
18814
18815    pub fn copy_file_location(
18816        &mut self,
18817        _: &CopyFileLocation,
18818        _: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18822        if let Some(file) = self.target_file(cx) {
18823            if let Some(path) = file.path().to_str() {
18824                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18825            }
18826        }
18827    }
18828
18829    pub fn open_permalink_to_line(
18830        &mut self,
18831        _: &OpenPermalinkToLine,
18832        window: &mut Window,
18833        cx: &mut Context<Self>,
18834    ) {
18835        let permalink_task = self.get_permalink_to_line(cx);
18836        let workspace = self.workspace();
18837
18838        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18839            Ok(permalink) => {
18840                cx.update(|_, cx| {
18841                    cx.open_url(permalink.as_ref());
18842                })
18843                .ok();
18844            }
18845            Err(err) => {
18846                let message = format!("Failed to open permalink: {err}");
18847
18848                anyhow::Result::<()>::Err(err).log_err();
18849
18850                if let Some(workspace) = workspace {
18851                    workspace
18852                        .update(cx, |workspace, cx| {
18853                            struct OpenPermalinkToLine;
18854
18855                            workspace.show_toast(
18856                                Toast::new(
18857                                    NotificationId::unique::<OpenPermalinkToLine>(),
18858                                    message,
18859                                ),
18860                                cx,
18861                            )
18862                        })
18863                        .ok();
18864                }
18865            }
18866        })
18867        .detach();
18868    }
18869
18870    pub fn insert_uuid_v4(
18871        &mut self,
18872        _: &InsertUuidV4,
18873        window: &mut Window,
18874        cx: &mut Context<Self>,
18875    ) {
18876        self.insert_uuid(UuidVersion::V4, window, cx);
18877    }
18878
18879    pub fn insert_uuid_v7(
18880        &mut self,
18881        _: &InsertUuidV7,
18882        window: &mut Window,
18883        cx: &mut Context<Self>,
18884    ) {
18885        self.insert_uuid(UuidVersion::V7, window, cx);
18886    }
18887
18888    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18890        self.transact(window, cx, |this, window, cx| {
18891            let edits = this
18892                .selections
18893                .all::<Point>(cx)
18894                .into_iter()
18895                .map(|selection| {
18896                    let uuid = match version {
18897                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18898                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18899                    };
18900
18901                    (selection.range(), uuid.to_string())
18902                });
18903            this.edit(edits, cx);
18904            this.refresh_inline_completion(true, false, window, cx);
18905        });
18906    }
18907
18908    pub fn open_selections_in_multibuffer(
18909        &mut self,
18910        _: &OpenSelectionsInMultibuffer,
18911        window: &mut Window,
18912        cx: &mut Context<Self>,
18913    ) {
18914        let multibuffer = self.buffer.read(cx);
18915
18916        let Some(buffer) = multibuffer.as_singleton() else {
18917            return;
18918        };
18919
18920        let Some(workspace) = self.workspace() else {
18921            return;
18922        };
18923
18924        let title = multibuffer.title(cx).to_string();
18925
18926        let locations = self
18927            .selections
18928            .all_anchors(cx)
18929            .into_iter()
18930            .map(|selection| Location {
18931                buffer: buffer.clone(),
18932                range: selection.start.text_anchor..selection.end.text_anchor,
18933            })
18934            .collect::<Vec<_>>();
18935
18936        cx.spawn_in(window, async move |_, cx| {
18937            workspace.update_in(cx, |workspace, window, cx| {
18938                Self::open_locations_in_multibuffer(
18939                    workspace,
18940                    locations,
18941                    format!("Selections for '{title}'"),
18942                    false,
18943                    MultibufferSelectionMode::All,
18944                    window,
18945                    cx,
18946                );
18947            })
18948        })
18949        .detach();
18950    }
18951
18952    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18953    /// last highlight added will be used.
18954    ///
18955    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18956    pub fn highlight_rows<T: 'static>(
18957        &mut self,
18958        range: Range<Anchor>,
18959        color: Hsla,
18960        options: RowHighlightOptions,
18961        cx: &mut Context<Self>,
18962    ) {
18963        let snapshot = self.buffer().read(cx).snapshot(cx);
18964        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18965        let ix = row_highlights.binary_search_by(|highlight| {
18966            Ordering::Equal
18967                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18968                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18969        });
18970
18971        if let Err(mut ix) = ix {
18972            let index = post_inc(&mut self.highlight_order);
18973
18974            // If this range intersects with the preceding highlight, then merge it with
18975            // the preceding highlight. Otherwise insert a new highlight.
18976            let mut merged = false;
18977            if ix > 0 {
18978                let prev_highlight = &mut row_highlights[ix - 1];
18979                if prev_highlight
18980                    .range
18981                    .end
18982                    .cmp(&range.start, &snapshot)
18983                    .is_ge()
18984                {
18985                    ix -= 1;
18986                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18987                        prev_highlight.range.end = range.end;
18988                    }
18989                    merged = true;
18990                    prev_highlight.index = index;
18991                    prev_highlight.color = color;
18992                    prev_highlight.options = options;
18993                }
18994            }
18995
18996            if !merged {
18997                row_highlights.insert(
18998                    ix,
18999                    RowHighlight {
19000                        range: range.clone(),
19001                        index,
19002                        color,
19003                        options,
19004                        type_id: TypeId::of::<T>(),
19005                    },
19006                );
19007            }
19008
19009            // If any of the following highlights intersect with this one, merge them.
19010            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19011                let highlight = &row_highlights[ix];
19012                if next_highlight
19013                    .range
19014                    .start
19015                    .cmp(&highlight.range.end, &snapshot)
19016                    .is_le()
19017                {
19018                    if next_highlight
19019                        .range
19020                        .end
19021                        .cmp(&highlight.range.end, &snapshot)
19022                        .is_gt()
19023                    {
19024                        row_highlights[ix].range.end = next_highlight.range.end;
19025                    }
19026                    row_highlights.remove(ix + 1);
19027                } else {
19028                    break;
19029                }
19030            }
19031        }
19032    }
19033
19034    /// Remove any highlighted row ranges of the given type that intersect the
19035    /// given ranges.
19036    pub fn remove_highlighted_rows<T: 'static>(
19037        &mut self,
19038        ranges_to_remove: Vec<Range<Anchor>>,
19039        cx: &mut Context<Self>,
19040    ) {
19041        let snapshot = self.buffer().read(cx).snapshot(cx);
19042        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19043        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19044        row_highlights.retain(|highlight| {
19045            while let Some(range_to_remove) = ranges_to_remove.peek() {
19046                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19047                    Ordering::Less | Ordering::Equal => {
19048                        ranges_to_remove.next();
19049                    }
19050                    Ordering::Greater => {
19051                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19052                            Ordering::Less | Ordering::Equal => {
19053                                return false;
19054                            }
19055                            Ordering::Greater => break,
19056                        }
19057                    }
19058                }
19059            }
19060
19061            true
19062        })
19063    }
19064
19065    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19066    pub fn clear_row_highlights<T: 'static>(&mut self) {
19067        self.highlighted_rows.remove(&TypeId::of::<T>());
19068    }
19069
19070    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19071    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19072        self.highlighted_rows
19073            .get(&TypeId::of::<T>())
19074            .map_or(&[] as &[_], |vec| vec.as_slice())
19075            .iter()
19076            .map(|highlight| (highlight.range.clone(), highlight.color))
19077    }
19078
19079    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19080    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19081    /// Allows to ignore certain kinds of highlights.
19082    pub fn highlighted_display_rows(
19083        &self,
19084        window: &mut Window,
19085        cx: &mut App,
19086    ) -> BTreeMap<DisplayRow, LineHighlight> {
19087        let snapshot = self.snapshot(window, cx);
19088        let mut used_highlight_orders = HashMap::default();
19089        self.highlighted_rows
19090            .iter()
19091            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19092            .fold(
19093                BTreeMap::<DisplayRow, LineHighlight>::new(),
19094                |mut unique_rows, highlight| {
19095                    let start = highlight.range.start.to_display_point(&snapshot);
19096                    let end = highlight.range.end.to_display_point(&snapshot);
19097                    let start_row = start.row().0;
19098                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19099                        && end.column() == 0
19100                    {
19101                        end.row().0.saturating_sub(1)
19102                    } else {
19103                        end.row().0
19104                    };
19105                    for row in start_row..=end_row {
19106                        let used_index =
19107                            used_highlight_orders.entry(row).or_insert(highlight.index);
19108                        if highlight.index >= *used_index {
19109                            *used_index = highlight.index;
19110                            unique_rows.insert(
19111                                DisplayRow(row),
19112                                LineHighlight {
19113                                    include_gutter: highlight.options.include_gutter,
19114                                    border: None,
19115                                    background: highlight.color.into(),
19116                                    type_id: Some(highlight.type_id),
19117                                },
19118                            );
19119                        }
19120                    }
19121                    unique_rows
19122                },
19123            )
19124    }
19125
19126    pub fn highlighted_display_row_for_autoscroll(
19127        &self,
19128        snapshot: &DisplaySnapshot,
19129    ) -> Option<DisplayRow> {
19130        self.highlighted_rows
19131            .values()
19132            .flat_map(|highlighted_rows| highlighted_rows.iter())
19133            .filter_map(|highlight| {
19134                if highlight.options.autoscroll {
19135                    Some(highlight.range.start.to_display_point(snapshot).row())
19136                } else {
19137                    None
19138                }
19139            })
19140            .min()
19141    }
19142
19143    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19144        self.highlight_background::<SearchWithinRange>(
19145            ranges,
19146            |colors| colors.colors().editor_document_highlight_read_background,
19147            cx,
19148        )
19149    }
19150
19151    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19152        self.breadcrumb_header = Some(new_header);
19153    }
19154
19155    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19156        self.clear_background_highlights::<SearchWithinRange>(cx);
19157    }
19158
19159    pub fn highlight_background<T: 'static>(
19160        &mut self,
19161        ranges: &[Range<Anchor>],
19162        color_fetcher: fn(&Theme) -> Hsla,
19163        cx: &mut Context<Self>,
19164    ) {
19165        self.background_highlights.insert(
19166            HighlightKey::Type(TypeId::of::<T>()),
19167            (color_fetcher, Arc::from(ranges)),
19168        );
19169        self.scrollbar_marker_state.dirty = true;
19170        cx.notify();
19171    }
19172
19173    pub fn highlight_background_key<T: 'static>(
19174        &mut self,
19175        key: usize,
19176        ranges: &[Range<Anchor>],
19177        color_fetcher: fn(&Theme) -> Hsla,
19178        cx: &mut Context<Self>,
19179    ) {
19180        self.background_highlights.insert(
19181            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19182            (color_fetcher, Arc::from(ranges)),
19183        );
19184        self.scrollbar_marker_state.dirty = true;
19185        cx.notify();
19186    }
19187
19188    pub fn clear_background_highlights<T: 'static>(
19189        &mut self,
19190        cx: &mut Context<Self>,
19191    ) -> Option<BackgroundHighlight> {
19192        let text_highlights = self
19193            .background_highlights
19194            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19195        if !text_highlights.1.is_empty() {
19196            self.scrollbar_marker_state.dirty = true;
19197            cx.notify();
19198        }
19199        Some(text_highlights)
19200    }
19201
19202    pub fn highlight_gutter<T: 'static>(
19203        &mut self,
19204        ranges: impl Into<Vec<Range<Anchor>>>,
19205        color_fetcher: fn(&App) -> Hsla,
19206        cx: &mut Context<Self>,
19207    ) {
19208        self.gutter_highlights
19209            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19210        cx.notify();
19211    }
19212
19213    pub fn clear_gutter_highlights<T: 'static>(
19214        &mut self,
19215        cx: &mut Context<Self>,
19216    ) -> Option<GutterHighlight> {
19217        cx.notify();
19218        self.gutter_highlights.remove(&TypeId::of::<T>())
19219    }
19220
19221    pub fn insert_gutter_highlight<T: 'static>(
19222        &mut self,
19223        range: Range<Anchor>,
19224        color_fetcher: fn(&App) -> Hsla,
19225        cx: &mut Context<Self>,
19226    ) {
19227        let snapshot = self.buffer().read(cx).snapshot(cx);
19228        let mut highlights = self
19229            .gutter_highlights
19230            .remove(&TypeId::of::<T>())
19231            .map(|(_, highlights)| highlights)
19232            .unwrap_or_default();
19233        let ix = highlights.binary_search_by(|highlight| {
19234            Ordering::Equal
19235                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19236                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19237        });
19238        if let Err(ix) = ix {
19239            highlights.insert(ix, range);
19240        }
19241        self.gutter_highlights
19242            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19243    }
19244
19245    pub fn remove_gutter_highlights<T: 'static>(
19246        &mut self,
19247        ranges_to_remove: Vec<Range<Anchor>>,
19248        cx: &mut Context<Self>,
19249    ) {
19250        let snapshot = self.buffer().read(cx).snapshot(cx);
19251        let Some((color_fetcher, mut gutter_highlights)) =
19252            self.gutter_highlights.remove(&TypeId::of::<T>())
19253        else {
19254            return;
19255        };
19256        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19257        gutter_highlights.retain(|highlight| {
19258            while let Some(range_to_remove) = ranges_to_remove.peek() {
19259                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19260                    Ordering::Less | Ordering::Equal => {
19261                        ranges_to_remove.next();
19262                    }
19263                    Ordering::Greater => {
19264                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19265                            Ordering::Less | Ordering::Equal => {
19266                                return false;
19267                            }
19268                            Ordering::Greater => break,
19269                        }
19270                    }
19271                }
19272            }
19273
19274            true
19275        });
19276        self.gutter_highlights
19277            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19278    }
19279
19280    #[cfg(feature = "test-support")]
19281    pub fn all_text_highlights(
19282        &self,
19283        window: &mut Window,
19284        cx: &mut Context<Self>,
19285    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19286        let snapshot = self.snapshot(window, cx);
19287        self.display_map.update(cx, |display_map, _| {
19288            display_map
19289                .all_text_highlights()
19290                .map(|highlight| {
19291                    let (style, ranges) = highlight.as_ref();
19292                    (
19293                        *style,
19294                        ranges
19295                            .iter()
19296                            .map(|range| range.clone().to_display_points(&snapshot))
19297                            .collect(),
19298                    )
19299                })
19300                .collect()
19301        })
19302    }
19303
19304    #[cfg(feature = "test-support")]
19305    pub fn all_text_background_highlights(
19306        &self,
19307        window: &mut Window,
19308        cx: &mut Context<Self>,
19309    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19310        let snapshot = self.snapshot(window, cx);
19311        let buffer = &snapshot.buffer_snapshot;
19312        let start = buffer.anchor_before(0);
19313        let end = buffer.anchor_after(buffer.len());
19314        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19315    }
19316
19317    #[cfg(feature = "test-support")]
19318    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19319        let snapshot = self.buffer().read(cx).snapshot(cx);
19320
19321        let highlights = self
19322            .background_highlights
19323            .get(&HighlightKey::Type(TypeId::of::<
19324                items::BufferSearchHighlights,
19325            >()));
19326
19327        if let Some((_color, ranges)) = highlights {
19328            ranges
19329                .iter()
19330                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19331                .collect_vec()
19332        } else {
19333            vec![]
19334        }
19335    }
19336
19337    fn document_highlights_for_position<'a>(
19338        &'a self,
19339        position: Anchor,
19340        buffer: &'a MultiBufferSnapshot,
19341    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19342        let read_highlights = self
19343            .background_highlights
19344            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19345            .map(|h| &h.1);
19346        let write_highlights = self
19347            .background_highlights
19348            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19349            .map(|h| &h.1);
19350        let left_position = position.bias_left(buffer);
19351        let right_position = position.bias_right(buffer);
19352        read_highlights
19353            .into_iter()
19354            .chain(write_highlights)
19355            .flat_map(move |ranges| {
19356                let start_ix = match ranges.binary_search_by(|probe| {
19357                    let cmp = probe.end.cmp(&left_position, buffer);
19358                    if cmp.is_ge() {
19359                        Ordering::Greater
19360                    } else {
19361                        Ordering::Less
19362                    }
19363                }) {
19364                    Ok(i) | Err(i) => i,
19365                };
19366
19367                ranges[start_ix..]
19368                    .iter()
19369                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19370            })
19371    }
19372
19373    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19374        self.background_highlights
19375            .get(&HighlightKey::Type(TypeId::of::<T>()))
19376            .map_or(false, |(_, highlights)| !highlights.is_empty())
19377    }
19378
19379    pub fn background_highlights_in_range(
19380        &self,
19381        search_range: Range<Anchor>,
19382        display_snapshot: &DisplaySnapshot,
19383        theme: &Theme,
19384    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19385        let mut results = Vec::new();
19386        for (color_fetcher, ranges) in self.background_highlights.values() {
19387            let color = color_fetcher(theme);
19388            let start_ix = match ranges.binary_search_by(|probe| {
19389                let cmp = probe
19390                    .end
19391                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19392                if cmp.is_gt() {
19393                    Ordering::Greater
19394                } else {
19395                    Ordering::Less
19396                }
19397            }) {
19398                Ok(i) | Err(i) => i,
19399            };
19400            for range in &ranges[start_ix..] {
19401                if range
19402                    .start
19403                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19404                    .is_ge()
19405                {
19406                    break;
19407                }
19408
19409                let start = range.start.to_display_point(display_snapshot);
19410                let end = range.end.to_display_point(display_snapshot);
19411                results.push((start..end, color))
19412            }
19413        }
19414        results
19415    }
19416
19417    pub fn background_highlight_row_ranges<T: 'static>(
19418        &self,
19419        search_range: Range<Anchor>,
19420        display_snapshot: &DisplaySnapshot,
19421        count: usize,
19422    ) -> Vec<RangeInclusive<DisplayPoint>> {
19423        let mut results = Vec::new();
19424        let Some((_, ranges)) = self
19425            .background_highlights
19426            .get(&HighlightKey::Type(TypeId::of::<T>()))
19427        else {
19428            return vec![];
19429        };
19430
19431        let start_ix = match ranges.binary_search_by(|probe| {
19432            let cmp = probe
19433                .end
19434                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19435            if cmp.is_gt() {
19436                Ordering::Greater
19437            } else {
19438                Ordering::Less
19439            }
19440        }) {
19441            Ok(i) | Err(i) => i,
19442        };
19443        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19444            if let (Some(start_display), Some(end_display)) = (start, end) {
19445                results.push(
19446                    start_display.to_display_point(display_snapshot)
19447                        ..=end_display.to_display_point(display_snapshot),
19448                );
19449            }
19450        };
19451        let mut start_row: Option<Point> = None;
19452        let mut end_row: Option<Point> = None;
19453        if ranges.len() > count {
19454            return Vec::new();
19455        }
19456        for range in &ranges[start_ix..] {
19457            if range
19458                .start
19459                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19460                .is_ge()
19461            {
19462                break;
19463            }
19464            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19465            if let Some(current_row) = &end_row {
19466                if end.row == current_row.row {
19467                    continue;
19468                }
19469            }
19470            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19471            if start_row.is_none() {
19472                assert_eq!(end_row, None);
19473                start_row = Some(start);
19474                end_row = Some(end);
19475                continue;
19476            }
19477            if let Some(current_end) = end_row.as_mut() {
19478                if start.row > current_end.row + 1 {
19479                    push_region(start_row, end_row);
19480                    start_row = Some(start);
19481                    end_row = Some(end);
19482                } else {
19483                    // Merge two hunks.
19484                    *current_end = end;
19485                }
19486            } else {
19487                unreachable!();
19488            }
19489        }
19490        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19491        push_region(start_row, end_row);
19492        results
19493    }
19494
19495    pub fn gutter_highlights_in_range(
19496        &self,
19497        search_range: Range<Anchor>,
19498        display_snapshot: &DisplaySnapshot,
19499        cx: &App,
19500    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19501        let mut results = Vec::new();
19502        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19503            let color = color_fetcher(cx);
19504            let start_ix = match ranges.binary_search_by(|probe| {
19505                let cmp = probe
19506                    .end
19507                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19508                if cmp.is_gt() {
19509                    Ordering::Greater
19510                } else {
19511                    Ordering::Less
19512                }
19513            }) {
19514                Ok(i) | Err(i) => i,
19515            };
19516            for range in &ranges[start_ix..] {
19517                if range
19518                    .start
19519                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19520                    .is_ge()
19521                {
19522                    break;
19523                }
19524
19525                let start = range.start.to_display_point(display_snapshot);
19526                let end = range.end.to_display_point(display_snapshot);
19527                results.push((start..end, color))
19528            }
19529        }
19530        results
19531    }
19532
19533    /// Get the text ranges corresponding to the redaction query
19534    pub fn redacted_ranges(
19535        &self,
19536        search_range: Range<Anchor>,
19537        display_snapshot: &DisplaySnapshot,
19538        cx: &App,
19539    ) -> Vec<Range<DisplayPoint>> {
19540        display_snapshot
19541            .buffer_snapshot
19542            .redacted_ranges(search_range, |file| {
19543                if let Some(file) = file {
19544                    file.is_private()
19545                        && EditorSettings::get(
19546                            Some(SettingsLocation {
19547                                worktree_id: file.worktree_id(cx),
19548                                path: file.path().as_ref(),
19549                            }),
19550                            cx,
19551                        )
19552                        .redact_private_values
19553                } else {
19554                    false
19555                }
19556            })
19557            .map(|range| {
19558                range.start.to_display_point(display_snapshot)
19559                    ..range.end.to_display_point(display_snapshot)
19560            })
19561            .collect()
19562    }
19563
19564    pub fn highlight_text_key<T: 'static>(
19565        &mut self,
19566        key: usize,
19567        ranges: Vec<Range<Anchor>>,
19568        style: HighlightStyle,
19569        cx: &mut Context<Self>,
19570    ) {
19571        self.display_map.update(cx, |map, _| {
19572            map.highlight_text(
19573                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19574                ranges,
19575                style,
19576            );
19577        });
19578        cx.notify();
19579    }
19580
19581    pub fn highlight_text<T: 'static>(
19582        &mut self,
19583        ranges: Vec<Range<Anchor>>,
19584        style: HighlightStyle,
19585        cx: &mut Context<Self>,
19586    ) {
19587        self.display_map.update(cx, |map, _| {
19588            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19589        });
19590        cx.notify();
19591    }
19592
19593    pub(crate) fn highlight_inlays<T: 'static>(
19594        &mut self,
19595        highlights: Vec<InlayHighlight>,
19596        style: HighlightStyle,
19597        cx: &mut Context<Self>,
19598    ) {
19599        self.display_map.update(cx, |map, _| {
19600            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19601        });
19602        cx.notify();
19603    }
19604
19605    pub fn text_highlights<'a, T: 'static>(
19606        &'a self,
19607        cx: &'a App,
19608    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19609        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19610    }
19611
19612    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19613        let cleared = self
19614            .display_map
19615            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19616        if cleared {
19617            cx.notify();
19618        }
19619    }
19620
19621    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19622        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19623            && self.focus_handle.is_focused(window)
19624    }
19625
19626    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19627        self.show_cursor_when_unfocused = is_enabled;
19628        cx.notify();
19629    }
19630
19631    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19632        cx.notify();
19633    }
19634
19635    fn on_debug_session_event(
19636        &mut self,
19637        _session: Entity<Session>,
19638        event: &SessionEvent,
19639        cx: &mut Context<Self>,
19640    ) {
19641        match event {
19642            SessionEvent::InvalidateInlineValue => {
19643                self.refresh_inline_values(cx);
19644            }
19645            _ => {}
19646        }
19647    }
19648
19649    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19650        let Some(project) = self.project.clone() else {
19651            return;
19652        };
19653
19654        if !self.inline_value_cache.enabled {
19655            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19656            self.splice_inlays(&inlays, Vec::new(), cx);
19657            return;
19658        }
19659
19660        let current_execution_position = self
19661            .highlighted_rows
19662            .get(&TypeId::of::<ActiveDebugLine>())
19663            .and_then(|lines| lines.last().map(|line| line.range.end));
19664
19665        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19666            let inline_values = editor
19667                .update(cx, |editor, cx| {
19668                    let Some(current_execution_position) = current_execution_position else {
19669                        return Some(Task::ready(Ok(Vec::new())));
19670                    };
19671
19672                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19673                        let snapshot = buffer.snapshot(cx);
19674
19675                        let excerpt = snapshot.excerpt_containing(
19676                            current_execution_position..current_execution_position,
19677                        )?;
19678
19679                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19680                    })?;
19681
19682                    let range =
19683                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19684
19685                    project.inline_values(buffer, range, cx)
19686                })
19687                .ok()
19688                .flatten()?
19689                .await
19690                .context("refreshing debugger inlays")
19691                .log_err()?;
19692
19693            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19694
19695            for (buffer_id, inline_value) in inline_values
19696                .into_iter()
19697                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19698            {
19699                buffer_inline_values
19700                    .entry(buffer_id)
19701                    .or_default()
19702                    .push(inline_value);
19703            }
19704
19705            editor
19706                .update(cx, |editor, cx| {
19707                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19708                    let mut new_inlays = Vec::default();
19709
19710                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19711                        let buffer_id = buffer_snapshot.remote_id();
19712                        buffer_inline_values
19713                            .get(&buffer_id)
19714                            .into_iter()
19715                            .flatten()
19716                            .for_each(|hint| {
19717                                let inlay = Inlay::debugger(
19718                                    post_inc(&mut editor.next_inlay_id),
19719                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19720                                    hint.text(),
19721                                );
19722                                if !inlay.text.chars().contains(&'\n') {
19723                                    new_inlays.push(inlay);
19724                                }
19725                            });
19726                    }
19727
19728                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19729                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19730
19731                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19732                })
19733                .ok()?;
19734            Some(())
19735        });
19736    }
19737
19738    fn on_buffer_event(
19739        &mut self,
19740        multibuffer: &Entity<MultiBuffer>,
19741        event: &multi_buffer::Event,
19742        window: &mut Window,
19743        cx: &mut Context<Self>,
19744    ) {
19745        match event {
19746            multi_buffer::Event::Edited {
19747                singleton_buffer_edited,
19748                edited_buffer,
19749            } => {
19750                self.scrollbar_marker_state.dirty = true;
19751                self.active_indent_guides_state.dirty = true;
19752                self.refresh_active_diagnostics(cx);
19753                self.refresh_code_actions(window, cx);
19754                self.refresh_selected_text_highlights(true, window, cx);
19755                self.refresh_single_line_folds(window, cx);
19756                refresh_matching_bracket_highlights(self, window, cx);
19757                if self.has_active_inline_completion() {
19758                    self.update_visible_inline_completion(window, cx);
19759                }
19760                if let Some(project) = self.project.as_ref() {
19761                    if let Some(edited_buffer) = edited_buffer {
19762                        project.update(cx, |project, cx| {
19763                            self.registered_buffers
19764                                .entry(edited_buffer.read(cx).remote_id())
19765                                .or_insert_with(|| {
19766                                    project
19767                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19768                                });
19769                        });
19770                    }
19771                }
19772                cx.emit(EditorEvent::BufferEdited);
19773                cx.emit(SearchEvent::MatchesInvalidated);
19774
19775                if let Some(buffer) = edited_buffer {
19776                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19777                }
19778
19779                if *singleton_buffer_edited {
19780                    if let Some(buffer) = edited_buffer {
19781                        if buffer.read(cx).file().is_none() {
19782                            cx.emit(EditorEvent::TitleChanged);
19783                        }
19784                    }
19785                    if let Some(project) = &self.project {
19786                        #[allow(clippy::mutable_key_type)]
19787                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19788                            multibuffer
19789                                .all_buffers()
19790                                .into_iter()
19791                                .filter_map(|buffer| {
19792                                    buffer.update(cx, |buffer, cx| {
19793                                        let language = buffer.language()?;
19794                                        let should_discard = project.update(cx, |project, cx| {
19795                                            project.is_local()
19796                                                && !project.has_language_servers_for(buffer, cx)
19797                                        });
19798                                        should_discard.not().then_some(language.clone())
19799                                    })
19800                                })
19801                                .collect::<HashSet<_>>()
19802                        });
19803                        if !languages_affected.is_empty() {
19804                            self.refresh_inlay_hints(
19805                                InlayHintRefreshReason::BufferEdited(languages_affected),
19806                                cx,
19807                            );
19808                        }
19809                    }
19810                }
19811
19812                let Some(project) = &self.project else { return };
19813                let (telemetry, is_via_ssh) = {
19814                    let project = project.read(cx);
19815                    let telemetry = project.client().telemetry().clone();
19816                    let is_via_ssh = project.is_via_ssh();
19817                    (telemetry, is_via_ssh)
19818                };
19819                refresh_linked_ranges(self, window, cx);
19820                telemetry.log_edit_event("editor", is_via_ssh);
19821            }
19822            multi_buffer::Event::ExcerptsAdded {
19823                buffer,
19824                predecessor,
19825                excerpts,
19826            } => {
19827                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19828                let buffer_id = buffer.read(cx).remote_id();
19829                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19830                    if let Some(project) = &self.project {
19831                        update_uncommitted_diff_for_buffer(
19832                            cx.entity(),
19833                            project,
19834                            [buffer.clone()],
19835                            self.buffer.clone(),
19836                            cx,
19837                        )
19838                        .detach();
19839                    }
19840                }
19841                self.update_lsp_data(false, Some(buffer_id), window, cx);
19842                cx.emit(EditorEvent::ExcerptsAdded {
19843                    buffer: buffer.clone(),
19844                    predecessor: *predecessor,
19845                    excerpts: excerpts.clone(),
19846                });
19847                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19848            }
19849            multi_buffer::Event::ExcerptsRemoved {
19850                ids,
19851                removed_buffer_ids,
19852            } => {
19853                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19854                let buffer = self.buffer.read(cx);
19855                self.registered_buffers
19856                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19857                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19858                cx.emit(EditorEvent::ExcerptsRemoved {
19859                    ids: ids.clone(),
19860                    removed_buffer_ids: removed_buffer_ids.clone(),
19861                });
19862            }
19863            multi_buffer::Event::ExcerptsEdited {
19864                excerpt_ids,
19865                buffer_ids,
19866            } => {
19867                self.display_map.update(cx, |map, cx| {
19868                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19869                });
19870                cx.emit(EditorEvent::ExcerptsEdited {
19871                    ids: excerpt_ids.clone(),
19872                });
19873            }
19874            multi_buffer::Event::ExcerptsExpanded { ids } => {
19875                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19876                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19877            }
19878            multi_buffer::Event::Reparsed(buffer_id) => {
19879                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19880                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19881
19882                cx.emit(EditorEvent::Reparsed(*buffer_id));
19883            }
19884            multi_buffer::Event::DiffHunksToggled => {
19885                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19886            }
19887            multi_buffer::Event::LanguageChanged(buffer_id) => {
19888                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19889                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19890                cx.emit(EditorEvent::Reparsed(*buffer_id));
19891                cx.notify();
19892            }
19893            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19894            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19895            multi_buffer::Event::FileHandleChanged
19896            | multi_buffer::Event::Reloaded
19897            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19898            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19899            multi_buffer::Event::DiagnosticsUpdated => {
19900                self.update_diagnostics_state(window, cx);
19901            }
19902            _ => {}
19903        };
19904    }
19905
19906    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19907        if !self.diagnostics_enabled() {
19908            return;
19909        }
19910        self.refresh_active_diagnostics(cx);
19911        self.refresh_inline_diagnostics(true, window, cx);
19912        self.scrollbar_marker_state.dirty = true;
19913        cx.notify();
19914    }
19915
19916    pub fn start_temporary_diff_override(&mut self) {
19917        self.load_diff_task.take();
19918        self.temporary_diff_override = true;
19919    }
19920
19921    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19922        self.temporary_diff_override = false;
19923        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19924        self.buffer.update(cx, |buffer, cx| {
19925            buffer.set_all_diff_hunks_collapsed(cx);
19926        });
19927
19928        if let Some(project) = self.project.clone() {
19929            self.load_diff_task = Some(
19930                update_uncommitted_diff_for_buffer(
19931                    cx.entity(),
19932                    &project,
19933                    self.buffer.read(cx).all_buffers(),
19934                    self.buffer.clone(),
19935                    cx,
19936                )
19937                .shared(),
19938            );
19939        }
19940    }
19941
19942    fn on_display_map_changed(
19943        &mut self,
19944        _: Entity<DisplayMap>,
19945        _: &mut Window,
19946        cx: &mut Context<Self>,
19947    ) {
19948        cx.notify();
19949    }
19950
19951    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19952        if self.diagnostics_enabled() {
19953            let new_severity = EditorSettings::get_global(cx)
19954                .diagnostics_max_severity
19955                .unwrap_or(DiagnosticSeverity::Hint);
19956            self.set_max_diagnostics_severity(new_severity, cx);
19957        }
19958        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19959        self.update_edit_prediction_settings(cx);
19960        self.refresh_inline_completion(true, false, window, cx);
19961        self.refresh_inline_values(cx);
19962        self.refresh_inlay_hints(
19963            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19964                self.selections.newest_anchor().head(),
19965                &self.buffer.read(cx).snapshot(cx),
19966                cx,
19967            )),
19968            cx,
19969        );
19970
19971        let old_cursor_shape = self.cursor_shape;
19972
19973        {
19974            let editor_settings = EditorSettings::get_global(cx);
19975            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19976            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19977            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19978            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19979        }
19980
19981        if old_cursor_shape != self.cursor_shape {
19982            cx.emit(EditorEvent::CursorShapeChanged);
19983        }
19984
19985        let project_settings = ProjectSettings::get_global(cx);
19986        self.serialize_dirty_buffers =
19987            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19988
19989        if self.mode.is_full() {
19990            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19991            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19992            if self.show_inline_diagnostics != show_inline_diagnostics {
19993                self.show_inline_diagnostics = show_inline_diagnostics;
19994                self.refresh_inline_diagnostics(false, window, cx);
19995            }
19996
19997            if self.git_blame_inline_enabled != inline_blame_enabled {
19998                self.toggle_git_blame_inline_internal(false, window, cx);
19999            }
20000
20001            let minimap_settings = EditorSettings::get_global(cx).minimap;
20002            if self.minimap_visibility != MinimapVisibility::Disabled {
20003                if self.minimap_visibility.settings_visibility()
20004                    != minimap_settings.minimap_enabled()
20005                {
20006                    self.set_minimap_visibility(
20007                        MinimapVisibility::for_mode(self.mode(), cx),
20008                        window,
20009                        cx,
20010                    );
20011                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20012                    minimap_entity.update(cx, |minimap_editor, cx| {
20013                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20014                    })
20015                }
20016            }
20017        }
20018
20019        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20020            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20021        }) {
20022            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20023                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20024            }
20025            self.refresh_colors(false, None, window, cx);
20026        }
20027
20028        cx.notify();
20029    }
20030
20031    pub fn set_searchable(&mut self, searchable: bool) {
20032        self.searchable = searchable;
20033    }
20034
20035    pub fn searchable(&self) -> bool {
20036        self.searchable
20037    }
20038
20039    fn open_proposed_changes_editor(
20040        &mut self,
20041        _: &OpenProposedChangesEditor,
20042        window: &mut Window,
20043        cx: &mut Context<Self>,
20044    ) {
20045        let Some(workspace) = self.workspace() else {
20046            cx.propagate();
20047            return;
20048        };
20049
20050        let selections = self.selections.all::<usize>(cx);
20051        let multi_buffer = self.buffer.read(cx);
20052        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20053        let mut new_selections_by_buffer = HashMap::default();
20054        for selection in selections {
20055            for (buffer, range, _) in
20056                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20057            {
20058                let mut range = range.to_point(buffer);
20059                range.start.column = 0;
20060                range.end.column = buffer.line_len(range.end.row);
20061                new_selections_by_buffer
20062                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20063                    .or_insert(Vec::new())
20064                    .push(range)
20065            }
20066        }
20067
20068        let proposed_changes_buffers = new_selections_by_buffer
20069            .into_iter()
20070            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20071            .collect::<Vec<_>>();
20072        let proposed_changes_editor = cx.new(|cx| {
20073            ProposedChangesEditor::new(
20074                "Proposed changes",
20075                proposed_changes_buffers,
20076                self.project.clone(),
20077                window,
20078                cx,
20079            )
20080        });
20081
20082        window.defer(cx, move |window, cx| {
20083            workspace.update(cx, |workspace, cx| {
20084                workspace.active_pane().update(cx, |pane, cx| {
20085                    pane.add_item(
20086                        Box::new(proposed_changes_editor),
20087                        true,
20088                        true,
20089                        None,
20090                        window,
20091                        cx,
20092                    );
20093                });
20094            });
20095        });
20096    }
20097
20098    pub fn open_excerpts_in_split(
20099        &mut self,
20100        _: &OpenExcerptsSplit,
20101        window: &mut Window,
20102        cx: &mut Context<Self>,
20103    ) {
20104        self.open_excerpts_common(None, true, window, cx)
20105    }
20106
20107    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20108        self.open_excerpts_common(None, false, window, cx)
20109    }
20110
20111    fn open_excerpts_common(
20112        &mut self,
20113        jump_data: Option<JumpData>,
20114        split: bool,
20115        window: &mut Window,
20116        cx: &mut Context<Self>,
20117    ) {
20118        let Some(workspace) = self.workspace() else {
20119            cx.propagate();
20120            return;
20121        };
20122
20123        if self.buffer.read(cx).is_singleton() {
20124            cx.propagate();
20125            return;
20126        }
20127
20128        let mut new_selections_by_buffer = HashMap::default();
20129        match &jump_data {
20130            Some(JumpData::MultiBufferPoint {
20131                excerpt_id,
20132                position,
20133                anchor,
20134                line_offset_from_top,
20135            }) => {
20136                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20137                if let Some(buffer) = multi_buffer_snapshot
20138                    .buffer_id_for_excerpt(*excerpt_id)
20139                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20140                {
20141                    let buffer_snapshot = buffer.read(cx).snapshot();
20142                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20143                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20144                    } else {
20145                        buffer_snapshot.clip_point(*position, Bias::Left)
20146                    };
20147                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20148                    new_selections_by_buffer.insert(
20149                        buffer,
20150                        (
20151                            vec![jump_to_offset..jump_to_offset],
20152                            Some(*line_offset_from_top),
20153                        ),
20154                    );
20155                }
20156            }
20157            Some(JumpData::MultiBufferRow {
20158                row,
20159                line_offset_from_top,
20160            }) => {
20161                let point = MultiBufferPoint::new(row.0, 0);
20162                if let Some((buffer, buffer_point, _)) =
20163                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20164                {
20165                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20166                    new_selections_by_buffer
20167                        .entry(buffer)
20168                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20169                        .0
20170                        .push(buffer_offset..buffer_offset)
20171                }
20172            }
20173            None => {
20174                let selections = self.selections.all::<usize>(cx);
20175                let multi_buffer = self.buffer.read(cx);
20176                for selection in selections {
20177                    for (snapshot, range, _, anchor) in multi_buffer
20178                        .snapshot(cx)
20179                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20180                    {
20181                        if let Some(anchor) = anchor {
20182                            // selection is in a deleted hunk
20183                            let Some(buffer_id) = anchor.buffer_id else {
20184                                continue;
20185                            };
20186                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20187                                continue;
20188                            };
20189                            let offset = text::ToOffset::to_offset(
20190                                &anchor.text_anchor,
20191                                &buffer_handle.read(cx).snapshot(),
20192                            );
20193                            let range = offset..offset;
20194                            new_selections_by_buffer
20195                                .entry(buffer_handle)
20196                                .or_insert((Vec::new(), None))
20197                                .0
20198                                .push(range)
20199                        } else {
20200                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20201                            else {
20202                                continue;
20203                            };
20204                            new_selections_by_buffer
20205                                .entry(buffer_handle)
20206                                .or_insert((Vec::new(), None))
20207                                .0
20208                                .push(range)
20209                        }
20210                    }
20211                }
20212            }
20213        }
20214
20215        new_selections_by_buffer
20216            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20217
20218        if new_selections_by_buffer.is_empty() {
20219            return;
20220        }
20221
20222        // We defer the pane interaction because we ourselves are a workspace item
20223        // and activating a new item causes the pane to call a method on us reentrantly,
20224        // which panics if we're on the stack.
20225        window.defer(cx, move |window, cx| {
20226            workspace.update(cx, |workspace, cx| {
20227                let pane = if split {
20228                    workspace.adjacent_pane(window, cx)
20229                } else {
20230                    workspace.active_pane().clone()
20231                };
20232
20233                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20234                    let editor = buffer
20235                        .read(cx)
20236                        .file()
20237                        .is_none()
20238                        .then(|| {
20239                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20240                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20241                            // Instead, we try to activate the existing editor in the pane first.
20242                            let (editor, pane_item_index) =
20243                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20244                                    let editor = item.downcast::<Editor>()?;
20245                                    let singleton_buffer =
20246                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20247                                    if singleton_buffer == buffer {
20248                                        Some((editor, i))
20249                                    } else {
20250                                        None
20251                                    }
20252                                })?;
20253                            pane.update(cx, |pane, cx| {
20254                                pane.activate_item(pane_item_index, true, true, window, cx)
20255                            });
20256                            Some(editor)
20257                        })
20258                        .flatten()
20259                        .unwrap_or_else(|| {
20260                            workspace.open_project_item::<Self>(
20261                                pane.clone(),
20262                                buffer,
20263                                true,
20264                                true,
20265                                window,
20266                                cx,
20267                            )
20268                        });
20269
20270                    editor.update(cx, |editor, cx| {
20271                        let autoscroll = match scroll_offset {
20272                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20273                            None => Autoscroll::newest(),
20274                        };
20275                        let nav_history = editor.nav_history.take();
20276                        editor.change_selections(
20277                            SelectionEffects::scroll(autoscroll),
20278                            window,
20279                            cx,
20280                            |s| {
20281                                s.select_ranges(ranges);
20282                            },
20283                        );
20284                        editor.nav_history = nav_history;
20285                    });
20286                }
20287            })
20288        });
20289    }
20290
20291    // For now, don't allow opening excerpts in buffers that aren't backed by
20292    // regular project files.
20293    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20294        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20295    }
20296
20297    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20298        let snapshot = self.buffer.read(cx).read(cx);
20299        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20300        Some(
20301            ranges
20302                .iter()
20303                .map(move |range| {
20304                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20305                })
20306                .collect(),
20307        )
20308    }
20309
20310    fn selection_replacement_ranges(
20311        &self,
20312        range: Range<OffsetUtf16>,
20313        cx: &mut App,
20314    ) -> Vec<Range<OffsetUtf16>> {
20315        let selections = self.selections.all::<OffsetUtf16>(cx);
20316        let newest_selection = selections
20317            .iter()
20318            .max_by_key(|selection| selection.id)
20319            .unwrap();
20320        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20321        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20322        let snapshot = self.buffer.read(cx).read(cx);
20323        selections
20324            .into_iter()
20325            .map(|mut selection| {
20326                selection.start.0 =
20327                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20328                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20329                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20330                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20331            })
20332            .collect()
20333    }
20334
20335    fn report_editor_event(
20336        &self,
20337        event_type: &'static str,
20338        file_extension: Option<String>,
20339        cx: &App,
20340    ) {
20341        if cfg!(any(test, feature = "test-support")) {
20342            return;
20343        }
20344
20345        let Some(project) = &self.project else { return };
20346
20347        // If None, we are in a file without an extension
20348        let file = self
20349            .buffer
20350            .read(cx)
20351            .as_singleton()
20352            .and_then(|b| b.read(cx).file());
20353        let file_extension = file_extension.or(file
20354            .as_ref()
20355            .and_then(|file| Path::new(file.file_name(cx)).extension())
20356            .and_then(|e| e.to_str())
20357            .map(|a| a.to_string()));
20358
20359        let vim_mode = vim_enabled(cx);
20360
20361        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20362        let copilot_enabled = edit_predictions_provider
20363            == language::language_settings::EditPredictionProvider::Copilot;
20364        let copilot_enabled_for_language = self
20365            .buffer
20366            .read(cx)
20367            .language_settings(cx)
20368            .show_edit_predictions;
20369
20370        let project = project.read(cx);
20371        telemetry::event!(
20372            event_type,
20373            file_extension,
20374            vim_mode,
20375            copilot_enabled,
20376            copilot_enabled_for_language,
20377            edit_predictions_provider,
20378            is_via_ssh = project.is_via_ssh(),
20379        );
20380    }
20381
20382    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20383    /// with each line being an array of {text, highlight} objects.
20384    fn copy_highlight_json(
20385        &mut self,
20386        _: &CopyHighlightJson,
20387        window: &mut Window,
20388        cx: &mut Context<Self>,
20389    ) {
20390        #[derive(Serialize)]
20391        struct Chunk<'a> {
20392            text: String,
20393            highlight: Option<&'a str>,
20394        }
20395
20396        let snapshot = self.buffer.read(cx).snapshot(cx);
20397        let range = self
20398            .selected_text_range(false, window, cx)
20399            .and_then(|selection| {
20400                if selection.range.is_empty() {
20401                    None
20402                } else {
20403                    Some(selection.range)
20404                }
20405            })
20406            .unwrap_or_else(|| 0..snapshot.len());
20407
20408        let chunks = snapshot.chunks(range, true);
20409        let mut lines = Vec::new();
20410        let mut line: VecDeque<Chunk> = VecDeque::new();
20411
20412        let Some(style) = self.style.as_ref() else {
20413            return;
20414        };
20415
20416        for chunk in chunks {
20417            let highlight = chunk
20418                .syntax_highlight_id
20419                .and_then(|id| id.name(&style.syntax));
20420            let mut chunk_lines = chunk.text.split('\n').peekable();
20421            while let Some(text) = chunk_lines.next() {
20422                let mut merged_with_last_token = false;
20423                if let Some(last_token) = line.back_mut() {
20424                    if last_token.highlight == highlight {
20425                        last_token.text.push_str(text);
20426                        merged_with_last_token = true;
20427                    }
20428                }
20429
20430                if !merged_with_last_token {
20431                    line.push_back(Chunk {
20432                        text: text.into(),
20433                        highlight,
20434                    });
20435                }
20436
20437                if chunk_lines.peek().is_some() {
20438                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20439                        line.pop_front();
20440                    }
20441                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20442                        line.pop_back();
20443                    }
20444
20445                    lines.push(mem::take(&mut line));
20446                }
20447            }
20448        }
20449
20450        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20451            return;
20452        };
20453        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20454    }
20455
20456    pub fn open_context_menu(
20457        &mut self,
20458        _: &OpenContextMenu,
20459        window: &mut Window,
20460        cx: &mut Context<Self>,
20461    ) {
20462        self.request_autoscroll(Autoscroll::newest(), cx);
20463        let position = self.selections.newest_display(cx).start;
20464        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20465    }
20466
20467    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20468        &self.inlay_hint_cache
20469    }
20470
20471    pub fn replay_insert_event(
20472        &mut self,
20473        text: &str,
20474        relative_utf16_range: Option<Range<isize>>,
20475        window: &mut Window,
20476        cx: &mut Context<Self>,
20477    ) {
20478        if !self.input_enabled {
20479            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20480            return;
20481        }
20482        if let Some(relative_utf16_range) = relative_utf16_range {
20483            let selections = self.selections.all::<OffsetUtf16>(cx);
20484            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20485                let new_ranges = selections.into_iter().map(|range| {
20486                    let start = OffsetUtf16(
20487                        range
20488                            .head()
20489                            .0
20490                            .saturating_add_signed(relative_utf16_range.start),
20491                    );
20492                    let end = OffsetUtf16(
20493                        range
20494                            .head()
20495                            .0
20496                            .saturating_add_signed(relative_utf16_range.end),
20497                    );
20498                    start..end
20499                });
20500                s.select_ranges(new_ranges);
20501            });
20502        }
20503
20504        self.handle_input(text, window, cx);
20505    }
20506
20507    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20508        let Some(provider) = self.semantics_provider.as_ref() else {
20509            return false;
20510        };
20511
20512        let mut supports = false;
20513        self.buffer().update(cx, |this, cx| {
20514            this.for_each_buffer(|buffer| {
20515                supports |= provider.supports_inlay_hints(buffer, cx);
20516            });
20517        });
20518
20519        supports
20520    }
20521
20522    pub fn is_focused(&self, window: &Window) -> bool {
20523        self.focus_handle.is_focused(window)
20524    }
20525
20526    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20527        cx.emit(EditorEvent::Focused);
20528
20529        if let Some(descendant) = self
20530            .last_focused_descendant
20531            .take()
20532            .and_then(|descendant| descendant.upgrade())
20533        {
20534            window.focus(&descendant);
20535        } else {
20536            if let Some(blame) = self.blame.as_ref() {
20537                blame.update(cx, GitBlame::focus)
20538            }
20539
20540            self.blink_manager.update(cx, BlinkManager::enable);
20541            self.show_cursor_names(window, cx);
20542            self.buffer.update(cx, |buffer, cx| {
20543                buffer.finalize_last_transaction(cx);
20544                if self.leader_id.is_none() {
20545                    buffer.set_active_selections(
20546                        &self.selections.disjoint_anchors(),
20547                        self.selections.line_mode,
20548                        self.cursor_shape,
20549                        cx,
20550                    );
20551                }
20552            });
20553        }
20554    }
20555
20556    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20557        cx.emit(EditorEvent::FocusedIn)
20558    }
20559
20560    fn handle_focus_out(
20561        &mut self,
20562        event: FocusOutEvent,
20563        _window: &mut Window,
20564        cx: &mut Context<Self>,
20565    ) {
20566        if event.blurred != self.focus_handle {
20567            self.last_focused_descendant = Some(event.blurred);
20568        }
20569        self.selection_drag_state = SelectionDragState::None;
20570        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20571    }
20572
20573    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20574        self.blink_manager.update(cx, BlinkManager::disable);
20575        self.buffer
20576            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20577
20578        if let Some(blame) = self.blame.as_ref() {
20579            blame.update(cx, GitBlame::blur)
20580        }
20581        if !self.hover_state.focused(window, cx) {
20582            hide_hover(self, cx);
20583        }
20584        if !self
20585            .context_menu
20586            .borrow()
20587            .as_ref()
20588            .is_some_and(|context_menu| context_menu.focused(window, cx))
20589        {
20590            self.hide_context_menu(window, cx);
20591        }
20592        self.discard_inline_completion(false, cx);
20593        cx.emit(EditorEvent::Blurred);
20594        cx.notify();
20595    }
20596
20597    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20598        let mut pending: String = window
20599            .pending_input_keystrokes()
20600            .into_iter()
20601            .flatten()
20602            .filter_map(|keystroke| {
20603                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20604                    keystroke.key_char.clone()
20605                } else {
20606                    None
20607                }
20608            })
20609            .collect();
20610
20611        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20612            pending = "".to_string();
20613        }
20614
20615        let existing_pending = self
20616            .text_highlights::<PendingInput>(cx)
20617            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20618        if existing_pending.is_none() && pending.is_empty() {
20619            return;
20620        }
20621        let transaction =
20622            self.transact(window, cx, |this, window, cx| {
20623                let selections = this.selections.all::<usize>(cx);
20624                let edits = selections
20625                    .iter()
20626                    .map(|selection| (selection.end..selection.end, pending.clone()));
20627                this.edit(edits, cx);
20628                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20629                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20630                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20631                    }));
20632                });
20633                if let Some(existing_ranges) = existing_pending {
20634                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20635                    this.edit(edits, cx);
20636                }
20637            });
20638
20639        let snapshot = self.snapshot(window, cx);
20640        let ranges = self
20641            .selections
20642            .all::<usize>(cx)
20643            .into_iter()
20644            .map(|selection| {
20645                snapshot.buffer_snapshot.anchor_after(selection.end)
20646                    ..snapshot
20647                        .buffer_snapshot
20648                        .anchor_before(selection.end + pending.len())
20649            })
20650            .collect();
20651
20652        if pending.is_empty() {
20653            self.clear_highlights::<PendingInput>(cx);
20654        } else {
20655            self.highlight_text::<PendingInput>(
20656                ranges,
20657                HighlightStyle {
20658                    underline: Some(UnderlineStyle {
20659                        thickness: px(1.),
20660                        color: None,
20661                        wavy: false,
20662                    }),
20663                    ..Default::default()
20664                },
20665                cx,
20666            );
20667        }
20668
20669        self.ime_transaction = self.ime_transaction.or(transaction);
20670        if let Some(transaction) = self.ime_transaction {
20671            self.buffer.update(cx, |buffer, cx| {
20672                buffer.group_until_transaction(transaction, cx);
20673            });
20674        }
20675
20676        if self.text_highlights::<PendingInput>(cx).is_none() {
20677            self.ime_transaction.take();
20678        }
20679    }
20680
20681    pub fn register_action_renderer(
20682        &mut self,
20683        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20684    ) -> Subscription {
20685        let id = self.next_editor_action_id.post_inc();
20686        self.editor_actions
20687            .borrow_mut()
20688            .insert(id, Box::new(listener));
20689
20690        let editor_actions = self.editor_actions.clone();
20691        Subscription::new(move || {
20692            editor_actions.borrow_mut().remove(&id);
20693        })
20694    }
20695
20696    pub fn register_action<A: Action>(
20697        &mut self,
20698        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20699    ) -> Subscription {
20700        let id = self.next_editor_action_id.post_inc();
20701        let listener = Arc::new(listener);
20702        self.editor_actions.borrow_mut().insert(
20703            id,
20704            Box::new(move |_, window, _| {
20705                let listener = listener.clone();
20706                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20707                    let action = action.downcast_ref().unwrap();
20708                    if phase == DispatchPhase::Bubble {
20709                        listener(action, window, cx)
20710                    }
20711                })
20712            }),
20713        );
20714
20715        let editor_actions = self.editor_actions.clone();
20716        Subscription::new(move || {
20717            editor_actions.borrow_mut().remove(&id);
20718        })
20719    }
20720
20721    pub fn file_header_size(&self) -> u32 {
20722        FILE_HEADER_HEIGHT
20723    }
20724
20725    pub fn restore(
20726        &mut self,
20727        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20728        window: &mut Window,
20729        cx: &mut Context<Self>,
20730    ) {
20731        let workspace = self.workspace();
20732        let project = self.project.as_ref();
20733        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20734            let mut tasks = Vec::new();
20735            for (buffer_id, changes) in revert_changes {
20736                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20737                    buffer.update(cx, |buffer, cx| {
20738                        buffer.edit(
20739                            changes
20740                                .into_iter()
20741                                .map(|(range, text)| (range, text.to_string())),
20742                            None,
20743                            cx,
20744                        );
20745                    });
20746
20747                    if let Some(project) =
20748                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20749                    {
20750                        project.update(cx, |project, cx| {
20751                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20752                        })
20753                    }
20754                }
20755            }
20756            tasks
20757        });
20758        cx.spawn_in(window, async move |_, cx| {
20759            for (buffer, task) in save_tasks {
20760                let result = task.await;
20761                if result.is_err() {
20762                    let Some(path) = buffer
20763                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20764                        .ok()
20765                    else {
20766                        continue;
20767                    };
20768                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20769                        let Some(task) = cx
20770                            .update_window_entity(&workspace, |workspace, window, cx| {
20771                                workspace
20772                                    .open_path_preview(path, None, false, false, false, window, cx)
20773                            })
20774                            .ok()
20775                        else {
20776                            continue;
20777                        };
20778                        task.await.log_err();
20779                    }
20780                }
20781            }
20782        })
20783        .detach();
20784        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20785            selections.refresh()
20786        });
20787    }
20788
20789    pub fn to_pixel_point(
20790        &self,
20791        source: multi_buffer::Anchor,
20792        editor_snapshot: &EditorSnapshot,
20793        window: &mut Window,
20794    ) -> Option<gpui::Point<Pixels>> {
20795        let source_point = source.to_display_point(editor_snapshot);
20796        self.display_to_pixel_point(source_point, editor_snapshot, window)
20797    }
20798
20799    pub fn display_to_pixel_point(
20800        &self,
20801        source: DisplayPoint,
20802        editor_snapshot: &EditorSnapshot,
20803        window: &mut Window,
20804    ) -> Option<gpui::Point<Pixels>> {
20805        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20806        let text_layout_details = self.text_layout_details(window);
20807        let scroll_top = text_layout_details
20808            .scroll_anchor
20809            .scroll_position(editor_snapshot)
20810            .y;
20811
20812        if source.row().as_f32() < scroll_top.floor() {
20813            return None;
20814        }
20815        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20816        let source_y = line_height * (source.row().as_f32() - scroll_top);
20817        Some(gpui::Point::new(source_x, source_y))
20818    }
20819
20820    pub fn has_visible_completions_menu(&self) -> bool {
20821        !self.edit_prediction_preview_is_active()
20822            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20823                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20824            })
20825    }
20826
20827    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20828        if self.mode.is_minimap() {
20829            return;
20830        }
20831        self.addons
20832            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20833    }
20834
20835    pub fn unregister_addon<T: Addon>(&mut self) {
20836        self.addons.remove(&std::any::TypeId::of::<T>());
20837    }
20838
20839    pub fn addon<T: Addon>(&self) -> Option<&T> {
20840        let type_id = std::any::TypeId::of::<T>();
20841        self.addons
20842            .get(&type_id)
20843            .and_then(|item| item.to_any().downcast_ref::<T>())
20844    }
20845
20846    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20847        let type_id = std::any::TypeId::of::<T>();
20848        self.addons
20849            .get_mut(&type_id)
20850            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20851    }
20852
20853    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20854        let text_layout_details = self.text_layout_details(window);
20855        let style = &text_layout_details.editor_style;
20856        let font_id = window.text_system().resolve_font(&style.text.font());
20857        let font_size = style.text.font_size.to_pixels(window.rem_size());
20858        let line_height = style.text.line_height_in_pixels(window.rem_size());
20859        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20860        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20861
20862        CharacterDimensions {
20863            em_width,
20864            em_advance,
20865            line_height,
20866        }
20867    }
20868
20869    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20870        self.load_diff_task.clone()
20871    }
20872
20873    fn read_metadata_from_db(
20874        &mut self,
20875        item_id: u64,
20876        workspace_id: WorkspaceId,
20877        window: &mut Window,
20878        cx: &mut Context<Editor>,
20879    ) {
20880        if self.is_singleton(cx)
20881            && !self.mode.is_minimap()
20882            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20883        {
20884            let buffer_snapshot = OnceCell::new();
20885
20886            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20887                if !folds.is_empty() {
20888                    let snapshot =
20889                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20890                    self.fold_ranges(
20891                        folds
20892                            .into_iter()
20893                            .map(|(start, end)| {
20894                                snapshot.clip_offset(start, Bias::Left)
20895                                    ..snapshot.clip_offset(end, Bias::Right)
20896                            })
20897                            .collect(),
20898                        false,
20899                        window,
20900                        cx,
20901                    );
20902                }
20903            }
20904
20905            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20906                if !selections.is_empty() {
20907                    let snapshot =
20908                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20909                    // skip adding the initial selection to selection history
20910                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20911                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20912                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20913                            snapshot.clip_offset(start, Bias::Left)
20914                                ..snapshot.clip_offset(end, Bias::Right)
20915                        }));
20916                    });
20917                    self.selection_history.mode = SelectionHistoryMode::Normal;
20918                }
20919            };
20920        }
20921
20922        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20923    }
20924
20925    fn update_lsp_data(
20926        &mut self,
20927        ignore_cache: bool,
20928        for_buffer: Option<BufferId>,
20929        window: &mut Window,
20930        cx: &mut Context<'_, Self>,
20931    ) {
20932        self.pull_diagnostics(for_buffer, window, cx);
20933        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20934    }
20935}
20936
20937fn vim_enabled(cx: &App) -> bool {
20938    cx.global::<SettingsStore>()
20939        .raw_user_settings()
20940        .get("vim_mode")
20941        == Some(&serde_json::Value::Bool(true))
20942}
20943
20944fn process_completion_for_edit(
20945    completion: &Completion,
20946    intent: CompletionIntent,
20947    buffer: &Entity<Buffer>,
20948    cursor_position: &text::Anchor,
20949    cx: &mut Context<Editor>,
20950) -> CompletionEdit {
20951    let buffer = buffer.read(cx);
20952    let buffer_snapshot = buffer.snapshot();
20953    let (snippet, new_text) = if completion.is_snippet() {
20954        // Workaround for typescript language server issues so that methods don't expand within
20955        // strings and functions with type expressions. The previous point is used because the query
20956        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20957        let mut snippet_source = completion.new_text.clone();
20958        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20959        previous_point.column = previous_point.column.saturating_sub(1);
20960        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20961            if scope.prefers_label_for_snippet_in_completion() {
20962                if let Some(label) = completion.label() {
20963                    if matches!(
20964                        completion.kind(),
20965                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20966                    ) {
20967                        snippet_source = label;
20968                    }
20969                }
20970            }
20971        }
20972        match Snippet::parse(&snippet_source).log_err() {
20973            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20974            None => (None, completion.new_text.clone()),
20975        }
20976    } else {
20977        (None, completion.new_text.clone())
20978    };
20979
20980    let mut range_to_replace = {
20981        let replace_range = &completion.replace_range;
20982        if let CompletionSource::Lsp {
20983            insert_range: Some(insert_range),
20984            ..
20985        } = &completion.source
20986        {
20987            debug_assert_eq!(
20988                insert_range.start, replace_range.start,
20989                "insert_range and replace_range should start at the same position"
20990            );
20991            debug_assert!(
20992                insert_range
20993                    .start
20994                    .cmp(&cursor_position, &buffer_snapshot)
20995                    .is_le(),
20996                "insert_range should start before or at cursor position"
20997            );
20998            debug_assert!(
20999                replace_range
21000                    .start
21001                    .cmp(&cursor_position, &buffer_snapshot)
21002                    .is_le(),
21003                "replace_range should start before or at cursor position"
21004            );
21005            debug_assert!(
21006                insert_range
21007                    .end
21008                    .cmp(&cursor_position, &buffer_snapshot)
21009                    .is_le(),
21010                "insert_range should end before or at cursor position"
21011            );
21012
21013            let should_replace = match intent {
21014                CompletionIntent::CompleteWithInsert => false,
21015                CompletionIntent::CompleteWithReplace => true,
21016                CompletionIntent::Complete | CompletionIntent::Compose => {
21017                    let insert_mode =
21018                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21019                            .completions
21020                            .lsp_insert_mode;
21021                    match insert_mode {
21022                        LspInsertMode::Insert => false,
21023                        LspInsertMode::Replace => true,
21024                        LspInsertMode::ReplaceSubsequence => {
21025                            let mut text_to_replace = buffer.chars_for_range(
21026                                buffer.anchor_before(replace_range.start)
21027                                    ..buffer.anchor_after(replace_range.end),
21028                            );
21029                            let mut current_needle = text_to_replace.next();
21030                            for haystack_ch in completion.label.text.chars() {
21031                                if let Some(needle_ch) = current_needle {
21032                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21033                                        current_needle = text_to_replace.next();
21034                                    }
21035                                }
21036                            }
21037                            current_needle.is_none()
21038                        }
21039                        LspInsertMode::ReplaceSuffix => {
21040                            if replace_range
21041                                .end
21042                                .cmp(&cursor_position, &buffer_snapshot)
21043                                .is_gt()
21044                            {
21045                                let range_after_cursor = *cursor_position..replace_range.end;
21046                                let text_after_cursor = buffer
21047                                    .text_for_range(
21048                                        buffer.anchor_before(range_after_cursor.start)
21049                                            ..buffer.anchor_after(range_after_cursor.end),
21050                                    )
21051                                    .collect::<String>()
21052                                    .to_ascii_lowercase();
21053                                completion
21054                                    .label
21055                                    .text
21056                                    .to_ascii_lowercase()
21057                                    .ends_with(&text_after_cursor)
21058                            } else {
21059                                true
21060                            }
21061                        }
21062                    }
21063                }
21064            };
21065
21066            if should_replace {
21067                replace_range.clone()
21068            } else {
21069                insert_range.clone()
21070            }
21071        } else {
21072            replace_range.clone()
21073        }
21074    };
21075
21076    if range_to_replace
21077        .end
21078        .cmp(&cursor_position, &buffer_snapshot)
21079        .is_lt()
21080    {
21081        range_to_replace.end = *cursor_position;
21082    }
21083
21084    CompletionEdit {
21085        new_text,
21086        replace_range: range_to_replace.to_offset(&buffer),
21087        snippet,
21088    }
21089}
21090
21091struct CompletionEdit {
21092    new_text: String,
21093    replace_range: Range<usize>,
21094    snippet: Option<Snippet>,
21095}
21096
21097fn insert_extra_newline_brackets(
21098    buffer: &MultiBufferSnapshot,
21099    range: Range<usize>,
21100    language: &language::LanguageScope,
21101) -> bool {
21102    let leading_whitespace_len = buffer
21103        .reversed_chars_at(range.start)
21104        .take_while(|c| c.is_whitespace() && *c != '\n')
21105        .map(|c| c.len_utf8())
21106        .sum::<usize>();
21107    let trailing_whitespace_len = buffer
21108        .chars_at(range.end)
21109        .take_while(|c| c.is_whitespace() && *c != '\n')
21110        .map(|c| c.len_utf8())
21111        .sum::<usize>();
21112    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21113
21114    language.brackets().any(|(pair, enabled)| {
21115        let pair_start = pair.start.trim_end();
21116        let pair_end = pair.end.trim_start();
21117
21118        enabled
21119            && pair.newline
21120            && buffer.contains_str_at(range.end, pair_end)
21121            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21122    })
21123}
21124
21125fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21126    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21127        [(buffer, range, _)] => (*buffer, range.clone()),
21128        _ => return false,
21129    };
21130    let pair = {
21131        let mut result: Option<BracketMatch> = None;
21132
21133        for pair in buffer
21134            .all_bracket_ranges(range.clone())
21135            .filter(move |pair| {
21136                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21137            })
21138        {
21139            let len = pair.close_range.end - pair.open_range.start;
21140
21141            if let Some(existing) = &result {
21142                let existing_len = existing.close_range.end - existing.open_range.start;
21143                if len > existing_len {
21144                    continue;
21145                }
21146            }
21147
21148            result = Some(pair);
21149        }
21150
21151        result
21152    };
21153    let Some(pair) = pair else {
21154        return false;
21155    };
21156    pair.newline_only
21157        && buffer
21158            .chars_for_range(pair.open_range.end..range.start)
21159            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21160            .all(|c| c.is_whitespace() && c != '\n')
21161}
21162
21163fn update_uncommitted_diff_for_buffer(
21164    editor: Entity<Editor>,
21165    project: &Entity<Project>,
21166    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21167    buffer: Entity<MultiBuffer>,
21168    cx: &mut App,
21169) -> Task<()> {
21170    let mut tasks = Vec::new();
21171    project.update(cx, |project, cx| {
21172        for buffer in buffers {
21173            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21174                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21175            }
21176        }
21177    });
21178    cx.spawn(async move |cx| {
21179        let diffs = future::join_all(tasks).await;
21180        if editor
21181            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21182            .unwrap_or(false)
21183        {
21184            return;
21185        }
21186
21187        buffer
21188            .update(cx, |buffer, cx| {
21189                for diff in diffs.into_iter().flatten() {
21190                    buffer.add_diff(diff, cx);
21191                }
21192            })
21193            .ok();
21194    })
21195}
21196
21197fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21198    let tab_size = tab_size.get() as usize;
21199    let mut width = offset;
21200
21201    for ch in text.chars() {
21202        width += if ch == '\t' {
21203            tab_size - (width % tab_size)
21204        } else {
21205            1
21206        };
21207    }
21208
21209    width - offset
21210}
21211
21212#[cfg(test)]
21213mod tests {
21214    use super::*;
21215
21216    #[test]
21217    fn test_string_size_with_expanded_tabs() {
21218        let nz = |val| NonZeroU32::new(val).unwrap();
21219        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21220        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21221        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21222        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21223        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21224        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21225        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21226        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21227    }
21228}
21229
21230/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21231struct WordBreakingTokenizer<'a> {
21232    input: &'a str,
21233}
21234
21235impl<'a> WordBreakingTokenizer<'a> {
21236    fn new(input: &'a str) -> Self {
21237        Self { input }
21238    }
21239}
21240
21241fn is_char_ideographic(ch: char) -> bool {
21242    use unicode_script::Script::*;
21243    use unicode_script::UnicodeScript;
21244    matches!(ch.script(), Han | Tangut | Yi)
21245}
21246
21247fn is_grapheme_ideographic(text: &str) -> bool {
21248    text.chars().any(is_char_ideographic)
21249}
21250
21251fn is_grapheme_whitespace(text: &str) -> bool {
21252    text.chars().any(|x| x.is_whitespace())
21253}
21254
21255fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21256    text.chars().next().map_or(false, |ch| {
21257        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21258    })
21259}
21260
21261#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21262enum WordBreakToken<'a> {
21263    Word { token: &'a str, grapheme_len: usize },
21264    InlineWhitespace { token: &'a str, grapheme_len: usize },
21265    Newline,
21266}
21267
21268impl<'a> Iterator for WordBreakingTokenizer<'a> {
21269    /// Yields a span, the count of graphemes in the token, and whether it was
21270    /// whitespace. Note that it also breaks at word boundaries.
21271    type Item = WordBreakToken<'a>;
21272
21273    fn next(&mut self) -> Option<Self::Item> {
21274        use unicode_segmentation::UnicodeSegmentation;
21275        if self.input.is_empty() {
21276            return None;
21277        }
21278
21279        let mut iter = self.input.graphemes(true).peekable();
21280        let mut offset = 0;
21281        let mut grapheme_len = 0;
21282        if let Some(first_grapheme) = iter.next() {
21283            let is_newline = first_grapheme == "\n";
21284            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21285            offset += first_grapheme.len();
21286            grapheme_len += 1;
21287            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21288                if let Some(grapheme) = iter.peek().copied() {
21289                    if should_stay_with_preceding_ideograph(grapheme) {
21290                        offset += grapheme.len();
21291                        grapheme_len += 1;
21292                    }
21293                }
21294            } else {
21295                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21296                let mut next_word_bound = words.peek().copied();
21297                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21298                    next_word_bound = words.next();
21299                }
21300                while let Some(grapheme) = iter.peek().copied() {
21301                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21302                        break;
21303                    };
21304                    if is_grapheme_whitespace(grapheme) != is_whitespace
21305                        || (grapheme == "\n") != is_newline
21306                    {
21307                        break;
21308                    };
21309                    offset += grapheme.len();
21310                    grapheme_len += 1;
21311                    iter.next();
21312                }
21313            }
21314            let token = &self.input[..offset];
21315            self.input = &self.input[offset..];
21316            if token == "\n" {
21317                Some(WordBreakToken::Newline)
21318            } else if is_whitespace {
21319                Some(WordBreakToken::InlineWhitespace {
21320                    token,
21321                    grapheme_len,
21322                })
21323            } else {
21324                Some(WordBreakToken::Word {
21325                    token,
21326                    grapheme_len,
21327                })
21328            }
21329        } else {
21330            None
21331        }
21332    }
21333}
21334
21335#[test]
21336fn test_word_breaking_tokenizer() {
21337    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21338        ("", &[]),
21339        ("  ", &[whitespace("  ", 2)]),
21340        ("Ʒ", &[word("Ʒ", 1)]),
21341        ("Ǽ", &[word("Ǽ", 1)]),
21342        ("", &[word("", 1)]),
21343        ("⋑⋑", &[word("⋑⋑", 2)]),
21344        (
21345            "原理,进而",
21346            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21347        ),
21348        (
21349            "hello world",
21350            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21351        ),
21352        (
21353            "hello, world",
21354            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21355        ),
21356        (
21357            "  hello world",
21358            &[
21359                whitespace("  ", 2),
21360                word("hello", 5),
21361                whitespace(" ", 1),
21362                word("world", 5),
21363            ],
21364        ),
21365        (
21366            "这是什么 \n 钢笔",
21367            &[
21368                word("", 1),
21369                word("", 1),
21370                word("", 1),
21371                word("", 1),
21372                whitespace(" ", 1),
21373                newline(),
21374                whitespace(" ", 1),
21375                word("", 1),
21376                word("", 1),
21377            ],
21378        ),
21379        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21380    ];
21381
21382    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21383        WordBreakToken::Word {
21384            token,
21385            grapheme_len,
21386        }
21387    }
21388
21389    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21390        WordBreakToken::InlineWhitespace {
21391            token,
21392            grapheme_len,
21393        }
21394    }
21395
21396    fn newline() -> WordBreakToken<'static> {
21397        WordBreakToken::Newline
21398    }
21399
21400    for (input, result) in tests {
21401        assert_eq!(
21402            WordBreakingTokenizer::new(input)
21403                .collect::<Vec<_>>()
21404                .as_slice(),
21405            *result,
21406        );
21407    }
21408}
21409
21410fn wrap_with_prefix(
21411    first_line_prefix: String,
21412    subsequent_lines_prefix: String,
21413    unwrapped_text: String,
21414    wrap_column: usize,
21415    tab_size: NonZeroU32,
21416    preserve_existing_whitespace: bool,
21417) -> String {
21418    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21419    let subsequent_lines_prefix_len =
21420        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21421    let mut wrapped_text = String::new();
21422    let mut current_line = first_line_prefix.clone();
21423    let mut is_first_line = true;
21424
21425    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21426    let mut current_line_len = first_line_prefix_len;
21427    let mut in_whitespace = false;
21428    for token in tokenizer {
21429        let have_preceding_whitespace = in_whitespace;
21430        match token {
21431            WordBreakToken::Word {
21432                token,
21433                grapheme_len,
21434            } => {
21435                in_whitespace = false;
21436                let current_prefix_len = if is_first_line {
21437                    first_line_prefix_len
21438                } else {
21439                    subsequent_lines_prefix_len
21440                };
21441                if current_line_len + grapheme_len > wrap_column
21442                    && current_line_len != current_prefix_len
21443                {
21444                    wrapped_text.push_str(current_line.trim_end());
21445                    wrapped_text.push('\n');
21446                    is_first_line = false;
21447                    current_line = subsequent_lines_prefix.clone();
21448                    current_line_len = subsequent_lines_prefix_len;
21449                }
21450                current_line.push_str(token);
21451                current_line_len += grapheme_len;
21452            }
21453            WordBreakToken::InlineWhitespace {
21454                mut token,
21455                mut grapheme_len,
21456            } => {
21457                in_whitespace = true;
21458                if have_preceding_whitespace && !preserve_existing_whitespace {
21459                    continue;
21460                }
21461                if !preserve_existing_whitespace {
21462                    token = " ";
21463                    grapheme_len = 1;
21464                }
21465                let current_prefix_len = if is_first_line {
21466                    first_line_prefix_len
21467                } else {
21468                    subsequent_lines_prefix_len
21469                };
21470                if current_line_len + grapheme_len > wrap_column {
21471                    wrapped_text.push_str(current_line.trim_end());
21472                    wrapped_text.push('\n');
21473                    is_first_line = false;
21474                    current_line = subsequent_lines_prefix.clone();
21475                    current_line_len = subsequent_lines_prefix_len;
21476                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21477                    current_line.push_str(token);
21478                    current_line_len += grapheme_len;
21479                }
21480            }
21481            WordBreakToken::Newline => {
21482                in_whitespace = true;
21483                let current_prefix_len = if is_first_line {
21484                    first_line_prefix_len
21485                } else {
21486                    subsequent_lines_prefix_len
21487                };
21488                if preserve_existing_whitespace {
21489                    wrapped_text.push_str(current_line.trim_end());
21490                    wrapped_text.push('\n');
21491                    is_first_line = false;
21492                    current_line = subsequent_lines_prefix.clone();
21493                    current_line_len = subsequent_lines_prefix_len;
21494                } else if have_preceding_whitespace {
21495                    continue;
21496                } else if current_line_len + 1 > wrap_column
21497                    && current_line_len != current_prefix_len
21498                {
21499                    wrapped_text.push_str(current_line.trim_end());
21500                    wrapped_text.push('\n');
21501                    is_first_line = false;
21502                    current_line = subsequent_lines_prefix.clone();
21503                    current_line_len = subsequent_lines_prefix_len;
21504                } else if current_line_len != current_prefix_len {
21505                    current_line.push(' ');
21506                    current_line_len += 1;
21507                }
21508            }
21509        }
21510    }
21511
21512    if !current_line.is_empty() {
21513        wrapped_text.push_str(&current_line);
21514    }
21515    wrapped_text
21516}
21517
21518#[test]
21519fn test_wrap_with_prefix() {
21520    assert_eq!(
21521        wrap_with_prefix(
21522            "# ".to_string(),
21523            "# ".to_string(),
21524            "abcdefg".to_string(),
21525            4,
21526            NonZeroU32::new(4).unwrap(),
21527            false,
21528        ),
21529        "# abcdefg"
21530    );
21531    assert_eq!(
21532        wrap_with_prefix(
21533            "".to_string(),
21534            "".to_string(),
21535            "\thello world".to_string(),
21536            8,
21537            NonZeroU32::new(4).unwrap(),
21538            false,
21539        ),
21540        "hello\nworld"
21541    );
21542    assert_eq!(
21543        wrap_with_prefix(
21544            "// ".to_string(),
21545            "// ".to_string(),
21546            "xx \nyy zz aa bb cc".to_string(),
21547            12,
21548            NonZeroU32::new(4).unwrap(),
21549            false,
21550        ),
21551        "// xx yy zz\n// aa bb cc"
21552    );
21553    assert_eq!(
21554        wrap_with_prefix(
21555            String::new(),
21556            String::new(),
21557            "这是什么 \n 钢笔".to_string(),
21558            3,
21559            NonZeroU32::new(4).unwrap(),
21560            false,
21561        ),
21562        "这是什\n么 钢\n"
21563    );
21564}
21565
21566pub trait CollaborationHub {
21567    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21568    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21569    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21570}
21571
21572impl CollaborationHub for Entity<Project> {
21573    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21574        self.read(cx).collaborators()
21575    }
21576
21577    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21578        self.read(cx).user_store().read(cx).participant_indices()
21579    }
21580
21581    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21582        let this = self.read(cx);
21583        let user_ids = this.collaborators().values().map(|c| c.user_id);
21584        this.user_store().read(cx).participant_names(user_ids, cx)
21585    }
21586}
21587
21588pub trait SemanticsProvider {
21589    fn hover(
21590        &self,
21591        buffer: &Entity<Buffer>,
21592        position: text::Anchor,
21593        cx: &mut App,
21594    ) -> Option<Task<Vec<project::Hover>>>;
21595
21596    fn inline_values(
21597        &self,
21598        buffer_handle: Entity<Buffer>,
21599        range: Range<text::Anchor>,
21600        cx: &mut App,
21601    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21602
21603    fn inlay_hints(
21604        &self,
21605        buffer_handle: Entity<Buffer>,
21606        range: Range<text::Anchor>,
21607        cx: &mut App,
21608    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21609
21610    fn resolve_inlay_hint(
21611        &self,
21612        hint: InlayHint,
21613        buffer_handle: Entity<Buffer>,
21614        server_id: LanguageServerId,
21615        cx: &mut App,
21616    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21617
21618    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21619
21620    fn document_highlights(
21621        &self,
21622        buffer: &Entity<Buffer>,
21623        position: text::Anchor,
21624        cx: &mut App,
21625    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21626
21627    fn definitions(
21628        &self,
21629        buffer: &Entity<Buffer>,
21630        position: text::Anchor,
21631        kind: GotoDefinitionKind,
21632        cx: &mut App,
21633    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21634
21635    fn range_for_rename(
21636        &self,
21637        buffer: &Entity<Buffer>,
21638        position: text::Anchor,
21639        cx: &mut App,
21640    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21641
21642    fn perform_rename(
21643        &self,
21644        buffer: &Entity<Buffer>,
21645        position: text::Anchor,
21646        new_name: String,
21647        cx: &mut App,
21648    ) -> Option<Task<Result<ProjectTransaction>>>;
21649}
21650
21651pub trait CompletionProvider {
21652    fn completions(
21653        &self,
21654        excerpt_id: ExcerptId,
21655        buffer: &Entity<Buffer>,
21656        buffer_position: text::Anchor,
21657        trigger: CompletionContext,
21658        window: &mut Window,
21659        cx: &mut Context<Editor>,
21660    ) -> Task<Result<Vec<CompletionResponse>>>;
21661
21662    fn resolve_completions(
21663        &self,
21664        _buffer: Entity<Buffer>,
21665        _completion_indices: Vec<usize>,
21666        _completions: Rc<RefCell<Box<[Completion]>>>,
21667        _cx: &mut Context<Editor>,
21668    ) -> Task<Result<bool>> {
21669        Task::ready(Ok(false))
21670    }
21671
21672    fn apply_additional_edits_for_completion(
21673        &self,
21674        _buffer: Entity<Buffer>,
21675        _completions: Rc<RefCell<Box<[Completion]>>>,
21676        _completion_index: usize,
21677        _push_to_history: bool,
21678        _cx: &mut Context<Editor>,
21679    ) -> Task<Result<Option<language::Transaction>>> {
21680        Task::ready(Ok(None))
21681    }
21682
21683    fn is_completion_trigger(
21684        &self,
21685        buffer: &Entity<Buffer>,
21686        position: language::Anchor,
21687        text: &str,
21688        trigger_in_words: bool,
21689        menu_is_open: bool,
21690        cx: &mut Context<Editor>,
21691    ) -> bool;
21692
21693    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21694
21695    fn sort_completions(&self) -> bool {
21696        true
21697    }
21698
21699    fn filter_completions(&self) -> bool {
21700        true
21701    }
21702}
21703
21704pub trait CodeActionProvider {
21705    fn id(&self) -> Arc<str>;
21706
21707    fn code_actions(
21708        &self,
21709        buffer: &Entity<Buffer>,
21710        range: Range<text::Anchor>,
21711        window: &mut Window,
21712        cx: &mut App,
21713    ) -> Task<Result<Vec<CodeAction>>>;
21714
21715    fn apply_code_action(
21716        &self,
21717        buffer_handle: Entity<Buffer>,
21718        action: CodeAction,
21719        excerpt_id: ExcerptId,
21720        push_to_history: bool,
21721        window: &mut Window,
21722        cx: &mut App,
21723    ) -> Task<Result<ProjectTransaction>>;
21724}
21725
21726impl CodeActionProvider for Entity<Project> {
21727    fn id(&self) -> Arc<str> {
21728        "project".into()
21729    }
21730
21731    fn code_actions(
21732        &self,
21733        buffer: &Entity<Buffer>,
21734        range: Range<text::Anchor>,
21735        _window: &mut Window,
21736        cx: &mut App,
21737    ) -> Task<Result<Vec<CodeAction>>> {
21738        self.update(cx, |project, cx| {
21739            let code_lens = project.code_lens(buffer, range.clone(), cx);
21740            let code_actions = project.code_actions(buffer, range, None, cx);
21741            cx.background_spawn(async move {
21742                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21743                Ok(code_lens
21744                    .context("code lens fetch")?
21745                    .into_iter()
21746                    .chain(code_actions.context("code action fetch")?)
21747                    .collect())
21748            })
21749        })
21750    }
21751
21752    fn apply_code_action(
21753        &self,
21754        buffer_handle: Entity<Buffer>,
21755        action: CodeAction,
21756        _excerpt_id: ExcerptId,
21757        push_to_history: bool,
21758        _window: &mut Window,
21759        cx: &mut App,
21760    ) -> Task<Result<ProjectTransaction>> {
21761        self.update(cx, |project, cx| {
21762            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21763        })
21764    }
21765}
21766
21767fn snippet_completions(
21768    project: &Project,
21769    buffer: &Entity<Buffer>,
21770    buffer_position: text::Anchor,
21771    cx: &mut App,
21772) -> Task<Result<CompletionResponse>> {
21773    let languages = buffer.read(cx).languages_at(buffer_position);
21774    let snippet_store = project.snippets().read(cx);
21775
21776    let scopes: Vec<_> = languages
21777        .iter()
21778        .filter_map(|language| {
21779            let language_name = language.lsp_id();
21780            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21781
21782            if snippets.is_empty() {
21783                None
21784            } else {
21785                Some((language.default_scope(), snippets))
21786            }
21787        })
21788        .collect();
21789
21790    if scopes.is_empty() {
21791        return Task::ready(Ok(CompletionResponse {
21792            completions: vec![],
21793            is_incomplete: false,
21794        }));
21795    }
21796
21797    let snapshot = buffer.read(cx).text_snapshot();
21798    let chars: String = snapshot
21799        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21800        .collect();
21801    let executor = cx.background_executor().clone();
21802
21803    cx.background_spawn(async move {
21804        let mut is_incomplete = false;
21805        let mut completions: Vec<Completion> = Vec::new();
21806        for (scope, snippets) in scopes.into_iter() {
21807            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21808            let mut last_word = chars
21809                .chars()
21810                .take_while(|c| classifier.is_word(*c))
21811                .collect::<String>();
21812            last_word = last_word.chars().rev().collect();
21813
21814            if last_word.is_empty() {
21815                return Ok(CompletionResponse {
21816                    completions: vec![],
21817                    is_incomplete: true,
21818                });
21819            }
21820
21821            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21822            let to_lsp = |point: &text::Anchor| {
21823                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21824                point_to_lsp(end)
21825            };
21826            let lsp_end = to_lsp(&buffer_position);
21827
21828            let candidates = snippets
21829                .iter()
21830                .enumerate()
21831                .flat_map(|(ix, snippet)| {
21832                    snippet
21833                        .prefix
21834                        .iter()
21835                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21836                })
21837                .collect::<Vec<StringMatchCandidate>>();
21838
21839            const MAX_RESULTS: usize = 100;
21840            let mut matches = fuzzy::match_strings(
21841                &candidates,
21842                &last_word,
21843                last_word.chars().any(|c| c.is_uppercase()),
21844                true,
21845                MAX_RESULTS,
21846                &Default::default(),
21847                executor.clone(),
21848            )
21849            .await;
21850
21851            if matches.len() >= MAX_RESULTS {
21852                is_incomplete = true;
21853            }
21854
21855            // Remove all candidates where the query's start does not match the start of any word in the candidate
21856            if let Some(query_start) = last_word.chars().next() {
21857                matches.retain(|string_match| {
21858                    split_words(&string_match.string).any(|word| {
21859                        // Check that the first codepoint of the word as lowercase matches the first
21860                        // codepoint of the query as lowercase
21861                        word.chars()
21862                            .flat_map(|codepoint| codepoint.to_lowercase())
21863                            .zip(query_start.to_lowercase())
21864                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21865                    })
21866                });
21867            }
21868
21869            let matched_strings = matches
21870                .into_iter()
21871                .map(|m| m.string)
21872                .collect::<HashSet<_>>();
21873
21874            completions.extend(snippets.iter().filter_map(|snippet| {
21875                let matching_prefix = snippet
21876                    .prefix
21877                    .iter()
21878                    .find(|prefix| matched_strings.contains(*prefix))?;
21879                let start = as_offset - last_word.len();
21880                let start = snapshot.anchor_before(start);
21881                let range = start..buffer_position;
21882                let lsp_start = to_lsp(&start);
21883                let lsp_range = lsp::Range {
21884                    start: lsp_start,
21885                    end: lsp_end,
21886                };
21887                Some(Completion {
21888                    replace_range: range,
21889                    new_text: snippet.body.clone(),
21890                    source: CompletionSource::Lsp {
21891                        insert_range: None,
21892                        server_id: LanguageServerId(usize::MAX),
21893                        resolved: true,
21894                        lsp_completion: Box::new(lsp::CompletionItem {
21895                            label: snippet.prefix.first().unwrap().clone(),
21896                            kind: Some(CompletionItemKind::SNIPPET),
21897                            label_details: snippet.description.as_ref().map(|description| {
21898                                lsp::CompletionItemLabelDetails {
21899                                    detail: Some(description.clone()),
21900                                    description: None,
21901                                }
21902                            }),
21903                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21904                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21905                                lsp::InsertReplaceEdit {
21906                                    new_text: snippet.body.clone(),
21907                                    insert: lsp_range,
21908                                    replace: lsp_range,
21909                                },
21910                            )),
21911                            filter_text: Some(snippet.body.clone()),
21912                            sort_text: Some(char::MAX.to_string()),
21913                            ..lsp::CompletionItem::default()
21914                        }),
21915                        lsp_defaults: None,
21916                    },
21917                    label: CodeLabel {
21918                        text: matching_prefix.clone(),
21919                        runs: Vec::new(),
21920                        filter_range: 0..matching_prefix.len(),
21921                    },
21922                    icon_path: None,
21923                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21924                        single_line: snippet.name.clone().into(),
21925                        plain_text: snippet
21926                            .description
21927                            .clone()
21928                            .map(|description| description.into()),
21929                    }),
21930                    insert_text_mode: None,
21931                    confirm: None,
21932                })
21933            }))
21934        }
21935
21936        Ok(CompletionResponse {
21937            completions,
21938            is_incomplete,
21939        })
21940    })
21941}
21942
21943impl CompletionProvider for Entity<Project> {
21944    fn completions(
21945        &self,
21946        _excerpt_id: ExcerptId,
21947        buffer: &Entity<Buffer>,
21948        buffer_position: text::Anchor,
21949        options: CompletionContext,
21950        _window: &mut Window,
21951        cx: &mut Context<Editor>,
21952    ) -> Task<Result<Vec<CompletionResponse>>> {
21953        self.update(cx, |project, cx| {
21954            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21955            let project_completions = project.completions(buffer, buffer_position, options, cx);
21956            cx.background_spawn(async move {
21957                let mut responses = project_completions.await?;
21958                let snippets = snippets.await?;
21959                if !snippets.completions.is_empty() {
21960                    responses.push(snippets);
21961                }
21962                Ok(responses)
21963            })
21964        })
21965    }
21966
21967    fn resolve_completions(
21968        &self,
21969        buffer: Entity<Buffer>,
21970        completion_indices: Vec<usize>,
21971        completions: Rc<RefCell<Box<[Completion]>>>,
21972        cx: &mut Context<Editor>,
21973    ) -> Task<Result<bool>> {
21974        self.update(cx, |project, cx| {
21975            project.lsp_store().update(cx, |lsp_store, cx| {
21976                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21977            })
21978        })
21979    }
21980
21981    fn apply_additional_edits_for_completion(
21982        &self,
21983        buffer: Entity<Buffer>,
21984        completions: Rc<RefCell<Box<[Completion]>>>,
21985        completion_index: usize,
21986        push_to_history: bool,
21987        cx: &mut Context<Editor>,
21988    ) -> Task<Result<Option<language::Transaction>>> {
21989        self.update(cx, |project, cx| {
21990            project.lsp_store().update(cx, |lsp_store, cx| {
21991                lsp_store.apply_additional_edits_for_completion(
21992                    buffer,
21993                    completions,
21994                    completion_index,
21995                    push_to_history,
21996                    cx,
21997                )
21998            })
21999        })
22000    }
22001
22002    fn is_completion_trigger(
22003        &self,
22004        buffer: &Entity<Buffer>,
22005        position: language::Anchor,
22006        text: &str,
22007        trigger_in_words: bool,
22008        menu_is_open: bool,
22009        cx: &mut Context<Editor>,
22010    ) -> bool {
22011        let mut chars = text.chars();
22012        let char = if let Some(char) = chars.next() {
22013            char
22014        } else {
22015            return false;
22016        };
22017        if chars.next().is_some() {
22018            return false;
22019        }
22020
22021        let buffer = buffer.read(cx);
22022        let snapshot = buffer.snapshot();
22023        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22024            return false;
22025        }
22026        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22027        if trigger_in_words && classifier.is_word(char) {
22028            return true;
22029        }
22030
22031        buffer.completion_triggers().contains(text)
22032    }
22033}
22034
22035impl SemanticsProvider for Entity<Project> {
22036    fn hover(
22037        &self,
22038        buffer: &Entity<Buffer>,
22039        position: text::Anchor,
22040        cx: &mut App,
22041    ) -> Option<Task<Vec<project::Hover>>> {
22042        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22043    }
22044
22045    fn document_highlights(
22046        &self,
22047        buffer: &Entity<Buffer>,
22048        position: text::Anchor,
22049        cx: &mut App,
22050    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22051        Some(self.update(cx, |project, cx| {
22052            project.document_highlights(buffer, position, cx)
22053        }))
22054    }
22055
22056    fn definitions(
22057        &self,
22058        buffer: &Entity<Buffer>,
22059        position: text::Anchor,
22060        kind: GotoDefinitionKind,
22061        cx: &mut App,
22062    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22063        Some(self.update(cx, |project, cx| match kind {
22064            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22065            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22066            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22067            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22068        }))
22069    }
22070
22071    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22072        // TODO: make this work for remote projects
22073        self.update(cx, |project, cx| {
22074            if project
22075                .active_debug_session(cx)
22076                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22077            {
22078                return true;
22079            }
22080
22081            buffer.update(cx, |buffer, cx| {
22082                project.any_language_server_supports_inlay_hints(buffer, cx)
22083            })
22084        })
22085    }
22086
22087    fn inline_values(
22088        &self,
22089        buffer_handle: Entity<Buffer>,
22090        range: Range<text::Anchor>,
22091        cx: &mut App,
22092    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22093        self.update(cx, |project, cx| {
22094            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22095
22096            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22097        })
22098    }
22099
22100    fn inlay_hints(
22101        &self,
22102        buffer_handle: Entity<Buffer>,
22103        range: Range<text::Anchor>,
22104        cx: &mut App,
22105    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22106        Some(self.update(cx, |project, cx| {
22107            project.inlay_hints(buffer_handle, range, cx)
22108        }))
22109    }
22110
22111    fn resolve_inlay_hint(
22112        &self,
22113        hint: InlayHint,
22114        buffer_handle: Entity<Buffer>,
22115        server_id: LanguageServerId,
22116        cx: &mut App,
22117    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22118        Some(self.update(cx, |project, cx| {
22119            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22120        }))
22121    }
22122
22123    fn range_for_rename(
22124        &self,
22125        buffer: &Entity<Buffer>,
22126        position: text::Anchor,
22127        cx: &mut App,
22128    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22129        Some(self.update(cx, |project, cx| {
22130            let buffer = buffer.clone();
22131            let task = project.prepare_rename(buffer.clone(), position, cx);
22132            cx.spawn(async move |_, cx| {
22133                Ok(match task.await? {
22134                    PrepareRenameResponse::Success(range) => Some(range),
22135                    PrepareRenameResponse::InvalidPosition => None,
22136                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22137                        // Fallback on using TreeSitter info to determine identifier range
22138                        buffer.read_with(cx, |buffer, _| {
22139                            let snapshot = buffer.snapshot();
22140                            let (range, kind) = snapshot.surrounding_word(position, false);
22141                            if kind != Some(CharKind::Word) {
22142                                return None;
22143                            }
22144                            Some(
22145                                snapshot.anchor_before(range.start)
22146                                    ..snapshot.anchor_after(range.end),
22147                            )
22148                        })?
22149                    }
22150                })
22151            })
22152        }))
22153    }
22154
22155    fn perform_rename(
22156        &self,
22157        buffer: &Entity<Buffer>,
22158        position: text::Anchor,
22159        new_name: String,
22160        cx: &mut App,
22161    ) -> Option<Task<Result<ProjectTransaction>>> {
22162        Some(self.update(cx, |project, cx| {
22163            project.perform_rename(buffer.clone(), position, new_name, cx)
22164        }))
22165    }
22166}
22167
22168fn inlay_hint_settings(
22169    location: Anchor,
22170    snapshot: &MultiBufferSnapshot,
22171    cx: &mut Context<Editor>,
22172) -> InlayHintSettings {
22173    let file = snapshot.file_at(location);
22174    let language = snapshot.language_at(location).map(|l| l.name());
22175    language_settings(language, file, cx).inlay_hints
22176}
22177
22178fn consume_contiguous_rows(
22179    contiguous_row_selections: &mut Vec<Selection<Point>>,
22180    selection: &Selection<Point>,
22181    display_map: &DisplaySnapshot,
22182    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22183) -> (MultiBufferRow, MultiBufferRow) {
22184    contiguous_row_selections.push(selection.clone());
22185    let start_row = MultiBufferRow(selection.start.row);
22186    let mut end_row = ending_row(selection, display_map);
22187
22188    while let Some(next_selection) = selections.peek() {
22189        if next_selection.start.row <= end_row.0 {
22190            end_row = ending_row(next_selection, display_map);
22191            contiguous_row_selections.push(selections.next().unwrap().clone());
22192        } else {
22193            break;
22194        }
22195    }
22196    (start_row, end_row)
22197}
22198
22199fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22200    if next_selection.end.column > 0 || next_selection.is_empty() {
22201        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22202    } else {
22203        MultiBufferRow(next_selection.end.row)
22204    }
22205}
22206
22207impl EditorSnapshot {
22208    pub fn remote_selections_in_range<'a>(
22209        &'a self,
22210        range: &'a Range<Anchor>,
22211        collaboration_hub: &dyn CollaborationHub,
22212        cx: &'a App,
22213    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22214        let participant_names = collaboration_hub.user_names(cx);
22215        let participant_indices = collaboration_hub.user_participant_indices(cx);
22216        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22217        let collaborators_by_replica_id = collaborators_by_peer_id
22218            .values()
22219            .map(|collaborator| (collaborator.replica_id, collaborator))
22220            .collect::<HashMap<_, _>>();
22221        self.buffer_snapshot
22222            .selections_in_range(range, false)
22223            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22224                if replica_id == AGENT_REPLICA_ID {
22225                    Some(RemoteSelection {
22226                        replica_id,
22227                        selection,
22228                        cursor_shape,
22229                        line_mode,
22230                        collaborator_id: CollaboratorId::Agent,
22231                        user_name: Some("Agent".into()),
22232                        color: cx.theme().players().agent(),
22233                    })
22234                } else {
22235                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22236                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22237                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22238                    Some(RemoteSelection {
22239                        replica_id,
22240                        selection,
22241                        cursor_shape,
22242                        line_mode,
22243                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22244                        user_name,
22245                        color: if let Some(index) = participant_index {
22246                            cx.theme().players().color_for_participant(index.0)
22247                        } else {
22248                            cx.theme().players().absent()
22249                        },
22250                    })
22251                }
22252            })
22253    }
22254
22255    pub fn hunks_for_ranges(
22256        &self,
22257        ranges: impl IntoIterator<Item = Range<Point>>,
22258    ) -> Vec<MultiBufferDiffHunk> {
22259        let mut hunks = Vec::new();
22260        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22261            HashMap::default();
22262        for query_range in ranges {
22263            let query_rows =
22264                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22265            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22266                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22267            ) {
22268                // Include deleted hunks that are adjacent to the query range, because
22269                // otherwise they would be missed.
22270                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22271                if hunk.status().is_deleted() {
22272                    intersects_range |= hunk.row_range.start == query_rows.end;
22273                    intersects_range |= hunk.row_range.end == query_rows.start;
22274                }
22275                if intersects_range {
22276                    if !processed_buffer_rows
22277                        .entry(hunk.buffer_id)
22278                        .or_default()
22279                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22280                    {
22281                        continue;
22282                    }
22283                    hunks.push(hunk);
22284                }
22285            }
22286        }
22287
22288        hunks
22289    }
22290
22291    fn display_diff_hunks_for_rows<'a>(
22292        &'a self,
22293        display_rows: Range<DisplayRow>,
22294        folded_buffers: &'a HashSet<BufferId>,
22295    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22296        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22297        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22298
22299        self.buffer_snapshot
22300            .diff_hunks_in_range(buffer_start..buffer_end)
22301            .filter_map(|hunk| {
22302                if folded_buffers.contains(&hunk.buffer_id) {
22303                    return None;
22304                }
22305
22306                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22307                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22308
22309                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22310                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22311
22312                let display_hunk = if hunk_display_start.column() != 0 {
22313                    DisplayDiffHunk::Folded {
22314                        display_row: hunk_display_start.row(),
22315                    }
22316                } else {
22317                    let mut end_row = hunk_display_end.row();
22318                    if hunk_display_end.column() > 0 {
22319                        end_row.0 += 1;
22320                    }
22321                    let is_created_file = hunk.is_created_file();
22322                    DisplayDiffHunk::Unfolded {
22323                        status: hunk.status(),
22324                        diff_base_byte_range: hunk.diff_base_byte_range,
22325                        display_row_range: hunk_display_start.row()..end_row,
22326                        multi_buffer_range: Anchor::range_in_buffer(
22327                            hunk.excerpt_id,
22328                            hunk.buffer_id,
22329                            hunk.buffer_range,
22330                        ),
22331                        is_created_file,
22332                    }
22333                };
22334
22335                Some(display_hunk)
22336            })
22337    }
22338
22339    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22340        self.display_snapshot.buffer_snapshot.language_at(position)
22341    }
22342
22343    pub fn is_focused(&self) -> bool {
22344        self.is_focused
22345    }
22346
22347    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22348        self.placeholder_text.as_ref()
22349    }
22350
22351    pub fn scroll_position(&self) -> gpui::Point<f32> {
22352        self.scroll_anchor.scroll_position(&self.display_snapshot)
22353    }
22354
22355    fn gutter_dimensions(
22356        &self,
22357        font_id: FontId,
22358        font_size: Pixels,
22359        max_line_number_width: Pixels,
22360        cx: &App,
22361    ) -> Option<GutterDimensions> {
22362        if !self.show_gutter {
22363            return None;
22364        }
22365
22366        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22367        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22368
22369        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22370            matches!(
22371                ProjectSettings::get_global(cx).git.git_gutter,
22372                Some(GitGutterSetting::TrackedFiles)
22373            )
22374        });
22375        let gutter_settings = EditorSettings::get_global(cx).gutter;
22376        let show_line_numbers = self
22377            .show_line_numbers
22378            .unwrap_or(gutter_settings.line_numbers);
22379        let line_gutter_width = if show_line_numbers {
22380            // Avoid flicker-like gutter resizes when the line number gains another digit by
22381            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22382            let min_width_for_number_on_gutter =
22383                ch_advance * gutter_settings.min_line_number_digits as f32;
22384            max_line_number_width.max(min_width_for_number_on_gutter)
22385        } else {
22386            0.0.into()
22387        };
22388
22389        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22390        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22391
22392        let git_blame_entries_width =
22393            self.git_blame_gutter_max_author_length
22394                .map(|max_author_length| {
22395                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22396                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22397
22398                    /// The number of characters to dedicate to gaps and margins.
22399                    const SPACING_WIDTH: usize = 4;
22400
22401                    let max_char_count = max_author_length.min(renderer.max_author_length())
22402                        + ::git::SHORT_SHA_LENGTH
22403                        + MAX_RELATIVE_TIMESTAMP.len()
22404                        + SPACING_WIDTH;
22405
22406                    ch_advance * max_char_count
22407                });
22408
22409        let is_singleton = self.buffer_snapshot.is_singleton();
22410
22411        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22412        left_padding += if !is_singleton {
22413            ch_width * 4.0
22414        } else if show_runnables || show_breakpoints {
22415            ch_width * 3.0
22416        } else if show_git_gutter && show_line_numbers {
22417            ch_width * 2.0
22418        } else if show_git_gutter || show_line_numbers {
22419            ch_width
22420        } else {
22421            px(0.)
22422        };
22423
22424        let shows_folds = is_singleton && gutter_settings.folds;
22425
22426        let right_padding = if shows_folds && show_line_numbers {
22427            ch_width * 4.0
22428        } else if shows_folds || (!is_singleton && show_line_numbers) {
22429            ch_width * 3.0
22430        } else if show_line_numbers {
22431            ch_width
22432        } else {
22433            px(0.)
22434        };
22435
22436        Some(GutterDimensions {
22437            left_padding,
22438            right_padding,
22439            width: line_gutter_width + left_padding + right_padding,
22440            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22441            git_blame_entries_width,
22442        })
22443    }
22444
22445    pub fn render_crease_toggle(
22446        &self,
22447        buffer_row: MultiBufferRow,
22448        row_contains_cursor: bool,
22449        editor: Entity<Editor>,
22450        window: &mut Window,
22451        cx: &mut App,
22452    ) -> Option<AnyElement> {
22453        let folded = self.is_line_folded(buffer_row);
22454        let mut is_foldable = false;
22455
22456        if let Some(crease) = self
22457            .crease_snapshot
22458            .query_row(buffer_row, &self.buffer_snapshot)
22459        {
22460            is_foldable = true;
22461            match crease {
22462                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22463                    if let Some(render_toggle) = render_toggle {
22464                        let toggle_callback =
22465                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22466                                if folded {
22467                                    editor.update(cx, |editor, cx| {
22468                                        editor.fold_at(buffer_row, window, cx)
22469                                    });
22470                                } else {
22471                                    editor.update(cx, |editor, cx| {
22472                                        editor.unfold_at(buffer_row, window, cx)
22473                                    });
22474                                }
22475                            });
22476                        return Some((render_toggle)(
22477                            buffer_row,
22478                            folded,
22479                            toggle_callback,
22480                            window,
22481                            cx,
22482                        ));
22483                    }
22484                }
22485            }
22486        }
22487
22488        is_foldable |= self.starts_indent(buffer_row);
22489
22490        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22491            Some(
22492                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22493                    .toggle_state(folded)
22494                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22495                        if folded {
22496                            this.unfold_at(buffer_row, window, cx);
22497                        } else {
22498                            this.fold_at(buffer_row, window, cx);
22499                        }
22500                    }))
22501                    .into_any_element(),
22502            )
22503        } else {
22504            None
22505        }
22506    }
22507
22508    pub fn render_crease_trailer(
22509        &self,
22510        buffer_row: MultiBufferRow,
22511        window: &mut Window,
22512        cx: &mut App,
22513    ) -> Option<AnyElement> {
22514        let folded = self.is_line_folded(buffer_row);
22515        if let Crease::Inline { render_trailer, .. } = self
22516            .crease_snapshot
22517            .query_row(buffer_row, &self.buffer_snapshot)?
22518        {
22519            let render_trailer = render_trailer.as_ref()?;
22520            Some(render_trailer(buffer_row, folded, window, cx))
22521        } else {
22522            None
22523        }
22524    }
22525}
22526
22527impl Deref for EditorSnapshot {
22528    type Target = DisplaySnapshot;
22529
22530    fn deref(&self) -> &Self::Target {
22531        &self.display_snapshot
22532    }
22533}
22534
22535#[derive(Clone, Debug, PartialEq, Eq)]
22536pub enum EditorEvent {
22537    InputIgnored {
22538        text: Arc<str>,
22539    },
22540    InputHandled {
22541        utf16_range_to_replace: Option<Range<isize>>,
22542        text: Arc<str>,
22543    },
22544    ExcerptsAdded {
22545        buffer: Entity<Buffer>,
22546        predecessor: ExcerptId,
22547        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22548    },
22549    ExcerptsRemoved {
22550        ids: Vec<ExcerptId>,
22551        removed_buffer_ids: Vec<BufferId>,
22552    },
22553    BufferFoldToggled {
22554        ids: Vec<ExcerptId>,
22555        folded: bool,
22556    },
22557    ExcerptsEdited {
22558        ids: Vec<ExcerptId>,
22559    },
22560    ExcerptsExpanded {
22561        ids: Vec<ExcerptId>,
22562    },
22563    BufferEdited,
22564    Edited {
22565        transaction_id: clock::Lamport,
22566    },
22567    Reparsed(BufferId),
22568    Focused,
22569    FocusedIn,
22570    Blurred,
22571    DirtyChanged,
22572    Saved,
22573    TitleChanged,
22574    DiffBaseChanged,
22575    SelectionsChanged {
22576        local: bool,
22577    },
22578    ScrollPositionChanged {
22579        local: bool,
22580        autoscroll: bool,
22581    },
22582    Closed,
22583    TransactionUndone {
22584        transaction_id: clock::Lamport,
22585    },
22586    TransactionBegun {
22587        transaction_id: clock::Lamport,
22588    },
22589    Reloaded,
22590    CursorShapeChanged,
22591    PushedToNavHistory {
22592        anchor: Anchor,
22593        is_deactivate: bool,
22594    },
22595}
22596
22597impl EventEmitter<EditorEvent> for Editor {}
22598
22599impl Focusable for Editor {
22600    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22601        self.focus_handle.clone()
22602    }
22603}
22604
22605impl Render for Editor {
22606    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22607        let settings = ThemeSettings::get_global(cx);
22608
22609        let mut text_style = match self.mode {
22610            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22611                color: cx.theme().colors().editor_foreground,
22612                font_family: settings.ui_font.family.clone(),
22613                font_features: settings.ui_font.features.clone(),
22614                font_fallbacks: settings.ui_font.fallbacks.clone(),
22615                font_size: rems(0.875).into(),
22616                font_weight: settings.ui_font.weight,
22617                line_height: relative(settings.buffer_line_height.value()),
22618                ..Default::default()
22619            },
22620            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22621                color: cx.theme().colors().editor_foreground,
22622                font_family: settings.buffer_font.family.clone(),
22623                font_features: settings.buffer_font.features.clone(),
22624                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22625                font_size: settings.buffer_font_size(cx).into(),
22626                font_weight: settings.buffer_font.weight,
22627                line_height: relative(settings.buffer_line_height.value()),
22628                ..Default::default()
22629            },
22630        };
22631        if let Some(text_style_refinement) = &self.text_style_refinement {
22632            text_style.refine(text_style_refinement)
22633        }
22634
22635        let background = match self.mode {
22636            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22637            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22638            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22639            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22640        };
22641
22642        EditorElement::new(
22643            &cx.entity(),
22644            EditorStyle {
22645                background,
22646                border: cx.theme().colors().border,
22647                local_player: cx.theme().players().local(),
22648                text: text_style,
22649                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22650                syntax: cx.theme().syntax().clone(),
22651                status: cx.theme().status().clone(),
22652                inlay_hints_style: make_inlay_hints_style(cx),
22653                inline_completion_styles: make_suggestion_styles(cx),
22654                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22655                show_underlines: self.diagnostics_enabled(),
22656            },
22657        )
22658    }
22659}
22660
22661impl EntityInputHandler for Editor {
22662    fn text_for_range(
22663        &mut self,
22664        range_utf16: Range<usize>,
22665        adjusted_range: &mut Option<Range<usize>>,
22666        _: &mut Window,
22667        cx: &mut Context<Self>,
22668    ) -> Option<String> {
22669        let snapshot = self.buffer.read(cx).read(cx);
22670        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22671        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22672        if (start.0..end.0) != range_utf16 {
22673            adjusted_range.replace(start.0..end.0);
22674        }
22675        Some(snapshot.text_for_range(start..end).collect())
22676    }
22677
22678    fn selected_text_range(
22679        &mut self,
22680        ignore_disabled_input: bool,
22681        _: &mut Window,
22682        cx: &mut Context<Self>,
22683    ) -> Option<UTF16Selection> {
22684        // Prevent the IME menu from appearing when holding down an alphabetic key
22685        // while input is disabled.
22686        if !ignore_disabled_input && !self.input_enabled {
22687            return None;
22688        }
22689
22690        let selection = self.selections.newest::<OffsetUtf16>(cx);
22691        let range = selection.range();
22692
22693        Some(UTF16Selection {
22694            range: range.start.0..range.end.0,
22695            reversed: selection.reversed,
22696        })
22697    }
22698
22699    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22700        let snapshot = self.buffer.read(cx).read(cx);
22701        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22702        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22703    }
22704
22705    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22706        self.clear_highlights::<InputComposition>(cx);
22707        self.ime_transaction.take();
22708    }
22709
22710    fn replace_text_in_range(
22711        &mut self,
22712        range_utf16: Option<Range<usize>>,
22713        text: &str,
22714        window: &mut Window,
22715        cx: &mut Context<Self>,
22716    ) {
22717        if !self.input_enabled {
22718            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22719            return;
22720        }
22721
22722        self.transact(window, cx, |this, window, cx| {
22723            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22724                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22725                Some(this.selection_replacement_ranges(range_utf16, cx))
22726            } else {
22727                this.marked_text_ranges(cx)
22728            };
22729
22730            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22731                let newest_selection_id = this.selections.newest_anchor().id;
22732                this.selections
22733                    .all::<OffsetUtf16>(cx)
22734                    .iter()
22735                    .zip(ranges_to_replace.iter())
22736                    .find_map(|(selection, range)| {
22737                        if selection.id == newest_selection_id {
22738                            Some(
22739                                (range.start.0 as isize - selection.head().0 as isize)
22740                                    ..(range.end.0 as isize - selection.head().0 as isize),
22741                            )
22742                        } else {
22743                            None
22744                        }
22745                    })
22746            });
22747
22748            cx.emit(EditorEvent::InputHandled {
22749                utf16_range_to_replace: range_to_replace,
22750                text: text.into(),
22751            });
22752
22753            if let Some(new_selected_ranges) = new_selected_ranges {
22754                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22755                    selections.select_ranges(new_selected_ranges)
22756                });
22757                this.backspace(&Default::default(), window, cx);
22758            }
22759
22760            this.handle_input(text, window, cx);
22761        });
22762
22763        if let Some(transaction) = self.ime_transaction {
22764            self.buffer.update(cx, |buffer, cx| {
22765                buffer.group_until_transaction(transaction, cx);
22766            });
22767        }
22768
22769        self.unmark_text(window, cx);
22770    }
22771
22772    fn replace_and_mark_text_in_range(
22773        &mut self,
22774        range_utf16: Option<Range<usize>>,
22775        text: &str,
22776        new_selected_range_utf16: Option<Range<usize>>,
22777        window: &mut Window,
22778        cx: &mut Context<Self>,
22779    ) {
22780        if !self.input_enabled {
22781            return;
22782        }
22783
22784        let transaction = self.transact(window, cx, |this, window, cx| {
22785            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22786                let snapshot = this.buffer.read(cx).read(cx);
22787                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22788                    for marked_range in &mut marked_ranges {
22789                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22790                        marked_range.start.0 += relative_range_utf16.start;
22791                        marked_range.start =
22792                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22793                        marked_range.end =
22794                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22795                    }
22796                }
22797                Some(marked_ranges)
22798            } else if let Some(range_utf16) = range_utf16 {
22799                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22800                Some(this.selection_replacement_ranges(range_utf16, cx))
22801            } else {
22802                None
22803            };
22804
22805            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22806                let newest_selection_id = this.selections.newest_anchor().id;
22807                this.selections
22808                    .all::<OffsetUtf16>(cx)
22809                    .iter()
22810                    .zip(ranges_to_replace.iter())
22811                    .find_map(|(selection, range)| {
22812                        if selection.id == newest_selection_id {
22813                            Some(
22814                                (range.start.0 as isize - selection.head().0 as isize)
22815                                    ..(range.end.0 as isize - selection.head().0 as isize),
22816                            )
22817                        } else {
22818                            None
22819                        }
22820                    })
22821            });
22822
22823            cx.emit(EditorEvent::InputHandled {
22824                utf16_range_to_replace: range_to_replace,
22825                text: text.into(),
22826            });
22827
22828            if let Some(ranges) = ranges_to_replace {
22829                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22830                    s.select_ranges(ranges)
22831                });
22832            }
22833
22834            let marked_ranges = {
22835                let snapshot = this.buffer.read(cx).read(cx);
22836                this.selections
22837                    .disjoint_anchors()
22838                    .iter()
22839                    .map(|selection| {
22840                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22841                    })
22842                    .collect::<Vec<_>>()
22843            };
22844
22845            if text.is_empty() {
22846                this.unmark_text(window, cx);
22847            } else {
22848                this.highlight_text::<InputComposition>(
22849                    marked_ranges.clone(),
22850                    HighlightStyle {
22851                        underline: Some(UnderlineStyle {
22852                            thickness: px(1.),
22853                            color: None,
22854                            wavy: false,
22855                        }),
22856                        ..Default::default()
22857                    },
22858                    cx,
22859                );
22860            }
22861
22862            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22863            let use_autoclose = this.use_autoclose;
22864            let use_auto_surround = this.use_auto_surround;
22865            this.set_use_autoclose(false);
22866            this.set_use_auto_surround(false);
22867            this.handle_input(text, window, cx);
22868            this.set_use_autoclose(use_autoclose);
22869            this.set_use_auto_surround(use_auto_surround);
22870
22871            if let Some(new_selected_range) = new_selected_range_utf16 {
22872                let snapshot = this.buffer.read(cx).read(cx);
22873                let new_selected_ranges = marked_ranges
22874                    .into_iter()
22875                    .map(|marked_range| {
22876                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22877                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22878                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22879                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22880                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22881                    })
22882                    .collect::<Vec<_>>();
22883
22884                drop(snapshot);
22885                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22886                    selections.select_ranges(new_selected_ranges)
22887                });
22888            }
22889        });
22890
22891        self.ime_transaction = self.ime_transaction.or(transaction);
22892        if let Some(transaction) = self.ime_transaction {
22893            self.buffer.update(cx, |buffer, cx| {
22894                buffer.group_until_transaction(transaction, cx);
22895            });
22896        }
22897
22898        if self.text_highlights::<InputComposition>(cx).is_none() {
22899            self.ime_transaction.take();
22900        }
22901    }
22902
22903    fn bounds_for_range(
22904        &mut self,
22905        range_utf16: Range<usize>,
22906        element_bounds: gpui::Bounds<Pixels>,
22907        window: &mut Window,
22908        cx: &mut Context<Self>,
22909    ) -> Option<gpui::Bounds<Pixels>> {
22910        let text_layout_details = self.text_layout_details(window);
22911        let CharacterDimensions {
22912            em_width,
22913            em_advance,
22914            line_height,
22915        } = self.character_dimensions(window);
22916
22917        let snapshot = self.snapshot(window, cx);
22918        let scroll_position = snapshot.scroll_position();
22919        let scroll_left = scroll_position.x * em_advance;
22920
22921        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22922        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22923            + self.gutter_dimensions.full_width();
22924        let y = line_height * (start.row().as_f32() - scroll_position.y);
22925
22926        Some(Bounds {
22927            origin: element_bounds.origin + point(x, y),
22928            size: size(em_width, line_height),
22929        })
22930    }
22931
22932    fn character_index_for_point(
22933        &mut self,
22934        point: gpui::Point<Pixels>,
22935        _window: &mut Window,
22936        _cx: &mut Context<Self>,
22937    ) -> Option<usize> {
22938        let position_map = self.last_position_map.as_ref()?;
22939        if !position_map.text_hitbox.contains(&point) {
22940            return None;
22941        }
22942        let display_point = position_map.point_for_position(point).previous_valid;
22943        let anchor = position_map
22944            .snapshot
22945            .display_point_to_anchor(display_point, Bias::Left);
22946        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22947        Some(utf16_offset.0)
22948    }
22949}
22950
22951trait SelectionExt {
22952    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22953    fn spanned_rows(
22954        &self,
22955        include_end_if_at_line_start: bool,
22956        map: &DisplaySnapshot,
22957    ) -> Range<MultiBufferRow>;
22958}
22959
22960impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22961    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22962        let start = self
22963            .start
22964            .to_point(&map.buffer_snapshot)
22965            .to_display_point(map);
22966        let end = self
22967            .end
22968            .to_point(&map.buffer_snapshot)
22969            .to_display_point(map);
22970        if self.reversed {
22971            end..start
22972        } else {
22973            start..end
22974        }
22975    }
22976
22977    fn spanned_rows(
22978        &self,
22979        include_end_if_at_line_start: bool,
22980        map: &DisplaySnapshot,
22981    ) -> Range<MultiBufferRow> {
22982        let start = self.start.to_point(&map.buffer_snapshot);
22983        let mut end = self.end.to_point(&map.buffer_snapshot);
22984        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22985            end.row -= 1;
22986        }
22987
22988        let buffer_start = map.prev_line_boundary(start).0;
22989        let buffer_end = map.next_line_boundary(end).0;
22990        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22991    }
22992}
22993
22994impl<T: InvalidationRegion> InvalidationStack<T> {
22995    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22996    where
22997        S: Clone + ToOffset,
22998    {
22999        while let Some(region) = self.last() {
23000            let all_selections_inside_invalidation_ranges =
23001                if selections.len() == region.ranges().len() {
23002                    selections
23003                        .iter()
23004                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23005                        .all(|(selection, invalidation_range)| {
23006                            let head = selection.head().to_offset(buffer);
23007                            invalidation_range.start <= head && invalidation_range.end >= head
23008                        })
23009                } else {
23010                    false
23011                };
23012
23013            if all_selections_inside_invalidation_ranges {
23014                break;
23015            } else {
23016                self.pop();
23017            }
23018        }
23019    }
23020}
23021
23022impl<T> Default for InvalidationStack<T> {
23023    fn default() -> Self {
23024        Self(Default::default())
23025    }
23026}
23027
23028impl<T> Deref for InvalidationStack<T> {
23029    type Target = Vec<T>;
23030
23031    fn deref(&self) -> &Self::Target {
23032        &self.0
23033    }
23034}
23035
23036impl<T> DerefMut for InvalidationStack<T> {
23037    fn deref_mut(&mut self) -> &mut Self::Target {
23038        &mut self.0
23039    }
23040}
23041
23042impl InvalidationRegion for SnippetState {
23043    fn ranges(&self) -> &[Range<Anchor>] {
23044        &self.ranges[self.active_index]
23045    }
23046}
23047
23048fn inline_completion_edit_text(
23049    current_snapshot: &BufferSnapshot,
23050    edits: &[(Range<Anchor>, String)],
23051    edit_preview: &EditPreview,
23052    include_deletions: bool,
23053    cx: &App,
23054) -> HighlightedText {
23055    let edits = edits
23056        .iter()
23057        .map(|(anchor, text)| {
23058            (
23059                anchor.start.text_anchor..anchor.end.text_anchor,
23060                text.clone(),
23061            )
23062        })
23063        .collect::<Vec<_>>();
23064
23065    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23066}
23067
23068pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23069    match severity {
23070        lsp::DiagnosticSeverity::ERROR => colors.error,
23071        lsp::DiagnosticSeverity::WARNING => colors.warning,
23072        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23073        lsp::DiagnosticSeverity::HINT => colors.info,
23074        _ => colors.ignored,
23075    }
23076}
23077
23078pub fn styled_runs_for_code_label<'a>(
23079    label: &'a CodeLabel,
23080    syntax_theme: &'a theme::SyntaxTheme,
23081) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23082    let fade_out = HighlightStyle {
23083        fade_out: Some(0.35),
23084        ..Default::default()
23085    };
23086
23087    let mut prev_end = label.filter_range.end;
23088    label
23089        .runs
23090        .iter()
23091        .enumerate()
23092        .flat_map(move |(ix, (range, highlight_id))| {
23093            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23094                style
23095            } else {
23096                return Default::default();
23097            };
23098            let mut muted_style = style;
23099            muted_style.highlight(fade_out);
23100
23101            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23102            if range.start >= label.filter_range.end {
23103                if range.start > prev_end {
23104                    runs.push((prev_end..range.start, fade_out));
23105                }
23106                runs.push((range.clone(), muted_style));
23107            } else if range.end <= label.filter_range.end {
23108                runs.push((range.clone(), style));
23109            } else {
23110                runs.push((range.start..label.filter_range.end, style));
23111                runs.push((label.filter_range.end..range.end, muted_style));
23112            }
23113            prev_end = cmp::max(prev_end, range.end);
23114
23115            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23116                runs.push((prev_end..label.text.len(), fade_out));
23117            }
23118
23119            runs
23120        })
23121}
23122
23123pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23124    let mut prev_index = 0;
23125    let mut prev_codepoint: Option<char> = None;
23126    text.char_indices()
23127        .chain([(text.len(), '\0')])
23128        .filter_map(move |(index, codepoint)| {
23129            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23130            let is_boundary = index == text.len()
23131                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23132                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23133            if is_boundary {
23134                let chunk = &text[prev_index..index];
23135                prev_index = index;
23136                Some(chunk)
23137            } else {
23138                None
23139            }
23140        })
23141}
23142
23143pub trait RangeToAnchorExt: Sized {
23144    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23145
23146    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23147        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23148        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23149    }
23150}
23151
23152impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23153    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23154        let start_offset = self.start.to_offset(snapshot);
23155        let end_offset = self.end.to_offset(snapshot);
23156        if start_offset == end_offset {
23157            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23158        } else {
23159            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23160        }
23161    }
23162}
23163
23164pub trait RowExt {
23165    fn as_f32(&self) -> f32;
23166
23167    fn next_row(&self) -> Self;
23168
23169    fn previous_row(&self) -> Self;
23170
23171    fn minus(&self, other: Self) -> u32;
23172}
23173
23174impl RowExt for DisplayRow {
23175    fn as_f32(&self) -> f32 {
23176        self.0 as f32
23177    }
23178
23179    fn next_row(&self) -> Self {
23180        Self(self.0 + 1)
23181    }
23182
23183    fn previous_row(&self) -> Self {
23184        Self(self.0.saturating_sub(1))
23185    }
23186
23187    fn minus(&self, other: Self) -> u32 {
23188        self.0 - other.0
23189    }
23190}
23191
23192impl RowExt for MultiBufferRow {
23193    fn as_f32(&self) -> f32 {
23194        self.0 as f32
23195    }
23196
23197    fn next_row(&self) -> Self {
23198        Self(self.0 + 1)
23199    }
23200
23201    fn previous_row(&self) -> Self {
23202        Self(self.0.saturating_sub(1))
23203    }
23204
23205    fn minus(&self, other: Self) -> u32 {
23206        self.0 - other.0
23207    }
23208}
23209
23210trait RowRangeExt {
23211    type Row;
23212
23213    fn len(&self) -> usize;
23214
23215    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23216}
23217
23218impl RowRangeExt for Range<MultiBufferRow> {
23219    type Row = MultiBufferRow;
23220
23221    fn len(&self) -> usize {
23222        (self.end.0 - self.start.0) as usize
23223    }
23224
23225    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23226        (self.start.0..self.end.0).map(MultiBufferRow)
23227    }
23228}
23229
23230impl RowRangeExt for Range<DisplayRow> {
23231    type Row = DisplayRow;
23232
23233    fn len(&self) -> usize {
23234        (self.end.0 - self.start.0) as usize
23235    }
23236
23237    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23238        (self.start.0..self.end.0).map(DisplayRow)
23239    }
23240}
23241
23242/// If select range has more than one line, we
23243/// just point the cursor to range.start.
23244fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23245    if range.start.row == range.end.row {
23246        range
23247    } else {
23248        range.start..range.start
23249    }
23250}
23251pub struct KillRing(ClipboardItem);
23252impl Global for KillRing {}
23253
23254const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23255
23256enum BreakpointPromptEditAction {
23257    Log,
23258    Condition,
23259    HitCondition,
23260}
23261
23262struct BreakpointPromptEditor {
23263    pub(crate) prompt: Entity<Editor>,
23264    editor: WeakEntity<Editor>,
23265    breakpoint_anchor: Anchor,
23266    breakpoint: Breakpoint,
23267    edit_action: BreakpointPromptEditAction,
23268    block_ids: HashSet<CustomBlockId>,
23269    editor_margins: Arc<Mutex<EditorMargins>>,
23270    _subscriptions: Vec<Subscription>,
23271}
23272
23273impl BreakpointPromptEditor {
23274    const MAX_LINES: u8 = 4;
23275
23276    fn new(
23277        editor: WeakEntity<Editor>,
23278        breakpoint_anchor: Anchor,
23279        breakpoint: Breakpoint,
23280        edit_action: BreakpointPromptEditAction,
23281        window: &mut Window,
23282        cx: &mut Context<Self>,
23283    ) -> Self {
23284        let base_text = match edit_action {
23285            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23286            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23287            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23288        }
23289        .map(|msg| msg.to_string())
23290        .unwrap_or_default();
23291
23292        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23293        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23294
23295        let prompt = cx.new(|cx| {
23296            let mut prompt = Editor::new(
23297                EditorMode::AutoHeight {
23298                    min_lines: 1,
23299                    max_lines: Some(Self::MAX_LINES as usize),
23300                },
23301                buffer,
23302                None,
23303                window,
23304                cx,
23305            );
23306            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23307            prompt.set_show_cursor_when_unfocused(false, cx);
23308            prompt.set_placeholder_text(
23309                match edit_action {
23310                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23311                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23312                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23313                },
23314                cx,
23315            );
23316
23317            prompt
23318        });
23319
23320        Self {
23321            prompt,
23322            editor,
23323            breakpoint_anchor,
23324            breakpoint,
23325            edit_action,
23326            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23327            block_ids: Default::default(),
23328            _subscriptions: vec![],
23329        }
23330    }
23331
23332    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23333        self.block_ids.extend(block_ids)
23334    }
23335
23336    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23337        if let Some(editor) = self.editor.upgrade() {
23338            let message = self
23339                .prompt
23340                .read(cx)
23341                .buffer
23342                .read(cx)
23343                .as_singleton()
23344                .expect("A multi buffer in breakpoint prompt isn't possible")
23345                .read(cx)
23346                .as_rope()
23347                .to_string();
23348
23349            editor.update(cx, |editor, cx| {
23350                editor.edit_breakpoint_at_anchor(
23351                    self.breakpoint_anchor,
23352                    self.breakpoint.clone(),
23353                    match self.edit_action {
23354                        BreakpointPromptEditAction::Log => {
23355                            BreakpointEditAction::EditLogMessage(message.into())
23356                        }
23357                        BreakpointPromptEditAction::Condition => {
23358                            BreakpointEditAction::EditCondition(message.into())
23359                        }
23360                        BreakpointPromptEditAction::HitCondition => {
23361                            BreakpointEditAction::EditHitCondition(message.into())
23362                        }
23363                    },
23364                    cx,
23365                );
23366
23367                editor.remove_blocks(self.block_ids.clone(), None, cx);
23368                cx.focus_self(window);
23369            });
23370        }
23371    }
23372
23373    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23374        self.editor
23375            .update(cx, |editor, cx| {
23376                editor.remove_blocks(self.block_ids.clone(), None, cx);
23377                window.focus(&editor.focus_handle);
23378            })
23379            .log_err();
23380    }
23381
23382    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23383        let settings = ThemeSettings::get_global(cx);
23384        let text_style = TextStyle {
23385            color: if self.prompt.read(cx).read_only(cx) {
23386                cx.theme().colors().text_disabled
23387            } else {
23388                cx.theme().colors().text
23389            },
23390            font_family: settings.buffer_font.family.clone(),
23391            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23392            font_size: settings.buffer_font_size(cx).into(),
23393            font_weight: settings.buffer_font.weight,
23394            line_height: relative(settings.buffer_line_height.value()),
23395            ..Default::default()
23396        };
23397        EditorElement::new(
23398            &self.prompt,
23399            EditorStyle {
23400                background: cx.theme().colors().editor_background,
23401                local_player: cx.theme().players().local(),
23402                text: text_style,
23403                ..Default::default()
23404            },
23405        )
23406    }
23407}
23408
23409impl Render for BreakpointPromptEditor {
23410    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23411        let editor_margins = *self.editor_margins.lock();
23412        let gutter_dimensions = editor_margins.gutter;
23413        h_flex()
23414            .key_context("Editor")
23415            .bg(cx.theme().colors().editor_background)
23416            .border_y_1()
23417            .border_color(cx.theme().status().info_border)
23418            .size_full()
23419            .py(window.line_height() / 2.5)
23420            .on_action(cx.listener(Self::confirm))
23421            .on_action(cx.listener(Self::cancel))
23422            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23423            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23424    }
23425}
23426
23427impl Focusable for BreakpointPromptEditor {
23428    fn focus_handle(&self, cx: &App) -> FocusHandle {
23429        self.prompt.focus_handle(cx)
23430    }
23431}
23432
23433fn all_edits_insertions_or_deletions(
23434    edits: &Vec<(Range<Anchor>, String)>,
23435    snapshot: &MultiBufferSnapshot,
23436) -> bool {
23437    let mut all_insertions = true;
23438    let mut all_deletions = true;
23439
23440    for (range, new_text) in edits.iter() {
23441        let range_is_empty = range.to_offset(&snapshot).is_empty();
23442        let text_is_empty = new_text.is_empty();
23443
23444        if range_is_empty != text_is_empty {
23445            if range_is_empty {
23446                all_deletions = false;
23447            } else {
23448                all_insertions = false;
23449            }
23450        } else {
23451            return false;
23452        }
23453
23454        if !all_insertions && !all_deletions {
23455            return false;
23456        }
23457    }
23458    all_insertions || all_deletions
23459}
23460
23461struct MissingEditPredictionKeybindingTooltip;
23462
23463impl Render for MissingEditPredictionKeybindingTooltip {
23464    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23465        ui::tooltip_container(window, cx, |container, _, cx| {
23466            container
23467                .flex_shrink_0()
23468                .max_w_80()
23469                .min_h(rems_from_px(124.))
23470                .justify_between()
23471                .child(
23472                    v_flex()
23473                        .flex_1()
23474                        .text_ui_sm(cx)
23475                        .child(Label::new("Conflict with Accept Keybinding"))
23476                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23477                )
23478                .child(
23479                    h_flex()
23480                        .pb_1()
23481                        .gap_1()
23482                        .items_end()
23483                        .w_full()
23484                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23485                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23486                        }))
23487                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23488                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23489                        })),
23490                )
23491        })
23492    }
23493}
23494
23495#[derive(Debug, Clone, Copy, PartialEq)]
23496pub struct LineHighlight {
23497    pub background: Background,
23498    pub border: Option<gpui::Hsla>,
23499    pub include_gutter: bool,
23500    pub type_id: Option<TypeId>,
23501}
23502
23503struct LineManipulationResult {
23504    pub new_text: String,
23505    pub line_count_before: usize,
23506    pub line_count_after: usize,
23507}
23508
23509fn render_diff_hunk_controls(
23510    row: u32,
23511    status: &DiffHunkStatus,
23512    hunk_range: Range<Anchor>,
23513    is_created_file: bool,
23514    line_height: Pixels,
23515    editor: &Entity<Editor>,
23516    _window: &mut Window,
23517    cx: &mut App,
23518) -> AnyElement {
23519    h_flex()
23520        .h(line_height)
23521        .mr_1()
23522        .gap_1()
23523        .px_0p5()
23524        .pb_1()
23525        .border_x_1()
23526        .border_b_1()
23527        .border_color(cx.theme().colors().border_variant)
23528        .rounded_b_lg()
23529        .bg(cx.theme().colors().editor_background)
23530        .gap_1()
23531        .block_mouse_except_scroll()
23532        .shadow_md()
23533        .child(if status.has_secondary_hunk() {
23534            Button::new(("stage", row as u64), "Stage")
23535                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23536                .tooltip({
23537                    let focus_handle = editor.focus_handle(cx);
23538                    move |window, cx| {
23539                        Tooltip::for_action_in(
23540                            "Stage Hunk",
23541                            &::git::ToggleStaged,
23542                            &focus_handle,
23543                            window,
23544                            cx,
23545                        )
23546                    }
23547                })
23548                .on_click({
23549                    let editor = editor.clone();
23550                    move |_event, _window, cx| {
23551                        editor.update(cx, |editor, cx| {
23552                            editor.stage_or_unstage_diff_hunks(
23553                                true,
23554                                vec![hunk_range.start..hunk_range.start],
23555                                cx,
23556                            );
23557                        });
23558                    }
23559                })
23560        } else {
23561            Button::new(("unstage", row as u64), "Unstage")
23562                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23563                .tooltip({
23564                    let focus_handle = editor.focus_handle(cx);
23565                    move |window, cx| {
23566                        Tooltip::for_action_in(
23567                            "Unstage Hunk",
23568                            &::git::ToggleStaged,
23569                            &focus_handle,
23570                            window,
23571                            cx,
23572                        )
23573                    }
23574                })
23575                .on_click({
23576                    let editor = editor.clone();
23577                    move |_event, _window, cx| {
23578                        editor.update(cx, |editor, cx| {
23579                            editor.stage_or_unstage_diff_hunks(
23580                                false,
23581                                vec![hunk_range.start..hunk_range.start],
23582                                cx,
23583                            );
23584                        });
23585                    }
23586                })
23587        })
23588        .child(
23589            Button::new(("restore", row as u64), "Restore")
23590                .tooltip({
23591                    let focus_handle = editor.focus_handle(cx);
23592                    move |window, cx| {
23593                        Tooltip::for_action_in(
23594                            "Restore Hunk",
23595                            &::git::Restore,
23596                            &focus_handle,
23597                            window,
23598                            cx,
23599                        )
23600                    }
23601                })
23602                .on_click({
23603                    let editor = editor.clone();
23604                    move |_event, window, cx| {
23605                        editor.update(cx, |editor, cx| {
23606                            let snapshot = editor.snapshot(window, cx);
23607                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23608                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23609                        });
23610                    }
23611                })
23612                .disabled(is_created_file),
23613        )
23614        .when(
23615            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23616            |el| {
23617                el.child(
23618                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23619                        .shape(IconButtonShape::Square)
23620                        .icon_size(IconSize::Small)
23621                        // .disabled(!has_multiple_hunks)
23622                        .tooltip({
23623                            let focus_handle = editor.focus_handle(cx);
23624                            move |window, cx| {
23625                                Tooltip::for_action_in(
23626                                    "Next Hunk",
23627                                    &GoToHunk,
23628                                    &focus_handle,
23629                                    window,
23630                                    cx,
23631                                )
23632                            }
23633                        })
23634                        .on_click({
23635                            let editor = editor.clone();
23636                            move |_event, window, cx| {
23637                                editor.update(cx, |editor, cx| {
23638                                    let snapshot = editor.snapshot(window, cx);
23639                                    let position =
23640                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23641                                    editor.go_to_hunk_before_or_after_position(
23642                                        &snapshot,
23643                                        position,
23644                                        Direction::Next,
23645                                        window,
23646                                        cx,
23647                                    );
23648                                    editor.expand_selected_diff_hunks(cx);
23649                                });
23650                            }
23651                        }),
23652                )
23653                .child(
23654                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23655                        .shape(IconButtonShape::Square)
23656                        .icon_size(IconSize::Small)
23657                        // .disabled(!has_multiple_hunks)
23658                        .tooltip({
23659                            let focus_handle = editor.focus_handle(cx);
23660                            move |window, cx| {
23661                                Tooltip::for_action_in(
23662                                    "Previous Hunk",
23663                                    &GoToPreviousHunk,
23664                                    &focus_handle,
23665                                    window,
23666                                    cx,
23667                                )
23668                            }
23669                        })
23670                        .on_click({
23671                            let editor = editor.clone();
23672                            move |_event, window, cx| {
23673                                editor.update(cx, |editor, cx| {
23674                                    let snapshot = editor.snapshot(window, cx);
23675                                    let point =
23676                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23677                                    editor.go_to_hunk_before_or_after_position(
23678                                        &snapshot,
23679                                        point,
23680                                        Direction::Prev,
23681                                        window,
23682                                        cx,
23683                                    );
23684                                    editor.expand_selected_diff_hunks(cx);
23685                                });
23686                            }
23687                        }),
23688                )
23689            },
23690        )
23691        .into_any_element()
23692}