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(_)) => {
 2386                key_context.add("menu");
 2387                key_context.add("showing_completions");
 2388            }
 2389            Some(CodeContextMenu::CodeActions(_)) => {
 2390                key_context.add("menu");
 2391                key_context.add("showing_code_actions")
 2392            }
 2393            None => {}
 2394        }
 2395
 2396        if self.signature_help_state.has_multiple_signatures() {
 2397            key_context.add("showing_signature_help");
 2398        }
 2399
 2400        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2401        if !self.focus_handle(cx).contains_focused(window, cx)
 2402            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2403        {
 2404            for addon in self.addons.values() {
 2405                addon.extend_key_context(&mut key_context, cx)
 2406            }
 2407        }
 2408
 2409        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2410            if let Some(extension) = singleton_buffer
 2411                .read(cx)
 2412                .file()
 2413                .and_then(|file| file.path().extension()?.to_str())
 2414            {
 2415                key_context.set("extension", extension.to_string());
 2416            }
 2417        } else {
 2418            key_context.add("multibuffer");
 2419        }
 2420
 2421        if has_active_edit_prediction {
 2422            if self.edit_prediction_in_conflict() {
 2423                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2424            } else {
 2425                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2426                key_context.add("copilot_suggestion");
 2427            }
 2428        }
 2429
 2430        if self.selection_mark_mode {
 2431            key_context.add("selection_mode");
 2432        }
 2433
 2434        key_context
 2435    }
 2436
 2437    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2438        if self.mouse_cursor_hidden {
 2439            self.mouse_cursor_hidden = false;
 2440            cx.notify();
 2441        }
 2442    }
 2443
 2444    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2445        let hide_mouse_cursor = match origin {
 2446            HideMouseCursorOrigin::TypingAction => {
 2447                matches!(
 2448                    self.hide_mouse_mode,
 2449                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2450                )
 2451            }
 2452            HideMouseCursorOrigin::MovementAction => {
 2453                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2454            }
 2455        };
 2456        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2457            self.mouse_cursor_hidden = hide_mouse_cursor;
 2458            cx.notify();
 2459        }
 2460    }
 2461
 2462    pub fn edit_prediction_in_conflict(&self) -> bool {
 2463        if !self.show_edit_predictions_in_menu() {
 2464            return false;
 2465        }
 2466
 2467        let showing_completions = self
 2468            .context_menu
 2469            .borrow()
 2470            .as_ref()
 2471            .map_or(false, |context| {
 2472                matches!(context, CodeContextMenu::Completions(_))
 2473            });
 2474
 2475        showing_completions
 2476            || self.edit_prediction_requires_modifier()
 2477            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2478            // bindings to insert tab characters.
 2479            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2480    }
 2481
 2482    pub fn accept_edit_prediction_keybind(
 2483        &self,
 2484        accept_partial: bool,
 2485        window: &Window,
 2486        cx: &App,
 2487    ) -> AcceptEditPredictionBinding {
 2488        let key_context = self.key_context_internal(true, window, cx);
 2489        let in_conflict = self.edit_prediction_in_conflict();
 2490
 2491        let bindings = if accept_partial {
 2492            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2493        } else {
 2494            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2495        };
 2496
 2497        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2498        // just the first one.
 2499        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2500            !in_conflict
 2501                || binding
 2502                    .keystrokes()
 2503                    .first()
 2504                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2505        }))
 2506    }
 2507
 2508    pub fn new_file(
 2509        workspace: &mut Workspace,
 2510        _: &workspace::NewFile,
 2511        window: &mut Window,
 2512        cx: &mut Context<Workspace>,
 2513    ) {
 2514        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2515            "Failed to create buffer",
 2516            window,
 2517            cx,
 2518            |e, _, _| match e.error_code() {
 2519                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2520                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2521                e.error_tag("required").unwrap_or("the latest version")
 2522            )),
 2523                _ => None,
 2524            },
 2525        );
 2526    }
 2527
 2528    pub fn new_in_workspace(
 2529        workspace: &mut Workspace,
 2530        window: &mut Window,
 2531        cx: &mut Context<Workspace>,
 2532    ) -> Task<Result<Entity<Editor>>> {
 2533        let project = workspace.project().clone();
 2534        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2535
 2536        cx.spawn_in(window, async move |workspace, cx| {
 2537            let buffer = create.await?;
 2538            workspace.update_in(cx, |workspace, window, cx| {
 2539                let editor =
 2540                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2541                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2542                editor
 2543            })
 2544        })
 2545    }
 2546
 2547    fn new_file_vertical(
 2548        workspace: &mut Workspace,
 2549        _: &workspace::NewFileSplitVertical,
 2550        window: &mut Window,
 2551        cx: &mut Context<Workspace>,
 2552    ) {
 2553        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2554    }
 2555
 2556    fn new_file_horizontal(
 2557        workspace: &mut Workspace,
 2558        _: &workspace::NewFileSplitHorizontal,
 2559        window: &mut Window,
 2560        cx: &mut Context<Workspace>,
 2561    ) {
 2562        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2563    }
 2564
 2565    fn new_file_in_direction(
 2566        workspace: &mut Workspace,
 2567        direction: SplitDirection,
 2568        window: &mut Window,
 2569        cx: &mut Context<Workspace>,
 2570    ) {
 2571        let project = workspace.project().clone();
 2572        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2573
 2574        cx.spawn_in(window, async move |workspace, cx| {
 2575            let buffer = create.await?;
 2576            workspace.update_in(cx, move |workspace, window, cx| {
 2577                workspace.split_item(
 2578                    direction,
 2579                    Box::new(
 2580                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2581                    ),
 2582                    window,
 2583                    cx,
 2584                )
 2585            })?;
 2586            anyhow::Ok(())
 2587        })
 2588        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2589            match e.error_code() {
 2590                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2591                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2592                e.error_tag("required").unwrap_or("the latest version")
 2593            )),
 2594                _ => None,
 2595            }
 2596        });
 2597    }
 2598
 2599    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2600        self.leader_id
 2601    }
 2602
 2603    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2604        &self.buffer
 2605    }
 2606
 2607    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2608        self.workspace.as_ref()?.0.upgrade()
 2609    }
 2610
 2611    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2612        self.buffer().read(cx).title(cx)
 2613    }
 2614
 2615    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2616        let git_blame_gutter_max_author_length = self
 2617            .render_git_blame_gutter(cx)
 2618            .then(|| {
 2619                if let Some(blame) = self.blame.as_ref() {
 2620                    let max_author_length =
 2621                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2622                    Some(max_author_length)
 2623                } else {
 2624                    None
 2625                }
 2626            })
 2627            .flatten();
 2628
 2629        EditorSnapshot {
 2630            mode: self.mode.clone(),
 2631            show_gutter: self.show_gutter,
 2632            show_line_numbers: self.show_line_numbers,
 2633            show_git_diff_gutter: self.show_git_diff_gutter,
 2634            show_code_actions: self.show_code_actions,
 2635            show_runnables: self.show_runnables,
 2636            show_breakpoints: self.show_breakpoints,
 2637            git_blame_gutter_max_author_length,
 2638            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2639            scroll_anchor: self.scroll_manager.anchor(),
 2640            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2641            placeholder_text: self.placeholder_text.clone(),
 2642            is_focused: self.focus_handle.is_focused(window),
 2643            current_line_highlight: self
 2644                .current_line_highlight
 2645                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2646            gutter_hovered: self.gutter_hovered,
 2647        }
 2648    }
 2649
 2650    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2651        self.buffer.read(cx).language_at(point, cx)
 2652    }
 2653
 2654    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2655        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2656    }
 2657
 2658    pub fn active_excerpt(
 2659        &self,
 2660        cx: &App,
 2661    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2662        self.buffer
 2663            .read(cx)
 2664            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2665    }
 2666
 2667    pub fn mode(&self) -> &EditorMode {
 2668        &self.mode
 2669    }
 2670
 2671    pub fn set_mode(&mut self, mode: EditorMode) {
 2672        self.mode = mode;
 2673    }
 2674
 2675    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2676        self.collaboration_hub.as_deref()
 2677    }
 2678
 2679    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2680        self.collaboration_hub = Some(hub);
 2681    }
 2682
 2683    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2684        self.in_project_search = in_project_search;
 2685    }
 2686
 2687    pub fn set_custom_context_menu(
 2688        &mut self,
 2689        f: impl 'static
 2690        + Fn(
 2691            &mut Self,
 2692            DisplayPoint,
 2693            &mut Window,
 2694            &mut Context<Self>,
 2695        ) -> Option<Entity<ui::ContextMenu>>,
 2696    ) {
 2697        self.custom_context_menu = Some(Box::new(f))
 2698    }
 2699
 2700    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2701        self.completion_provider = provider;
 2702    }
 2703
 2704    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2705        self.semantics_provider.clone()
 2706    }
 2707
 2708    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2709        self.semantics_provider = provider;
 2710    }
 2711
 2712    pub fn set_edit_prediction_provider<T>(
 2713        &mut self,
 2714        provider: Option<Entity<T>>,
 2715        window: &mut Window,
 2716        cx: &mut Context<Self>,
 2717    ) where
 2718        T: EditPredictionProvider,
 2719    {
 2720        self.edit_prediction_provider =
 2721            provider.map(|provider| RegisteredInlineCompletionProvider {
 2722                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2723                    if this.focus_handle.is_focused(window) {
 2724                        this.update_visible_inline_completion(window, cx);
 2725                    }
 2726                }),
 2727                provider: Arc::new(provider),
 2728            });
 2729        self.update_edit_prediction_settings(cx);
 2730        self.refresh_inline_completion(false, false, window, cx);
 2731    }
 2732
 2733    pub fn placeholder_text(&self) -> Option<&str> {
 2734        self.placeholder_text.as_deref()
 2735    }
 2736
 2737    pub fn set_placeholder_text(
 2738        &mut self,
 2739        placeholder_text: impl Into<Arc<str>>,
 2740        cx: &mut Context<Self>,
 2741    ) {
 2742        let placeholder_text = Some(placeholder_text.into());
 2743        if self.placeholder_text != placeholder_text {
 2744            self.placeholder_text = placeholder_text;
 2745            cx.notify();
 2746        }
 2747    }
 2748
 2749    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2750        self.cursor_shape = cursor_shape;
 2751
 2752        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2753        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2754
 2755        cx.notify();
 2756    }
 2757
 2758    pub fn set_current_line_highlight(
 2759        &mut self,
 2760        current_line_highlight: Option<CurrentLineHighlight>,
 2761    ) {
 2762        self.current_line_highlight = current_line_highlight;
 2763    }
 2764
 2765    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2766        self.collapse_matches = collapse_matches;
 2767    }
 2768
 2769    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2770        let buffers = self.buffer.read(cx).all_buffers();
 2771        let Some(project) = self.project.as_ref() else {
 2772            return;
 2773        };
 2774        project.update(cx, |project, cx| {
 2775            for buffer in buffers {
 2776                self.registered_buffers
 2777                    .entry(buffer.read(cx).remote_id())
 2778                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2779            }
 2780        })
 2781    }
 2782
 2783    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2784        if self.collapse_matches {
 2785            return range.start..range.start;
 2786        }
 2787        range.clone()
 2788    }
 2789
 2790    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2791        if self.display_map.read(cx).clip_at_line_ends != clip {
 2792            self.display_map
 2793                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2794        }
 2795    }
 2796
 2797    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2798        self.input_enabled = input_enabled;
 2799    }
 2800
 2801    pub fn set_inline_completions_hidden_for_vim_mode(
 2802        &mut self,
 2803        hidden: bool,
 2804        window: &mut Window,
 2805        cx: &mut Context<Self>,
 2806    ) {
 2807        if hidden != self.inline_completions_hidden_for_vim_mode {
 2808            self.inline_completions_hidden_for_vim_mode = hidden;
 2809            if hidden {
 2810                self.update_visible_inline_completion(window, cx);
 2811            } else {
 2812                self.refresh_inline_completion(true, false, window, cx);
 2813            }
 2814        }
 2815    }
 2816
 2817    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2818        self.menu_inline_completions_policy = value;
 2819    }
 2820
 2821    pub fn set_autoindent(&mut self, autoindent: bool) {
 2822        if autoindent {
 2823            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2824        } else {
 2825            self.autoindent_mode = None;
 2826        }
 2827    }
 2828
 2829    pub fn read_only(&self, cx: &App) -> bool {
 2830        self.read_only || self.buffer.read(cx).read_only()
 2831    }
 2832
 2833    pub fn set_read_only(&mut self, read_only: bool) {
 2834        self.read_only = read_only;
 2835    }
 2836
 2837    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2838        self.use_autoclose = autoclose;
 2839    }
 2840
 2841    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2842        self.use_auto_surround = auto_surround;
 2843    }
 2844
 2845    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2846        self.auto_replace_emoji_shortcode = auto_replace;
 2847    }
 2848
 2849    pub fn toggle_edit_predictions(
 2850        &mut self,
 2851        _: &ToggleEditPrediction,
 2852        window: &mut Window,
 2853        cx: &mut Context<Self>,
 2854    ) {
 2855        if self.show_inline_completions_override.is_some() {
 2856            self.set_show_edit_predictions(None, window, cx);
 2857        } else {
 2858            let show_edit_predictions = !self.edit_predictions_enabled();
 2859            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2860        }
 2861    }
 2862
 2863    pub fn set_show_edit_predictions(
 2864        &mut self,
 2865        show_edit_predictions: Option<bool>,
 2866        window: &mut Window,
 2867        cx: &mut Context<Self>,
 2868    ) {
 2869        self.show_inline_completions_override = show_edit_predictions;
 2870        self.update_edit_prediction_settings(cx);
 2871
 2872        if let Some(false) = show_edit_predictions {
 2873            self.discard_inline_completion(false, cx);
 2874        } else {
 2875            self.refresh_inline_completion(false, true, window, cx);
 2876        }
 2877    }
 2878
 2879    fn inline_completions_disabled_in_scope(
 2880        &self,
 2881        buffer: &Entity<Buffer>,
 2882        buffer_position: language::Anchor,
 2883        cx: &App,
 2884    ) -> bool {
 2885        let snapshot = buffer.read(cx).snapshot();
 2886        let settings = snapshot.settings_at(buffer_position, cx);
 2887
 2888        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2889            return false;
 2890        };
 2891
 2892        scope.override_name().map_or(false, |scope_name| {
 2893            settings
 2894                .edit_predictions_disabled_in
 2895                .iter()
 2896                .any(|s| s == scope_name)
 2897        })
 2898    }
 2899
 2900    pub fn set_use_modal_editing(&mut self, to: bool) {
 2901        self.use_modal_editing = to;
 2902    }
 2903
 2904    pub fn use_modal_editing(&self) -> bool {
 2905        self.use_modal_editing
 2906    }
 2907
 2908    fn selections_did_change(
 2909        &mut self,
 2910        local: bool,
 2911        old_cursor_position: &Anchor,
 2912        effects: SelectionEffects,
 2913        window: &mut Window,
 2914        cx: &mut Context<Self>,
 2915    ) {
 2916        window.invalidate_character_coordinates();
 2917
 2918        // Copy selections to primary selection buffer
 2919        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2920        if local {
 2921            let selections = self.selections.all::<usize>(cx);
 2922            let buffer_handle = self.buffer.read(cx).read(cx);
 2923
 2924            let mut text = String::new();
 2925            for (index, selection) in selections.iter().enumerate() {
 2926                let text_for_selection = buffer_handle
 2927                    .text_for_range(selection.start..selection.end)
 2928                    .collect::<String>();
 2929
 2930                text.push_str(&text_for_selection);
 2931                if index != selections.len() - 1 {
 2932                    text.push('\n');
 2933                }
 2934            }
 2935
 2936            if !text.is_empty() {
 2937                cx.write_to_primary(ClipboardItem::new_string(text));
 2938            }
 2939        }
 2940
 2941        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2942            self.buffer.update(cx, |buffer, cx| {
 2943                buffer.set_active_selections(
 2944                    &self.selections.disjoint_anchors(),
 2945                    self.selections.line_mode,
 2946                    self.cursor_shape,
 2947                    cx,
 2948                )
 2949            });
 2950        }
 2951        let display_map = self
 2952            .display_map
 2953            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2954        let buffer = &display_map.buffer_snapshot;
 2955        if self.selections.count() == 1 {
 2956            self.add_selections_state = None;
 2957        }
 2958        self.select_next_state = None;
 2959        self.select_prev_state = None;
 2960        self.select_syntax_node_history.try_clear();
 2961        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2962        self.snippet_stack
 2963            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2964        self.take_rename(false, window, cx);
 2965
 2966        let newest_selection = self.selections.newest_anchor();
 2967        let new_cursor_position = newest_selection.head();
 2968        let selection_start = newest_selection.start;
 2969
 2970        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2971            self.push_to_nav_history(
 2972                *old_cursor_position,
 2973                Some(new_cursor_position.to_point(buffer)),
 2974                false,
 2975                effects.nav_history == Some(true),
 2976                cx,
 2977            );
 2978        }
 2979
 2980        if local {
 2981            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2982                if !self.registered_buffers.contains_key(&buffer_id) {
 2983                    if let Some(project) = self.project.as_ref() {
 2984                        project.update(cx, |project, cx| {
 2985                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2986                                return;
 2987                            };
 2988                            self.registered_buffers.insert(
 2989                                buffer_id,
 2990                                project.register_buffer_with_language_servers(&buffer, cx),
 2991                            );
 2992                        })
 2993                    }
 2994                }
 2995            }
 2996
 2997            let mut context_menu = self.context_menu.borrow_mut();
 2998            let completion_menu = match context_menu.as_ref() {
 2999                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3000                Some(CodeContextMenu::CodeActions(_)) => {
 3001                    *context_menu = None;
 3002                    None
 3003                }
 3004                None => None,
 3005            };
 3006            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3007            drop(context_menu);
 3008
 3009            if effects.completions {
 3010                if let Some(completion_position) = completion_position {
 3011                    let start_offset = selection_start.to_offset(buffer);
 3012                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3013                    let continue_showing = if position_matches {
 3014                        if self.snippet_stack.is_empty() {
 3015                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3016                        } else {
 3017                            // Snippet choices can be shown even when the cursor is in whitespace.
 3018                            // Dismissing the menu with actions like backspace is handled by
 3019                            // invalidation regions.
 3020                            true
 3021                        }
 3022                    } else {
 3023                        false
 3024                    };
 3025
 3026                    if continue_showing {
 3027                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3028                    } else {
 3029                        self.hide_context_menu(window, cx);
 3030                    }
 3031                }
 3032            }
 3033
 3034            hide_hover(self, cx);
 3035
 3036            if old_cursor_position.to_display_point(&display_map).row()
 3037                != new_cursor_position.to_display_point(&display_map).row()
 3038            {
 3039                self.available_code_actions.take();
 3040            }
 3041            self.refresh_code_actions(window, cx);
 3042            self.refresh_document_highlights(cx);
 3043            self.refresh_selected_text_highlights(false, window, cx);
 3044            refresh_matching_bracket_highlights(self, window, cx);
 3045            self.update_visible_inline_completion(window, cx);
 3046            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3047            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3048            self.inline_blame_popover.take();
 3049            if self.git_blame_inline_enabled {
 3050                self.start_inline_blame_timer(window, cx);
 3051            }
 3052        }
 3053
 3054        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3055        cx.emit(EditorEvent::SelectionsChanged { local });
 3056
 3057        let selections = &self.selections.disjoint;
 3058        if selections.len() == 1 {
 3059            cx.emit(SearchEvent::ActiveMatchChanged)
 3060        }
 3061        if local {
 3062            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3063                let inmemory_selections = selections
 3064                    .iter()
 3065                    .map(|s| {
 3066                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3067                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3068                    })
 3069                    .collect();
 3070                self.update_restoration_data(cx, |data| {
 3071                    data.selections = inmemory_selections;
 3072                });
 3073
 3074                if WorkspaceSettings::get(None, cx).restore_on_startup
 3075                    != RestoreOnStartupBehavior::None
 3076                {
 3077                    if let Some(workspace_id) =
 3078                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3079                    {
 3080                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3081                        let selections = selections.clone();
 3082                        let background_executor = cx.background_executor().clone();
 3083                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3084                        self.serialize_selections = cx.background_spawn(async move {
 3085                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3086                            let db_selections = selections
 3087                                .iter()
 3088                                .map(|selection| {
 3089                                    (
 3090                                        selection.start.to_offset(&snapshot),
 3091                                        selection.end.to_offset(&snapshot),
 3092                                    )
 3093                                })
 3094                                .collect();
 3095
 3096                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3097                                .await
 3098                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3099                                .log_err();
 3100                        });
 3101                    }
 3102                }
 3103            }
 3104        }
 3105
 3106        cx.notify();
 3107    }
 3108
 3109    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3110        use text::ToOffset as _;
 3111        use text::ToPoint as _;
 3112
 3113        if self.mode.is_minimap()
 3114            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3115        {
 3116            return;
 3117        }
 3118
 3119        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3120            return;
 3121        };
 3122
 3123        let snapshot = singleton.read(cx).snapshot();
 3124        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3125            let display_snapshot = display_map.snapshot(cx);
 3126
 3127            display_snapshot
 3128                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3129                .map(|fold| {
 3130                    fold.range.start.text_anchor.to_point(&snapshot)
 3131                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3132                })
 3133                .collect()
 3134        });
 3135        self.update_restoration_data(cx, |data| {
 3136            data.folds = inmemory_folds;
 3137        });
 3138
 3139        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3140            return;
 3141        };
 3142        let background_executor = cx.background_executor().clone();
 3143        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3144        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3145            display_map
 3146                .snapshot(cx)
 3147                .folds_in_range(0..snapshot.len())
 3148                .map(|fold| {
 3149                    (
 3150                        fold.range.start.text_anchor.to_offset(&snapshot),
 3151                        fold.range.end.text_anchor.to_offset(&snapshot),
 3152                    )
 3153                })
 3154                .collect()
 3155        });
 3156        self.serialize_folds = cx.background_spawn(async move {
 3157            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3158            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3159                .await
 3160                .with_context(|| {
 3161                    format!(
 3162                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3163                    )
 3164                })
 3165                .log_err();
 3166        });
 3167    }
 3168
 3169    pub fn sync_selections(
 3170        &mut self,
 3171        other: Entity<Editor>,
 3172        cx: &mut Context<Self>,
 3173    ) -> gpui::Subscription {
 3174        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3175        self.selections.change_with(cx, |selections| {
 3176            selections.select_anchors(other_selections);
 3177        });
 3178
 3179        let other_subscription =
 3180            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3181                EditorEvent::SelectionsChanged { local: true } => {
 3182                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3183                    if other_selections.is_empty() {
 3184                        return;
 3185                    }
 3186                    this.selections.change_with(cx, |selections| {
 3187                        selections.select_anchors(other_selections);
 3188                    });
 3189                }
 3190                _ => {}
 3191            });
 3192
 3193        let this_subscription =
 3194            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3195                EditorEvent::SelectionsChanged { local: true } => {
 3196                    let these_selections = this.selections.disjoint.to_vec();
 3197                    if these_selections.is_empty() {
 3198                        return;
 3199                    }
 3200                    other.update(cx, |other_editor, cx| {
 3201                        other_editor.selections.change_with(cx, |selections| {
 3202                            selections.select_anchors(these_selections);
 3203                        })
 3204                    });
 3205                }
 3206                _ => {}
 3207            });
 3208
 3209        Subscription::join(other_subscription, this_subscription)
 3210    }
 3211
 3212    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3213    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3214    /// effects of selection change occur at the end of the transaction.
 3215    pub fn change_selections<R>(
 3216        &mut self,
 3217        effects: SelectionEffects,
 3218        window: &mut Window,
 3219        cx: &mut Context<Self>,
 3220        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3221    ) -> R {
 3222        if let Some(state) = &mut self.deferred_selection_effects_state {
 3223            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3224            state.effects.completions = effects.completions;
 3225            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3226            let (changed, result) = self.selections.change_with(cx, change);
 3227            state.changed |= changed;
 3228            return result;
 3229        }
 3230        let mut state = DeferredSelectionEffectsState {
 3231            changed: false,
 3232            effects,
 3233            old_cursor_position: self.selections.newest_anchor().head(),
 3234            history_entry: SelectionHistoryEntry {
 3235                selections: self.selections.disjoint_anchors(),
 3236                select_next_state: self.select_next_state.clone(),
 3237                select_prev_state: self.select_prev_state.clone(),
 3238                add_selections_state: self.add_selections_state.clone(),
 3239            },
 3240        };
 3241        let (changed, result) = self.selections.change_with(cx, change);
 3242        state.changed = state.changed || changed;
 3243        if self.defer_selection_effects {
 3244            self.deferred_selection_effects_state = Some(state);
 3245        } else {
 3246            self.apply_selection_effects(state, window, cx);
 3247        }
 3248        result
 3249    }
 3250
 3251    /// Defers the effects of selection change, so that the effects of multiple calls to
 3252    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3253    /// to selection history and the state of popovers based on selection position aren't
 3254    /// erroneously updated.
 3255    pub fn with_selection_effects_deferred<R>(
 3256        &mut self,
 3257        window: &mut Window,
 3258        cx: &mut Context<Self>,
 3259        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3260    ) -> R {
 3261        let already_deferred = self.defer_selection_effects;
 3262        self.defer_selection_effects = true;
 3263        let result = update(self, window, cx);
 3264        if !already_deferred {
 3265            self.defer_selection_effects = false;
 3266            if let Some(state) = self.deferred_selection_effects_state.take() {
 3267                self.apply_selection_effects(state, window, cx);
 3268            }
 3269        }
 3270        result
 3271    }
 3272
 3273    fn apply_selection_effects(
 3274        &mut self,
 3275        state: DeferredSelectionEffectsState,
 3276        window: &mut Window,
 3277        cx: &mut Context<Self>,
 3278    ) {
 3279        if state.changed {
 3280            self.selection_history.push(state.history_entry);
 3281
 3282            if let Some(autoscroll) = state.effects.scroll {
 3283                self.request_autoscroll(autoscroll, cx);
 3284            }
 3285
 3286            let old_cursor_position = &state.old_cursor_position;
 3287
 3288            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3289
 3290            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3291                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3292            }
 3293        }
 3294    }
 3295
 3296    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3297    where
 3298        I: IntoIterator<Item = (Range<S>, T)>,
 3299        S: ToOffset,
 3300        T: Into<Arc<str>>,
 3301    {
 3302        if self.read_only(cx) {
 3303            return;
 3304        }
 3305
 3306        self.buffer
 3307            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3308    }
 3309
 3310    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3311    where
 3312        I: IntoIterator<Item = (Range<S>, T)>,
 3313        S: ToOffset,
 3314        T: Into<Arc<str>>,
 3315    {
 3316        if self.read_only(cx) {
 3317            return;
 3318        }
 3319
 3320        self.buffer.update(cx, |buffer, cx| {
 3321            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3322        });
 3323    }
 3324
 3325    pub fn edit_with_block_indent<I, S, T>(
 3326        &mut self,
 3327        edits: I,
 3328        original_indent_columns: Vec<Option<u32>>,
 3329        cx: &mut Context<Self>,
 3330    ) where
 3331        I: IntoIterator<Item = (Range<S>, T)>,
 3332        S: ToOffset,
 3333        T: Into<Arc<str>>,
 3334    {
 3335        if self.read_only(cx) {
 3336            return;
 3337        }
 3338
 3339        self.buffer.update(cx, |buffer, cx| {
 3340            buffer.edit(
 3341                edits,
 3342                Some(AutoindentMode::Block {
 3343                    original_indent_columns,
 3344                }),
 3345                cx,
 3346            )
 3347        });
 3348    }
 3349
 3350    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3351        self.hide_context_menu(window, cx);
 3352
 3353        match phase {
 3354            SelectPhase::Begin {
 3355                position,
 3356                add,
 3357                click_count,
 3358            } => self.begin_selection(position, add, click_count, window, cx),
 3359            SelectPhase::BeginColumnar {
 3360                position,
 3361                goal_column,
 3362                reset,
 3363                mode,
 3364            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3365            SelectPhase::Extend {
 3366                position,
 3367                click_count,
 3368            } => self.extend_selection(position, click_count, window, cx),
 3369            SelectPhase::Update {
 3370                position,
 3371                goal_column,
 3372                scroll_delta,
 3373            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3374            SelectPhase::End => self.end_selection(window, cx),
 3375        }
 3376    }
 3377
 3378    fn extend_selection(
 3379        &mut self,
 3380        position: DisplayPoint,
 3381        click_count: usize,
 3382        window: &mut Window,
 3383        cx: &mut Context<Self>,
 3384    ) {
 3385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3386        let tail = self.selections.newest::<usize>(cx).tail();
 3387        self.begin_selection(position, false, click_count, window, cx);
 3388
 3389        let position = position.to_offset(&display_map, Bias::Left);
 3390        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3391
 3392        let mut pending_selection = self
 3393            .selections
 3394            .pending_anchor()
 3395            .expect("extend_selection not called with pending selection");
 3396        if position >= tail {
 3397            pending_selection.start = tail_anchor;
 3398        } else {
 3399            pending_selection.end = tail_anchor;
 3400            pending_selection.reversed = true;
 3401        }
 3402
 3403        let mut pending_mode = self.selections.pending_mode().unwrap();
 3404        match &mut pending_mode {
 3405            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3406            _ => {}
 3407        }
 3408
 3409        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3410            SelectionEffects::scroll(Autoscroll::fit())
 3411        } else {
 3412            SelectionEffects::no_scroll()
 3413        };
 3414
 3415        self.change_selections(effects, window, cx, |s| {
 3416            s.set_pending(pending_selection, pending_mode)
 3417        });
 3418    }
 3419
 3420    fn begin_selection(
 3421        &mut self,
 3422        position: DisplayPoint,
 3423        add: bool,
 3424        click_count: usize,
 3425        window: &mut Window,
 3426        cx: &mut Context<Self>,
 3427    ) {
 3428        if !self.focus_handle.is_focused(window) {
 3429            self.last_focused_descendant = None;
 3430            window.focus(&self.focus_handle);
 3431        }
 3432
 3433        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3434        let buffer = &display_map.buffer_snapshot;
 3435        let position = display_map.clip_point(position, Bias::Left);
 3436
 3437        let start;
 3438        let end;
 3439        let mode;
 3440        let mut auto_scroll;
 3441        match click_count {
 3442            1 => {
 3443                start = buffer.anchor_before(position.to_point(&display_map));
 3444                end = start;
 3445                mode = SelectMode::Character;
 3446                auto_scroll = true;
 3447            }
 3448            2 => {
 3449                let position = display_map
 3450                    .clip_point(position, Bias::Left)
 3451                    .to_offset(&display_map, Bias::Left);
 3452                let (range, _) = buffer.surrounding_word(position, false);
 3453                start = buffer.anchor_before(range.start);
 3454                end = buffer.anchor_before(range.end);
 3455                mode = SelectMode::Word(start..end);
 3456                auto_scroll = true;
 3457            }
 3458            3 => {
 3459                let position = display_map
 3460                    .clip_point(position, Bias::Left)
 3461                    .to_point(&display_map);
 3462                let line_start = display_map.prev_line_boundary(position).0;
 3463                let next_line_start = buffer.clip_point(
 3464                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3465                    Bias::Left,
 3466                );
 3467                start = buffer.anchor_before(line_start);
 3468                end = buffer.anchor_before(next_line_start);
 3469                mode = SelectMode::Line(start..end);
 3470                auto_scroll = true;
 3471            }
 3472            _ => {
 3473                start = buffer.anchor_before(0);
 3474                end = buffer.anchor_before(buffer.len());
 3475                mode = SelectMode::All;
 3476                auto_scroll = false;
 3477            }
 3478        }
 3479        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3480
 3481        let point_to_delete: Option<usize> = {
 3482            let selected_points: Vec<Selection<Point>> =
 3483                self.selections.disjoint_in_range(start..end, cx);
 3484
 3485            if !add || click_count > 1 {
 3486                None
 3487            } else if !selected_points.is_empty() {
 3488                Some(selected_points[0].id)
 3489            } else {
 3490                let clicked_point_already_selected =
 3491                    self.selections.disjoint.iter().find(|selection| {
 3492                        selection.start.to_point(buffer) == start.to_point(buffer)
 3493                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3494                    });
 3495
 3496                clicked_point_already_selected.map(|selection| selection.id)
 3497            }
 3498        };
 3499
 3500        let selections_count = self.selections.count();
 3501        let effects = if auto_scroll {
 3502            SelectionEffects::default()
 3503        } else {
 3504            SelectionEffects::no_scroll()
 3505        };
 3506
 3507        self.change_selections(effects, window, cx, |s| {
 3508            if let Some(point_to_delete) = point_to_delete {
 3509                s.delete(point_to_delete);
 3510
 3511                if selections_count == 1 {
 3512                    s.set_pending_anchor_range(start..end, mode);
 3513                }
 3514            } else {
 3515                if !add {
 3516                    s.clear_disjoint();
 3517                }
 3518
 3519                s.set_pending_anchor_range(start..end, mode);
 3520            }
 3521        });
 3522    }
 3523
 3524    fn begin_columnar_selection(
 3525        &mut self,
 3526        position: DisplayPoint,
 3527        goal_column: u32,
 3528        reset: bool,
 3529        mode: ColumnarMode,
 3530        window: &mut Window,
 3531        cx: &mut Context<Self>,
 3532    ) {
 3533        if !self.focus_handle.is_focused(window) {
 3534            self.last_focused_descendant = None;
 3535            window.focus(&self.focus_handle);
 3536        }
 3537
 3538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3539
 3540        if reset {
 3541            let pointer_position = display_map
 3542                .buffer_snapshot
 3543                .anchor_before(position.to_point(&display_map));
 3544
 3545            self.change_selections(
 3546                SelectionEffects::scroll(Autoscroll::newest()),
 3547                window,
 3548                cx,
 3549                |s| {
 3550                    s.clear_disjoint();
 3551                    s.set_pending_anchor_range(
 3552                        pointer_position..pointer_position,
 3553                        SelectMode::Character,
 3554                    );
 3555                },
 3556            );
 3557        };
 3558
 3559        let tail = self.selections.newest::<Point>(cx).tail();
 3560        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3561        self.columnar_selection_state = match mode {
 3562            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3563                selection_tail: selection_anchor,
 3564                display_point: if reset {
 3565                    if position.column() != goal_column {
 3566                        Some(DisplayPoint::new(position.row(), goal_column))
 3567                    } else {
 3568                        None
 3569                    }
 3570                } else {
 3571                    None
 3572                },
 3573            }),
 3574            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3575                selection_tail: selection_anchor,
 3576            }),
 3577        };
 3578
 3579        if !reset {
 3580            self.select_columns(position, goal_column, &display_map, window, cx);
 3581        }
 3582    }
 3583
 3584    fn update_selection(
 3585        &mut self,
 3586        position: DisplayPoint,
 3587        goal_column: u32,
 3588        scroll_delta: gpui::Point<f32>,
 3589        window: &mut Window,
 3590        cx: &mut Context<Self>,
 3591    ) {
 3592        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3593
 3594        if self.columnar_selection_state.is_some() {
 3595            self.select_columns(position, goal_column, &display_map, window, cx);
 3596        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3597            let buffer = &display_map.buffer_snapshot;
 3598            let head;
 3599            let tail;
 3600            let mode = self.selections.pending_mode().unwrap();
 3601            match &mode {
 3602                SelectMode::Character => {
 3603                    head = position.to_point(&display_map);
 3604                    tail = pending.tail().to_point(buffer);
 3605                }
 3606                SelectMode::Word(original_range) => {
 3607                    let offset = display_map
 3608                        .clip_point(position, Bias::Left)
 3609                        .to_offset(&display_map, Bias::Left);
 3610                    let original_range = original_range.to_offset(buffer);
 3611
 3612                    let head_offset = if buffer.is_inside_word(offset, false)
 3613                        || original_range.contains(&offset)
 3614                    {
 3615                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3616                        if word_range.start < original_range.start {
 3617                            word_range.start
 3618                        } else {
 3619                            word_range.end
 3620                        }
 3621                    } else {
 3622                        offset
 3623                    };
 3624
 3625                    head = head_offset.to_point(buffer);
 3626                    if head_offset <= original_range.start {
 3627                        tail = original_range.end.to_point(buffer);
 3628                    } else {
 3629                        tail = original_range.start.to_point(buffer);
 3630                    }
 3631                }
 3632                SelectMode::Line(original_range) => {
 3633                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3634
 3635                    let position = display_map
 3636                        .clip_point(position, Bias::Left)
 3637                        .to_point(&display_map);
 3638                    let line_start = display_map.prev_line_boundary(position).0;
 3639                    let next_line_start = buffer.clip_point(
 3640                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3641                        Bias::Left,
 3642                    );
 3643
 3644                    if line_start < original_range.start {
 3645                        head = line_start
 3646                    } else {
 3647                        head = next_line_start
 3648                    }
 3649
 3650                    if head <= original_range.start {
 3651                        tail = original_range.end;
 3652                    } else {
 3653                        tail = original_range.start;
 3654                    }
 3655                }
 3656                SelectMode::All => {
 3657                    return;
 3658                }
 3659            };
 3660
 3661            if head < tail {
 3662                pending.start = buffer.anchor_before(head);
 3663                pending.end = buffer.anchor_before(tail);
 3664                pending.reversed = true;
 3665            } else {
 3666                pending.start = buffer.anchor_before(tail);
 3667                pending.end = buffer.anchor_before(head);
 3668                pending.reversed = false;
 3669            }
 3670
 3671            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3672                s.set_pending(pending, mode);
 3673            });
 3674        } else {
 3675            log::error!("update_selection dispatched with no pending selection");
 3676            return;
 3677        }
 3678
 3679        self.apply_scroll_delta(scroll_delta, window, cx);
 3680        cx.notify();
 3681    }
 3682
 3683    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3684        self.columnar_selection_state.take();
 3685        if self.selections.pending_anchor().is_some() {
 3686            let selections = self.selections.all::<usize>(cx);
 3687            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3688                s.select(selections);
 3689                s.clear_pending();
 3690            });
 3691        }
 3692    }
 3693
 3694    fn select_columns(
 3695        &mut self,
 3696        head: DisplayPoint,
 3697        goal_column: u32,
 3698        display_map: &DisplaySnapshot,
 3699        window: &mut Window,
 3700        cx: &mut Context<Self>,
 3701    ) {
 3702        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3703            return;
 3704        };
 3705
 3706        let tail = match columnar_state {
 3707            ColumnarSelectionState::FromMouse {
 3708                selection_tail,
 3709                display_point,
 3710            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3711            ColumnarSelectionState::FromSelection { selection_tail } => {
 3712                selection_tail.to_display_point(&display_map)
 3713            }
 3714        };
 3715
 3716        let start_row = cmp::min(tail.row(), head.row());
 3717        let end_row = cmp::max(tail.row(), head.row());
 3718        let start_column = cmp::min(tail.column(), goal_column);
 3719        let end_column = cmp::max(tail.column(), goal_column);
 3720        let reversed = start_column < tail.column();
 3721
 3722        let selection_ranges = (start_row.0..=end_row.0)
 3723            .map(DisplayRow)
 3724            .filter_map(|row| {
 3725                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3726                    || start_column <= display_map.line_len(row))
 3727                    && !display_map.is_block_line(row)
 3728                {
 3729                    let start = display_map
 3730                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3731                        .to_point(display_map);
 3732                    let end = display_map
 3733                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3734                        .to_point(display_map);
 3735                    if reversed {
 3736                        Some(end..start)
 3737                    } else {
 3738                        Some(start..end)
 3739                    }
 3740                } else {
 3741                    None
 3742                }
 3743            })
 3744            .collect::<Vec<_>>();
 3745
 3746        let ranges = match columnar_state {
 3747            ColumnarSelectionState::FromMouse { .. } => {
 3748                let mut non_empty_ranges = selection_ranges
 3749                    .iter()
 3750                    .filter(|selection_range| selection_range.start != selection_range.end)
 3751                    .peekable();
 3752                if non_empty_ranges.peek().is_some() {
 3753                    non_empty_ranges.cloned().collect()
 3754                } else {
 3755                    selection_ranges
 3756                }
 3757            }
 3758            _ => selection_ranges,
 3759        };
 3760
 3761        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3762            s.select_ranges(ranges);
 3763        });
 3764        cx.notify();
 3765    }
 3766
 3767    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3768        self.selections
 3769            .all_adjusted(cx)
 3770            .iter()
 3771            .any(|selection| !selection.is_empty())
 3772    }
 3773
 3774    pub fn has_pending_nonempty_selection(&self) -> bool {
 3775        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3776            Some(Selection { start, end, .. }) => start != end,
 3777            None => false,
 3778        };
 3779
 3780        pending_nonempty_selection
 3781            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3782    }
 3783
 3784    pub fn has_pending_selection(&self) -> bool {
 3785        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3786    }
 3787
 3788    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3789        self.selection_mark_mode = false;
 3790        self.selection_drag_state = SelectionDragState::None;
 3791
 3792        if self.clear_expanded_diff_hunks(cx) {
 3793            cx.notify();
 3794            return;
 3795        }
 3796        if self.dismiss_menus_and_popups(true, window, cx) {
 3797            return;
 3798        }
 3799
 3800        if self.mode.is_full()
 3801            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3802        {
 3803            return;
 3804        }
 3805
 3806        cx.propagate();
 3807    }
 3808
 3809    pub fn dismiss_menus_and_popups(
 3810        &mut self,
 3811        is_user_requested: bool,
 3812        window: &mut Window,
 3813        cx: &mut Context<Self>,
 3814    ) -> bool {
 3815        if self.take_rename(false, window, cx).is_some() {
 3816            return true;
 3817        }
 3818
 3819        if hide_hover(self, cx) {
 3820            return true;
 3821        }
 3822
 3823        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3824            return true;
 3825        }
 3826
 3827        if self.hide_context_menu(window, cx).is_some() {
 3828            return true;
 3829        }
 3830
 3831        if self.mouse_context_menu.take().is_some() {
 3832            return true;
 3833        }
 3834
 3835        if is_user_requested && self.discard_inline_completion(true, cx) {
 3836            return true;
 3837        }
 3838
 3839        if self.snippet_stack.pop().is_some() {
 3840            return true;
 3841        }
 3842
 3843        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3844            self.dismiss_diagnostics(cx);
 3845            return true;
 3846        }
 3847
 3848        false
 3849    }
 3850
 3851    fn linked_editing_ranges_for(
 3852        &self,
 3853        selection: Range<text::Anchor>,
 3854        cx: &App,
 3855    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3856        if self.linked_edit_ranges.is_empty() {
 3857            return None;
 3858        }
 3859        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3860            selection.end.buffer_id.and_then(|end_buffer_id| {
 3861                if selection.start.buffer_id != Some(end_buffer_id) {
 3862                    return None;
 3863                }
 3864                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3865                let snapshot = buffer.read(cx).snapshot();
 3866                self.linked_edit_ranges
 3867                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3868                    .map(|ranges| (ranges, snapshot, buffer))
 3869            })?;
 3870        use text::ToOffset as TO;
 3871        // find offset from the start of current range to current cursor position
 3872        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3873
 3874        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3875        let start_difference = start_offset - start_byte_offset;
 3876        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3877        let end_difference = end_offset - start_byte_offset;
 3878        // Current range has associated linked ranges.
 3879        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3880        for range in linked_ranges.iter() {
 3881            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3882            let end_offset = start_offset + end_difference;
 3883            let start_offset = start_offset + start_difference;
 3884            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3885                continue;
 3886            }
 3887            if self.selections.disjoint_anchor_ranges().any(|s| {
 3888                if s.start.buffer_id != selection.start.buffer_id
 3889                    || s.end.buffer_id != selection.end.buffer_id
 3890                {
 3891                    return false;
 3892                }
 3893                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3894                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3895            }) {
 3896                continue;
 3897            }
 3898            let start = buffer_snapshot.anchor_after(start_offset);
 3899            let end = buffer_snapshot.anchor_after(end_offset);
 3900            linked_edits
 3901                .entry(buffer.clone())
 3902                .or_default()
 3903                .push(start..end);
 3904        }
 3905        Some(linked_edits)
 3906    }
 3907
 3908    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3909        let text: Arc<str> = text.into();
 3910
 3911        if self.read_only(cx) {
 3912            return;
 3913        }
 3914
 3915        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3916
 3917        let selections = self.selections.all_adjusted(cx);
 3918        let mut bracket_inserted = false;
 3919        let mut edits = Vec::new();
 3920        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3921        let mut new_selections = Vec::with_capacity(selections.len());
 3922        let mut new_autoclose_regions = Vec::new();
 3923        let snapshot = self.buffer.read(cx).read(cx);
 3924        let mut clear_linked_edit_ranges = false;
 3925
 3926        for (selection, autoclose_region) in
 3927            self.selections_with_autoclose_regions(selections, &snapshot)
 3928        {
 3929            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3930                // Determine if the inserted text matches the opening or closing
 3931                // bracket of any of this language's bracket pairs.
 3932                let mut bracket_pair = None;
 3933                let mut is_bracket_pair_start = false;
 3934                let mut is_bracket_pair_end = false;
 3935                if !text.is_empty() {
 3936                    let mut bracket_pair_matching_end = None;
 3937                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3938                    //  and they are removing the character that triggered IME popup.
 3939                    for (pair, enabled) in scope.brackets() {
 3940                        if !pair.close && !pair.surround {
 3941                            continue;
 3942                        }
 3943
 3944                        if enabled && pair.start.ends_with(text.as_ref()) {
 3945                            let prefix_len = pair.start.len() - text.len();
 3946                            let preceding_text_matches_prefix = prefix_len == 0
 3947                                || (selection.start.column >= (prefix_len as u32)
 3948                                    && snapshot.contains_str_at(
 3949                                        Point::new(
 3950                                            selection.start.row,
 3951                                            selection.start.column - (prefix_len as u32),
 3952                                        ),
 3953                                        &pair.start[..prefix_len],
 3954                                    ));
 3955                            if preceding_text_matches_prefix {
 3956                                bracket_pair = Some(pair.clone());
 3957                                is_bracket_pair_start = true;
 3958                                break;
 3959                            }
 3960                        }
 3961                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3962                        {
 3963                            // take first bracket pair matching end, but don't break in case a later bracket
 3964                            // pair matches start
 3965                            bracket_pair_matching_end = Some(pair.clone());
 3966                        }
 3967                    }
 3968                    if let Some(end) = bracket_pair_matching_end
 3969                        && bracket_pair.is_none()
 3970                    {
 3971                        bracket_pair = Some(end);
 3972                        is_bracket_pair_end = true;
 3973                    }
 3974                }
 3975
 3976                if let Some(bracket_pair) = bracket_pair {
 3977                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3978                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3979                    let auto_surround =
 3980                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3981                    if selection.is_empty() {
 3982                        if is_bracket_pair_start {
 3983                            // If the inserted text is a suffix of an opening bracket and the
 3984                            // selection is preceded by the rest of the opening bracket, then
 3985                            // insert the closing bracket.
 3986                            let following_text_allows_autoclose = snapshot
 3987                                .chars_at(selection.start)
 3988                                .next()
 3989                                .map_or(true, |c| scope.should_autoclose_before(c));
 3990
 3991                            let preceding_text_allows_autoclose = selection.start.column == 0
 3992                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3993                                    true,
 3994                                    |c| {
 3995                                        bracket_pair.start != bracket_pair.end
 3996                                            || !snapshot
 3997                                                .char_classifier_at(selection.start)
 3998                                                .is_word(c)
 3999                                    },
 4000                                );
 4001
 4002                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4003                                && bracket_pair.start.len() == 1
 4004                            {
 4005                                let target = bracket_pair.start.chars().next().unwrap();
 4006                                let current_line_count = snapshot
 4007                                    .reversed_chars_at(selection.start)
 4008                                    .take_while(|&c| c != '\n')
 4009                                    .filter(|&c| c == target)
 4010                                    .count();
 4011                                current_line_count % 2 == 1
 4012                            } else {
 4013                                false
 4014                            };
 4015
 4016                            if autoclose
 4017                                && bracket_pair.close
 4018                                && following_text_allows_autoclose
 4019                                && preceding_text_allows_autoclose
 4020                                && !is_closing_quote
 4021                            {
 4022                                let anchor = snapshot.anchor_before(selection.end);
 4023                                new_selections.push((selection.map(|_| anchor), text.len()));
 4024                                new_autoclose_regions.push((
 4025                                    anchor,
 4026                                    text.len(),
 4027                                    selection.id,
 4028                                    bracket_pair.clone(),
 4029                                ));
 4030                                edits.push((
 4031                                    selection.range(),
 4032                                    format!("{}{}", text, bracket_pair.end).into(),
 4033                                ));
 4034                                bracket_inserted = true;
 4035                                continue;
 4036                            }
 4037                        }
 4038
 4039                        if let Some(region) = autoclose_region {
 4040                            // If the selection is followed by an auto-inserted closing bracket,
 4041                            // then don't insert that closing bracket again; just move the selection
 4042                            // past the closing bracket.
 4043                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4044                                && text.as_ref() == region.pair.end.as_str();
 4045                            if should_skip {
 4046                                let anchor = snapshot.anchor_after(selection.end);
 4047                                new_selections
 4048                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4049                                continue;
 4050                            }
 4051                        }
 4052
 4053                        let always_treat_brackets_as_autoclosed = snapshot
 4054                            .language_settings_at(selection.start, cx)
 4055                            .always_treat_brackets_as_autoclosed;
 4056                        if always_treat_brackets_as_autoclosed
 4057                            && is_bracket_pair_end
 4058                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4059                        {
 4060                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4061                            // and the inserted text is a closing bracket and the selection is followed
 4062                            // by the closing bracket then move the selection past the closing bracket.
 4063                            let anchor = snapshot.anchor_after(selection.end);
 4064                            new_selections.push((selection.map(|_| anchor), text.len()));
 4065                            continue;
 4066                        }
 4067                    }
 4068                    // If an opening bracket is 1 character long and is typed while
 4069                    // text is selected, then surround that text with the bracket pair.
 4070                    else if auto_surround
 4071                        && bracket_pair.surround
 4072                        && is_bracket_pair_start
 4073                        && bracket_pair.start.chars().count() == 1
 4074                    {
 4075                        edits.push((selection.start..selection.start, text.clone()));
 4076                        edits.push((
 4077                            selection.end..selection.end,
 4078                            bracket_pair.end.as_str().into(),
 4079                        ));
 4080                        bracket_inserted = true;
 4081                        new_selections.push((
 4082                            Selection {
 4083                                id: selection.id,
 4084                                start: snapshot.anchor_after(selection.start),
 4085                                end: snapshot.anchor_before(selection.end),
 4086                                reversed: selection.reversed,
 4087                                goal: selection.goal,
 4088                            },
 4089                            0,
 4090                        ));
 4091                        continue;
 4092                    }
 4093                }
 4094            }
 4095
 4096            if self.auto_replace_emoji_shortcode
 4097                && selection.is_empty()
 4098                && text.as_ref().ends_with(':')
 4099            {
 4100                if let Some(possible_emoji_short_code) =
 4101                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4102                {
 4103                    if !possible_emoji_short_code.is_empty() {
 4104                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4105                            let emoji_shortcode_start = Point::new(
 4106                                selection.start.row,
 4107                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4108                            );
 4109
 4110                            // Remove shortcode from buffer
 4111                            edits.push((
 4112                                emoji_shortcode_start..selection.start,
 4113                                "".to_string().into(),
 4114                            ));
 4115                            new_selections.push((
 4116                                Selection {
 4117                                    id: selection.id,
 4118                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4119                                    end: snapshot.anchor_before(selection.start),
 4120                                    reversed: selection.reversed,
 4121                                    goal: selection.goal,
 4122                                },
 4123                                0,
 4124                            ));
 4125
 4126                            // Insert emoji
 4127                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4128                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4129                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4130
 4131                            continue;
 4132                        }
 4133                    }
 4134                }
 4135            }
 4136
 4137            // If not handling any auto-close operation, then just replace the selected
 4138            // text with the given input and move the selection to the end of the
 4139            // newly inserted text.
 4140            let anchor = snapshot.anchor_after(selection.end);
 4141            if !self.linked_edit_ranges.is_empty() {
 4142                let start_anchor = snapshot.anchor_before(selection.start);
 4143
 4144                let is_word_char = text.chars().next().map_or(true, |char| {
 4145                    let classifier = snapshot
 4146                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4147                        .ignore_punctuation(true);
 4148                    classifier.is_word(char)
 4149                });
 4150
 4151                if is_word_char {
 4152                    if let Some(ranges) = self
 4153                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4154                    {
 4155                        for (buffer, edits) in ranges {
 4156                            linked_edits
 4157                                .entry(buffer.clone())
 4158                                .or_default()
 4159                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4160                        }
 4161                    }
 4162                } else {
 4163                    clear_linked_edit_ranges = true;
 4164                }
 4165            }
 4166
 4167            new_selections.push((selection.map(|_| anchor), 0));
 4168            edits.push((selection.start..selection.end, text.clone()));
 4169        }
 4170
 4171        drop(snapshot);
 4172
 4173        self.transact(window, cx, |this, window, cx| {
 4174            if clear_linked_edit_ranges {
 4175                this.linked_edit_ranges.clear();
 4176            }
 4177            let initial_buffer_versions =
 4178                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4179
 4180            this.buffer.update(cx, |buffer, cx| {
 4181                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4182            });
 4183            for (buffer, edits) in linked_edits {
 4184                buffer.update(cx, |buffer, cx| {
 4185                    let snapshot = buffer.snapshot();
 4186                    let edits = edits
 4187                        .into_iter()
 4188                        .map(|(range, text)| {
 4189                            use text::ToPoint as TP;
 4190                            let end_point = TP::to_point(&range.end, &snapshot);
 4191                            let start_point = TP::to_point(&range.start, &snapshot);
 4192                            (start_point..end_point, text)
 4193                        })
 4194                        .sorted_by_key(|(range, _)| range.start);
 4195                    buffer.edit(edits, None, cx);
 4196                })
 4197            }
 4198            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4199            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4200            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4201            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4202                .zip(new_selection_deltas)
 4203                .map(|(selection, delta)| Selection {
 4204                    id: selection.id,
 4205                    start: selection.start + delta,
 4206                    end: selection.end + delta,
 4207                    reversed: selection.reversed,
 4208                    goal: SelectionGoal::None,
 4209                })
 4210                .collect::<Vec<_>>();
 4211
 4212            let mut i = 0;
 4213            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4214                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4215                let start = map.buffer_snapshot.anchor_before(position);
 4216                let end = map.buffer_snapshot.anchor_after(position);
 4217                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4218                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4219                        Ordering::Less => i += 1,
 4220                        Ordering::Greater => break,
 4221                        Ordering::Equal => {
 4222                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4223                                Ordering::Less => i += 1,
 4224                                Ordering::Equal => break,
 4225                                Ordering::Greater => break,
 4226                            }
 4227                        }
 4228                    }
 4229                }
 4230                this.autoclose_regions.insert(
 4231                    i,
 4232                    AutocloseRegion {
 4233                        selection_id,
 4234                        range: start..end,
 4235                        pair,
 4236                    },
 4237                );
 4238            }
 4239
 4240            let had_active_inline_completion = this.has_active_inline_completion();
 4241            this.change_selections(
 4242                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4243                window,
 4244                cx,
 4245                |s| s.select(new_selections),
 4246            );
 4247
 4248            if !bracket_inserted {
 4249                if let Some(on_type_format_task) =
 4250                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4251                {
 4252                    on_type_format_task.detach_and_log_err(cx);
 4253                }
 4254            }
 4255
 4256            let editor_settings = EditorSettings::get_global(cx);
 4257            if bracket_inserted
 4258                && (editor_settings.auto_signature_help
 4259                    || editor_settings.show_signature_help_after_edits)
 4260            {
 4261                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4262            }
 4263
 4264            let trigger_in_words =
 4265                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4266            if this.hard_wrap.is_some() {
 4267                let latest: Range<Point> = this.selections.newest(cx).range();
 4268                if latest.is_empty()
 4269                    && this
 4270                        .buffer()
 4271                        .read(cx)
 4272                        .snapshot(cx)
 4273                        .line_len(MultiBufferRow(latest.start.row))
 4274                        == latest.start.column
 4275                {
 4276                    this.rewrap_impl(
 4277                        RewrapOptions {
 4278                            override_language_settings: true,
 4279                            preserve_existing_whitespace: true,
 4280                        },
 4281                        cx,
 4282                    )
 4283                }
 4284            }
 4285            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4286            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4287            this.refresh_inline_completion(true, false, window, cx);
 4288            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4289        });
 4290    }
 4291
 4292    fn find_possible_emoji_shortcode_at_position(
 4293        snapshot: &MultiBufferSnapshot,
 4294        position: Point,
 4295    ) -> Option<String> {
 4296        let mut chars = Vec::new();
 4297        let mut found_colon = false;
 4298        for char in snapshot.reversed_chars_at(position).take(100) {
 4299            // Found a possible emoji shortcode in the middle of the buffer
 4300            if found_colon {
 4301                if char.is_whitespace() {
 4302                    chars.reverse();
 4303                    return Some(chars.iter().collect());
 4304                }
 4305                // If the previous character is not a whitespace, we are in the middle of a word
 4306                // and we only want to complete the shortcode if the word is made up of other emojis
 4307                let mut containing_word = String::new();
 4308                for ch in snapshot
 4309                    .reversed_chars_at(position)
 4310                    .skip(chars.len() + 1)
 4311                    .take(100)
 4312                {
 4313                    if ch.is_whitespace() {
 4314                        break;
 4315                    }
 4316                    containing_word.push(ch);
 4317                }
 4318                let containing_word = containing_word.chars().rev().collect::<String>();
 4319                if util::word_consists_of_emojis(containing_word.as_str()) {
 4320                    chars.reverse();
 4321                    return Some(chars.iter().collect());
 4322                }
 4323            }
 4324
 4325            if char.is_whitespace() || !char.is_ascii() {
 4326                return None;
 4327            }
 4328            if char == ':' {
 4329                found_colon = true;
 4330            } else {
 4331                chars.push(char);
 4332            }
 4333        }
 4334        // Found a possible emoji shortcode at the beginning of the buffer
 4335        chars.reverse();
 4336        Some(chars.iter().collect())
 4337    }
 4338
 4339    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4341        self.transact(window, cx, |this, window, cx| {
 4342            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4343                let selections = this.selections.all::<usize>(cx);
 4344                let multi_buffer = this.buffer.read(cx);
 4345                let buffer = multi_buffer.snapshot(cx);
 4346                selections
 4347                    .iter()
 4348                    .map(|selection| {
 4349                        let start_point = selection.start.to_point(&buffer);
 4350                        let mut existing_indent =
 4351                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4352                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4353                        let start = selection.start;
 4354                        let end = selection.end;
 4355                        let selection_is_empty = start == end;
 4356                        let language_scope = buffer.language_scope_at(start);
 4357                        let (
 4358                            comment_delimiter,
 4359                            doc_delimiter,
 4360                            insert_extra_newline,
 4361                            indent_on_newline,
 4362                            indent_on_extra_newline,
 4363                        ) = if let Some(language) = &language_scope {
 4364                            let mut insert_extra_newline =
 4365                                insert_extra_newline_brackets(&buffer, start..end, language)
 4366                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4367
 4368                            // Comment extension on newline is allowed only for cursor selections
 4369                            let comment_delimiter = maybe!({
 4370                                if !selection_is_empty {
 4371                                    return None;
 4372                                }
 4373
 4374                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4375                                    return None;
 4376                                }
 4377
 4378                                let delimiters = language.line_comment_prefixes();
 4379                                let max_len_of_delimiter =
 4380                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4381                                let (snapshot, range) =
 4382                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4383
 4384                                let num_of_whitespaces = snapshot
 4385                                    .chars_for_range(range.clone())
 4386                                    .take_while(|c| c.is_whitespace())
 4387                                    .count();
 4388                                let comment_candidate = snapshot
 4389                                    .chars_for_range(range.clone())
 4390                                    .skip(num_of_whitespaces)
 4391                                    .take(max_len_of_delimiter)
 4392                                    .collect::<String>();
 4393                                let (delimiter, trimmed_len) = delimiters
 4394                                    .iter()
 4395                                    .filter_map(|delimiter| {
 4396                                        let prefix = delimiter.trim_end();
 4397                                        if comment_candidate.starts_with(prefix) {
 4398                                            Some((delimiter, prefix.len()))
 4399                                        } else {
 4400                                            None
 4401                                        }
 4402                                    })
 4403                                    .max_by_key(|(_, len)| *len)?;
 4404
 4405                                if let Some((block_start, _)) = language.block_comment_delimiters()
 4406                                {
 4407                                    let block_start_trimmed = block_start.trim_end();
 4408                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4409                                        let line_content = snapshot
 4410                                            .chars_for_range(range)
 4411                                            .skip(num_of_whitespaces)
 4412                                            .take(block_start_trimmed.len())
 4413                                            .collect::<String>();
 4414
 4415                                        if line_content.starts_with(block_start_trimmed) {
 4416                                            return None;
 4417                                        }
 4418                                    }
 4419                                }
 4420
 4421                                let cursor_is_placed_after_comment_marker =
 4422                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4423                                if cursor_is_placed_after_comment_marker {
 4424                                    Some(delimiter.clone())
 4425                                } else {
 4426                                    None
 4427                                }
 4428                            });
 4429
 4430                            let mut indent_on_newline = IndentSize::spaces(0);
 4431                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4432
 4433                            let doc_delimiter = maybe!({
 4434                                if !selection_is_empty {
 4435                                    return None;
 4436                                }
 4437
 4438                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4439                                    return None;
 4440                                }
 4441
 4442                                let DocumentationConfig {
 4443                                    start: start_tag,
 4444                                    end: end_tag,
 4445                                    prefix: delimiter,
 4446                                    tab_size: len,
 4447                                } = language.documentation()?;
 4448
 4449                                let is_within_block_comment = buffer
 4450                                    .language_scope_at(start_point)
 4451                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4452                                if !is_within_block_comment {
 4453                                    return None;
 4454                                }
 4455
 4456                                let (snapshot, range) =
 4457                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4458
 4459                                let num_of_whitespaces = snapshot
 4460                                    .chars_for_range(range.clone())
 4461                                    .take_while(|c| c.is_whitespace())
 4462                                    .count();
 4463
 4464                                // 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.
 4465                                let column = start_point.column;
 4466                                let cursor_is_after_start_tag = {
 4467                                    let start_tag_len = start_tag.len();
 4468                                    let start_tag_line = snapshot
 4469                                        .chars_for_range(range.clone())
 4470                                        .skip(num_of_whitespaces)
 4471                                        .take(start_tag_len)
 4472                                        .collect::<String>();
 4473                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4474                                        num_of_whitespaces + start_tag_len <= column as usize
 4475                                    } else {
 4476                                        false
 4477                                    }
 4478                                };
 4479
 4480                                let cursor_is_after_delimiter = {
 4481                                    let delimiter_trim = delimiter.trim_end();
 4482                                    let delimiter_line = snapshot
 4483                                        .chars_for_range(range.clone())
 4484                                        .skip(num_of_whitespaces)
 4485                                        .take(delimiter_trim.len())
 4486                                        .collect::<String>();
 4487                                    if delimiter_line.starts_with(delimiter_trim) {
 4488                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4489                                    } else {
 4490                                        false
 4491                                    }
 4492                                };
 4493
 4494                                let cursor_is_before_end_tag_if_exists = {
 4495                                    let mut char_position = 0u32;
 4496                                    let mut end_tag_offset = None;
 4497
 4498                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4499                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4500                                            let chars_before_match =
 4501                                                chunk[..byte_pos].chars().count() as u32;
 4502                                            end_tag_offset =
 4503                                                Some(char_position + chars_before_match);
 4504                                            break 'outer;
 4505                                        }
 4506                                        char_position += chunk.chars().count() as u32;
 4507                                    }
 4508
 4509                                    if let Some(end_tag_offset) = end_tag_offset {
 4510                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4511                                        if cursor_is_after_start_tag {
 4512                                            if cursor_is_before_end_tag {
 4513                                                insert_extra_newline = true;
 4514                                            }
 4515                                            let cursor_is_at_start_of_end_tag =
 4516                                                column == end_tag_offset;
 4517                                            if cursor_is_at_start_of_end_tag {
 4518                                                indent_on_extra_newline.len = (*len).into();
 4519                                            }
 4520                                        }
 4521                                        cursor_is_before_end_tag
 4522                                    } else {
 4523                                        true
 4524                                    }
 4525                                };
 4526
 4527                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4528                                    && cursor_is_before_end_tag_if_exists
 4529                                {
 4530                                    if cursor_is_after_start_tag {
 4531                                        indent_on_newline.len = (*len).into();
 4532                                    }
 4533                                    Some(delimiter.clone())
 4534                                } else {
 4535                                    None
 4536                                }
 4537                            });
 4538
 4539                            (
 4540                                comment_delimiter,
 4541                                doc_delimiter,
 4542                                insert_extra_newline,
 4543                                indent_on_newline,
 4544                                indent_on_extra_newline,
 4545                            )
 4546                        } else {
 4547                            (
 4548                                None,
 4549                                None,
 4550                                false,
 4551                                IndentSize::default(),
 4552                                IndentSize::default(),
 4553                            )
 4554                        };
 4555
 4556                        let prevent_auto_indent = doc_delimiter.is_some();
 4557                        let delimiter = comment_delimiter.or(doc_delimiter);
 4558
 4559                        let capacity_for_delimiter =
 4560                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4561                        let mut new_text = String::with_capacity(
 4562                            1 + capacity_for_delimiter
 4563                                + existing_indent.len as usize
 4564                                + indent_on_newline.len as usize
 4565                                + indent_on_extra_newline.len as usize,
 4566                        );
 4567                        new_text.push('\n');
 4568                        new_text.extend(existing_indent.chars());
 4569                        new_text.extend(indent_on_newline.chars());
 4570
 4571                        if let Some(delimiter) = &delimiter {
 4572                            new_text.push_str(delimiter);
 4573                        }
 4574
 4575                        if insert_extra_newline {
 4576                            new_text.push('\n');
 4577                            new_text.extend(existing_indent.chars());
 4578                            new_text.extend(indent_on_extra_newline.chars());
 4579                        }
 4580
 4581                        let anchor = buffer.anchor_after(end);
 4582                        let new_selection = selection.map(|_| anchor);
 4583                        (
 4584                            ((start..end, new_text), prevent_auto_indent),
 4585                            (insert_extra_newline, new_selection),
 4586                        )
 4587                    })
 4588                    .unzip()
 4589            };
 4590
 4591            let mut auto_indent_edits = Vec::new();
 4592            let mut edits = Vec::new();
 4593            for (edit, prevent_auto_indent) in edits_with_flags {
 4594                if prevent_auto_indent {
 4595                    edits.push(edit);
 4596                } else {
 4597                    auto_indent_edits.push(edit);
 4598                }
 4599            }
 4600            if !edits.is_empty() {
 4601                this.edit(edits, cx);
 4602            }
 4603            if !auto_indent_edits.is_empty() {
 4604                this.edit_with_autoindent(auto_indent_edits, cx);
 4605            }
 4606
 4607            let buffer = this.buffer.read(cx).snapshot(cx);
 4608            let new_selections = selection_info
 4609                .into_iter()
 4610                .map(|(extra_newline_inserted, new_selection)| {
 4611                    let mut cursor = new_selection.end.to_point(&buffer);
 4612                    if extra_newline_inserted {
 4613                        cursor.row -= 1;
 4614                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4615                    }
 4616                    new_selection.map(|_| cursor)
 4617                })
 4618                .collect();
 4619
 4620            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4621            this.refresh_inline_completion(true, false, window, cx);
 4622        });
 4623    }
 4624
 4625    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4627
 4628        let buffer = self.buffer.read(cx);
 4629        let snapshot = buffer.snapshot(cx);
 4630
 4631        let mut edits = Vec::new();
 4632        let mut rows = Vec::new();
 4633
 4634        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4635            let cursor = selection.head();
 4636            let row = cursor.row;
 4637
 4638            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4639
 4640            let newline = "\n".to_string();
 4641            edits.push((start_of_line..start_of_line, newline));
 4642
 4643            rows.push(row + rows_inserted as u32);
 4644        }
 4645
 4646        self.transact(window, cx, |editor, window, cx| {
 4647            editor.edit(edits, cx);
 4648
 4649            editor.change_selections(Default::default(), window, cx, |s| {
 4650                let mut index = 0;
 4651                s.move_cursors_with(|map, _, _| {
 4652                    let row = rows[index];
 4653                    index += 1;
 4654
 4655                    let point = Point::new(row, 0);
 4656                    let boundary = map.next_line_boundary(point).1;
 4657                    let clipped = map.clip_point(boundary, Bias::Left);
 4658
 4659                    (clipped, SelectionGoal::None)
 4660                });
 4661            });
 4662
 4663            let mut indent_edits = Vec::new();
 4664            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4665            for row in rows {
 4666                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4667                for (row, indent) in indents {
 4668                    if indent.len == 0 {
 4669                        continue;
 4670                    }
 4671
 4672                    let text = match indent.kind {
 4673                        IndentKind::Space => " ".repeat(indent.len as usize),
 4674                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4675                    };
 4676                    let point = Point::new(row.0, 0);
 4677                    indent_edits.push((point..point, text));
 4678                }
 4679            }
 4680            editor.edit(indent_edits, cx);
 4681        });
 4682    }
 4683
 4684    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4685        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4686
 4687        let buffer = self.buffer.read(cx);
 4688        let snapshot = buffer.snapshot(cx);
 4689
 4690        let mut edits = Vec::new();
 4691        let mut rows = Vec::new();
 4692        let mut rows_inserted = 0;
 4693
 4694        for selection in self.selections.all_adjusted(cx) {
 4695            let cursor = selection.head();
 4696            let row = cursor.row;
 4697
 4698            let point = Point::new(row + 1, 0);
 4699            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4700
 4701            let newline = "\n".to_string();
 4702            edits.push((start_of_line..start_of_line, newline));
 4703
 4704            rows_inserted += 1;
 4705            rows.push(row + rows_inserted);
 4706        }
 4707
 4708        self.transact(window, cx, |editor, window, cx| {
 4709            editor.edit(edits, cx);
 4710
 4711            editor.change_selections(Default::default(), window, cx, |s| {
 4712                let mut index = 0;
 4713                s.move_cursors_with(|map, _, _| {
 4714                    let row = rows[index];
 4715                    index += 1;
 4716
 4717                    let point = Point::new(row, 0);
 4718                    let boundary = map.next_line_boundary(point).1;
 4719                    let clipped = map.clip_point(boundary, Bias::Left);
 4720
 4721                    (clipped, SelectionGoal::None)
 4722                });
 4723            });
 4724
 4725            let mut indent_edits = Vec::new();
 4726            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4727            for row in rows {
 4728                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4729                for (row, indent) in indents {
 4730                    if indent.len == 0 {
 4731                        continue;
 4732                    }
 4733
 4734                    let text = match indent.kind {
 4735                        IndentKind::Space => " ".repeat(indent.len as usize),
 4736                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4737                    };
 4738                    let point = Point::new(row.0, 0);
 4739                    indent_edits.push((point..point, text));
 4740                }
 4741            }
 4742            editor.edit(indent_edits, cx);
 4743        });
 4744    }
 4745
 4746    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4747        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4748            original_indent_columns: Vec::new(),
 4749        });
 4750        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4751    }
 4752
 4753    fn insert_with_autoindent_mode(
 4754        &mut self,
 4755        text: &str,
 4756        autoindent_mode: Option<AutoindentMode>,
 4757        window: &mut Window,
 4758        cx: &mut Context<Self>,
 4759    ) {
 4760        if self.read_only(cx) {
 4761            return;
 4762        }
 4763
 4764        let text: Arc<str> = text.into();
 4765        self.transact(window, cx, |this, window, cx| {
 4766            let old_selections = this.selections.all_adjusted(cx);
 4767            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4768                let anchors = {
 4769                    let snapshot = buffer.read(cx);
 4770                    old_selections
 4771                        .iter()
 4772                        .map(|s| {
 4773                            let anchor = snapshot.anchor_after(s.head());
 4774                            s.map(|_| anchor)
 4775                        })
 4776                        .collect::<Vec<_>>()
 4777                };
 4778                buffer.edit(
 4779                    old_selections
 4780                        .iter()
 4781                        .map(|s| (s.start..s.end, text.clone())),
 4782                    autoindent_mode,
 4783                    cx,
 4784                );
 4785                anchors
 4786            });
 4787
 4788            this.change_selections(Default::default(), window, cx, |s| {
 4789                s.select_anchors(selection_anchors);
 4790            });
 4791
 4792            cx.notify();
 4793        });
 4794    }
 4795
 4796    fn trigger_completion_on_input(
 4797        &mut self,
 4798        text: &str,
 4799        trigger_in_words: bool,
 4800        window: &mut Window,
 4801        cx: &mut Context<Self>,
 4802    ) {
 4803        let completions_source = self
 4804            .context_menu
 4805            .borrow()
 4806            .as_ref()
 4807            .and_then(|menu| match menu {
 4808                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4809                CodeContextMenu::CodeActions(_) => None,
 4810            });
 4811
 4812        match completions_source {
 4813            Some(CompletionsMenuSource::Words) => {
 4814                self.show_word_completions(&ShowWordCompletions, window, cx)
 4815            }
 4816            Some(CompletionsMenuSource::Normal)
 4817            | Some(CompletionsMenuSource::SnippetChoices)
 4818            | None
 4819                if self.is_completion_trigger(
 4820                    text,
 4821                    trigger_in_words,
 4822                    completions_source.is_some(),
 4823                    cx,
 4824                ) =>
 4825            {
 4826                self.show_completions(
 4827                    &ShowCompletions {
 4828                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4829                    },
 4830                    window,
 4831                    cx,
 4832                )
 4833            }
 4834            _ => {
 4835                self.hide_context_menu(window, cx);
 4836            }
 4837        }
 4838    }
 4839
 4840    fn is_completion_trigger(
 4841        &self,
 4842        text: &str,
 4843        trigger_in_words: bool,
 4844        menu_is_open: bool,
 4845        cx: &mut Context<Self>,
 4846    ) -> bool {
 4847        let position = self.selections.newest_anchor().head();
 4848        let multibuffer = self.buffer.read(cx);
 4849        let Some(buffer) = position
 4850            .buffer_id
 4851            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4852        else {
 4853            return false;
 4854        };
 4855
 4856        if let Some(completion_provider) = &self.completion_provider {
 4857            completion_provider.is_completion_trigger(
 4858                &buffer,
 4859                position.text_anchor,
 4860                text,
 4861                trigger_in_words,
 4862                menu_is_open,
 4863                cx,
 4864            )
 4865        } else {
 4866            false
 4867        }
 4868    }
 4869
 4870    /// If any empty selections is touching the start of its innermost containing autoclose
 4871    /// region, expand it to select the brackets.
 4872    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4873        let selections = self.selections.all::<usize>(cx);
 4874        let buffer = self.buffer.read(cx).read(cx);
 4875        let new_selections = self
 4876            .selections_with_autoclose_regions(selections, &buffer)
 4877            .map(|(mut selection, region)| {
 4878                if !selection.is_empty() {
 4879                    return selection;
 4880                }
 4881
 4882                if let Some(region) = region {
 4883                    let mut range = region.range.to_offset(&buffer);
 4884                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4885                        range.start -= region.pair.start.len();
 4886                        if buffer.contains_str_at(range.start, &region.pair.start)
 4887                            && buffer.contains_str_at(range.end, &region.pair.end)
 4888                        {
 4889                            range.end += region.pair.end.len();
 4890                            selection.start = range.start;
 4891                            selection.end = range.end;
 4892
 4893                            return selection;
 4894                        }
 4895                    }
 4896                }
 4897
 4898                let always_treat_brackets_as_autoclosed = buffer
 4899                    .language_settings_at(selection.start, cx)
 4900                    .always_treat_brackets_as_autoclosed;
 4901
 4902                if !always_treat_brackets_as_autoclosed {
 4903                    return selection;
 4904                }
 4905
 4906                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4907                    for (pair, enabled) in scope.brackets() {
 4908                        if !enabled || !pair.close {
 4909                            continue;
 4910                        }
 4911
 4912                        if buffer.contains_str_at(selection.start, &pair.end) {
 4913                            let pair_start_len = pair.start.len();
 4914                            if buffer.contains_str_at(
 4915                                selection.start.saturating_sub(pair_start_len),
 4916                                &pair.start,
 4917                            ) {
 4918                                selection.start -= pair_start_len;
 4919                                selection.end += pair.end.len();
 4920
 4921                                return selection;
 4922                            }
 4923                        }
 4924                    }
 4925                }
 4926
 4927                selection
 4928            })
 4929            .collect();
 4930
 4931        drop(buffer);
 4932        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4933            selections.select(new_selections)
 4934        });
 4935    }
 4936
 4937    /// Iterate the given selections, and for each one, find the smallest surrounding
 4938    /// autoclose region. This uses the ordering of the selections and the autoclose
 4939    /// regions to avoid repeated comparisons.
 4940    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4941        &'a self,
 4942        selections: impl IntoIterator<Item = Selection<D>>,
 4943        buffer: &'a MultiBufferSnapshot,
 4944    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4945        let mut i = 0;
 4946        let mut regions = self.autoclose_regions.as_slice();
 4947        selections.into_iter().map(move |selection| {
 4948            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4949
 4950            let mut enclosing = None;
 4951            while let Some(pair_state) = regions.get(i) {
 4952                if pair_state.range.end.to_offset(buffer) < range.start {
 4953                    regions = &regions[i + 1..];
 4954                    i = 0;
 4955                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4956                    break;
 4957                } else {
 4958                    if pair_state.selection_id == selection.id {
 4959                        enclosing = Some(pair_state);
 4960                    }
 4961                    i += 1;
 4962                }
 4963            }
 4964
 4965            (selection, enclosing)
 4966        })
 4967    }
 4968
 4969    /// Remove any autoclose regions that no longer contain their selection.
 4970    fn invalidate_autoclose_regions(
 4971        &mut self,
 4972        mut selections: &[Selection<Anchor>],
 4973        buffer: &MultiBufferSnapshot,
 4974    ) {
 4975        self.autoclose_regions.retain(|state| {
 4976            let mut i = 0;
 4977            while let Some(selection) = selections.get(i) {
 4978                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4979                    selections = &selections[1..];
 4980                    continue;
 4981                }
 4982                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4983                    break;
 4984                }
 4985                if selection.id == state.selection_id {
 4986                    return true;
 4987                } else {
 4988                    i += 1;
 4989                }
 4990            }
 4991            false
 4992        });
 4993    }
 4994
 4995    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4996        let offset = position.to_offset(buffer);
 4997        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4998        if offset > word_range.start && kind == Some(CharKind::Word) {
 4999            Some(
 5000                buffer
 5001                    .text_for_range(word_range.start..offset)
 5002                    .collect::<String>(),
 5003            )
 5004        } else {
 5005            None
 5006        }
 5007    }
 5008
 5009    pub fn toggle_inline_values(
 5010        &mut self,
 5011        _: &ToggleInlineValues,
 5012        _: &mut Window,
 5013        cx: &mut Context<Self>,
 5014    ) {
 5015        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5016
 5017        self.refresh_inline_values(cx);
 5018    }
 5019
 5020    pub fn toggle_inlay_hints(
 5021        &mut self,
 5022        _: &ToggleInlayHints,
 5023        _: &mut Window,
 5024        cx: &mut Context<Self>,
 5025    ) {
 5026        self.refresh_inlay_hints(
 5027            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5028            cx,
 5029        );
 5030    }
 5031
 5032    pub fn inlay_hints_enabled(&self) -> bool {
 5033        self.inlay_hint_cache.enabled
 5034    }
 5035
 5036    pub fn inline_values_enabled(&self) -> bool {
 5037        self.inline_value_cache.enabled
 5038    }
 5039
 5040    #[cfg(any(test, feature = "test-support"))]
 5041    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5042        self.display_map
 5043            .read(cx)
 5044            .current_inlays()
 5045            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5046            .cloned()
 5047            .collect()
 5048    }
 5049
 5050    #[cfg(any(test, feature = "test-support"))]
 5051    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5052        self.display_map
 5053            .read(cx)
 5054            .current_inlays()
 5055            .cloned()
 5056            .collect()
 5057    }
 5058
 5059    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5060        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5061            return;
 5062        }
 5063
 5064        let reason_description = reason.description();
 5065        let ignore_debounce = matches!(
 5066            reason,
 5067            InlayHintRefreshReason::SettingsChange(_)
 5068                | InlayHintRefreshReason::Toggle(_)
 5069                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5070                | InlayHintRefreshReason::ModifiersChanged(_)
 5071        );
 5072        let (invalidate_cache, required_languages) = match reason {
 5073            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5074                match self.inlay_hint_cache.modifiers_override(enabled) {
 5075                    Some(enabled) => {
 5076                        if enabled {
 5077                            (InvalidationStrategy::RefreshRequested, None)
 5078                        } else {
 5079                            self.splice_inlays(
 5080                                &self
 5081                                    .visible_inlay_hints(cx)
 5082                                    .iter()
 5083                                    .map(|inlay| inlay.id)
 5084                                    .collect::<Vec<InlayId>>(),
 5085                                Vec::new(),
 5086                                cx,
 5087                            );
 5088                            return;
 5089                        }
 5090                    }
 5091                    None => return,
 5092                }
 5093            }
 5094            InlayHintRefreshReason::Toggle(enabled) => {
 5095                if self.inlay_hint_cache.toggle(enabled) {
 5096                    if enabled {
 5097                        (InvalidationStrategy::RefreshRequested, None)
 5098                    } else {
 5099                        self.splice_inlays(
 5100                            &self
 5101                                .visible_inlay_hints(cx)
 5102                                .iter()
 5103                                .map(|inlay| inlay.id)
 5104                                .collect::<Vec<InlayId>>(),
 5105                            Vec::new(),
 5106                            cx,
 5107                        );
 5108                        return;
 5109                    }
 5110                } else {
 5111                    return;
 5112                }
 5113            }
 5114            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5115                match self.inlay_hint_cache.update_settings(
 5116                    &self.buffer,
 5117                    new_settings,
 5118                    self.visible_inlay_hints(cx),
 5119                    cx,
 5120                ) {
 5121                    ControlFlow::Break(Some(InlaySplice {
 5122                        to_remove,
 5123                        to_insert,
 5124                    })) => {
 5125                        self.splice_inlays(&to_remove, to_insert, cx);
 5126                        return;
 5127                    }
 5128                    ControlFlow::Break(None) => return,
 5129                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5130                }
 5131            }
 5132            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5133                if let Some(InlaySplice {
 5134                    to_remove,
 5135                    to_insert,
 5136                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5137                {
 5138                    self.splice_inlays(&to_remove, to_insert, cx);
 5139                }
 5140                self.display_map.update(cx, |display_map, _| {
 5141                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5142                });
 5143                return;
 5144            }
 5145            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5146            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5147                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5148            }
 5149            InlayHintRefreshReason::RefreshRequested => {
 5150                (InvalidationStrategy::RefreshRequested, None)
 5151            }
 5152        };
 5153
 5154        if let Some(InlaySplice {
 5155            to_remove,
 5156            to_insert,
 5157        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5158            reason_description,
 5159            self.visible_excerpts(required_languages.as_ref(), cx),
 5160            invalidate_cache,
 5161            ignore_debounce,
 5162            cx,
 5163        ) {
 5164            self.splice_inlays(&to_remove, to_insert, cx);
 5165        }
 5166    }
 5167
 5168    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5169        self.display_map
 5170            .read(cx)
 5171            .current_inlays()
 5172            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5173            .cloned()
 5174            .collect()
 5175    }
 5176
 5177    pub fn visible_excerpts(
 5178        &self,
 5179        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5180        cx: &mut Context<Editor>,
 5181    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5182        let Some(project) = self.project.as_ref() else {
 5183            return HashMap::default();
 5184        };
 5185        let project = project.read(cx);
 5186        let multi_buffer = self.buffer().read(cx);
 5187        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5188        let multi_buffer_visible_start = self
 5189            .scroll_manager
 5190            .anchor()
 5191            .anchor
 5192            .to_point(&multi_buffer_snapshot);
 5193        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5194            multi_buffer_visible_start
 5195                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5196            Bias::Left,
 5197        );
 5198        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5199        multi_buffer_snapshot
 5200            .range_to_buffer_ranges(multi_buffer_visible_range)
 5201            .into_iter()
 5202            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5203            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5204                let buffer_file = project::File::from_dyn(buffer.file())?;
 5205                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5206                let worktree_entry = buffer_worktree
 5207                    .read(cx)
 5208                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5209                if worktree_entry.is_ignored {
 5210                    return None;
 5211                }
 5212
 5213                let language = buffer.language()?;
 5214                if let Some(restrict_to_languages) = restrict_to_languages {
 5215                    if !restrict_to_languages.contains(language) {
 5216                        return None;
 5217                    }
 5218                }
 5219                Some((
 5220                    excerpt_id,
 5221                    (
 5222                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5223                        buffer.version().clone(),
 5224                        excerpt_visible_range,
 5225                    ),
 5226                ))
 5227            })
 5228            .collect()
 5229    }
 5230
 5231    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5232        TextLayoutDetails {
 5233            text_system: window.text_system().clone(),
 5234            editor_style: self.style.clone().unwrap(),
 5235            rem_size: window.rem_size(),
 5236            scroll_anchor: self.scroll_manager.anchor(),
 5237            visible_rows: self.visible_line_count(),
 5238            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5239        }
 5240    }
 5241
 5242    pub fn splice_inlays(
 5243        &self,
 5244        to_remove: &[InlayId],
 5245        to_insert: Vec<Inlay>,
 5246        cx: &mut Context<Self>,
 5247    ) {
 5248        self.display_map.update(cx, |display_map, cx| {
 5249            display_map.splice_inlays(to_remove, to_insert, cx)
 5250        });
 5251        cx.notify();
 5252    }
 5253
 5254    fn trigger_on_type_formatting(
 5255        &self,
 5256        input: String,
 5257        window: &mut Window,
 5258        cx: &mut Context<Self>,
 5259    ) -> Option<Task<Result<()>>> {
 5260        if input.len() != 1 {
 5261            return None;
 5262        }
 5263
 5264        let project = self.project.as_ref()?;
 5265        let position = self.selections.newest_anchor().head();
 5266        let (buffer, buffer_position) = self
 5267            .buffer
 5268            .read(cx)
 5269            .text_anchor_for_position(position, cx)?;
 5270
 5271        let settings = language_settings::language_settings(
 5272            buffer
 5273                .read(cx)
 5274                .language_at(buffer_position)
 5275                .map(|l| l.name()),
 5276            buffer.read(cx).file(),
 5277            cx,
 5278        );
 5279        if !settings.use_on_type_format {
 5280            return None;
 5281        }
 5282
 5283        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5284        // hence we do LSP request & edit on host side only — add formats to host's history.
 5285        let push_to_lsp_host_history = true;
 5286        // If this is not the host, append its history with new edits.
 5287        let push_to_client_history = project.read(cx).is_via_collab();
 5288
 5289        let on_type_formatting = project.update(cx, |project, cx| {
 5290            project.on_type_format(
 5291                buffer.clone(),
 5292                buffer_position,
 5293                input,
 5294                push_to_lsp_host_history,
 5295                cx,
 5296            )
 5297        });
 5298        Some(cx.spawn_in(window, async move |editor, cx| {
 5299            if let Some(transaction) = on_type_formatting.await? {
 5300                if push_to_client_history {
 5301                    buffer
 5302                        .update(cx, |buffer, _| {
 5303                            buffer.push_transaction(transaction, Instant::now());
 5304                            buffer.finalize_last_transaction();
 5305                        })
 5306                        .ok();
 5307                }
 5308                editor.update(cx, |editor, cx| {
 5309                    editor.refresh_document_highlights(cx);
 5310                })?;
 5311            }
 5312            Ok(())
 5313        }))
 5314    }
 5315
 5316    pub fn show_word_completions(
 5317        &mut self,
 5318        _: &ShowWordCompletions,
 5319        window: &mut Window,
 5320        cx: &mut Context<Self>,
 5321    ) {
 5322        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5323    }
 5324
 5325    pub fn show_completions(
 5326        &mut self,
 5327        options: &ShowCompletions,
 5328        window: &mut Window,
 5329        cx: &mut Context<Self>,
 5330    ) {
 5331        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5332    }
 5333
 5334    fn open_or_update_completions_menu(
 5335        &mut self,
 5336        requested_source: Option<CompletionsMenuSource>,
 5337        trigger: Option<&str>,
 5338        window: &mut Window,
 5339        cx: &mut Context<Self>,
 5340    ) {
 5341        if self.pending_rename.is_some() {
 5342            return;
 5343        }
 5344
 5345        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5346
 5347        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5348        // inserted and selected. To handle that case, the start of the selection is used so that
 5349        // the menu starts with all choices.
 5350        let position = self
 5351            .selections
 5352            .newest_anchor()
 5353            .start
 5354            .bias_right(&multibuffer_snapshot);
 5355        if position.diff_base_anchor.is_some() {
 5356            return;
 5357        }
 5358        let (buffer, buffer_position) =
 5359            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5360                output
 5361            } else {
 5362                return;
 5363            };
 5364        let buffer_snapshot = buffer.read(cx).snapshot();
 5365
 5366        let query: Option<Arc<String>> =
 5367            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5368
 5369        drop(multibuffer_snapshot);
 5370
 5371        let provider = match requested_source {
 5372            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5373            Some(CompletionsMenuSource::Words) => None,
 5374            Some(CompletionsMenuSource::SnippetChoices) => {
 5375                log::error!("bug: SnippetChoices requested_source is not handled");
 5376                None
 5377            }
 5378        };
 5379
 5380        let sort_completions = provider
 5381            .as_ref()
 5382            .map_or(false, |provider| provider.sort_completions());
 5383
 5384        let filter_completions = provider
 5385            .as_ref()
 5386            .map_or(true, |provider| provider.filter_completions());
 5387
 5388        let trigger_kind = match trigger {
 5389            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5390                CompletionTriggerKind::TRIGGER_CHARACTER
 5391            }
 5392            _ => CompletionTriggerKind::INVOKED,
 5393        };
 5394        let completion_context = CompletionContext {
 5395            trigger_character: trigger.and_then(|trigger| {
 5396                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5397                    Some(String::from(trigger))
 5398                } else {
 5399                    None
 5400                }
 5401            }),
 5402            trigger_kind,
 5403        };
 5404
 5405        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5406        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5407        // involve trigger chars, so this is skipped in that case.
 5408        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5409        {
 5410            let menu_is_open = matches!(
 5411                self.context_menu.borrow().as_ref(),
 5412                Some(CodeContextMenu::Completions(_))
 5413            );
 5414            if menu_is_open {
 5415                self.hide_context_menu(window, cx);
 5416            }
 5417        }
 5418
 5419        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5420            if filter_completions {
 5421                menu.filter(query.clone(), provider.clone(), window, cx);
 5422            }
 5423            // When `is_incomplete` is false, no need to re-query completions when the current query
 5424            // is a suffix of the initial query.
 5425            if !menu.is_incomplete {
 5426                // If the new query is a suffix of the old query (typing more characters) and
 5427                // the previous result was complete, the existing completions can be filtered.
 5428                //
 5429                // Note that this is always true for snippet completions.
 5430                let query_matches = match (&menu.initial_query, &query) {
 5431                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5432                    (None, _) => true,
 5433                    _ => false,
 5434                };
 5435                if query_matches {
 5436                    let position_matches = if menu.initial_position == position {
 5437                        true
 5438                    } else {
 5439                        let snapshot = self.buffer.read(cx).read(cx);
 5440                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5441                    };
 5442                    if position_matches {
 5443                        return;
 5444                    }
 5445                }
 5446            }
 5447        };
 5448
 5449        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5450            buffer_snapshot.surrounding_word(buffer_position)
 5451        {
 5452            let word_to_exclude = buffer_snapshot
 5453                .text_for_range(word_range.clone())
 5454                .collect::<String>();
 5455            (
 5456                buffer_snapshot.anchor_before(word_range.start)
 5457                    ..buffer_snapshot.anchor_after(buffer_position),
 5458                Some(word_to_exclude),
 5459            )
 5460        } else {
 5461            (buffer_position..buffer_position, None)
 5462        };
 5463
 5464        let language = buffer_snapshot
 5465            .language_at(buffer_position)
 5466            .map(|language| language.name());
 5467
 5468        let completion_settings =
 5469            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5470
 5471        let show_completion_documentation = buffer_snapshot
 5472            .settings_at(buffer_position, cx)
 5473            .show_completion_documentation;
 5474
 5475        // The document can be large, so stay in reasonable bounds when searching for words,
 5476        // otherwise completion pop-up might be slow to appear.
 5477        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5478        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5479        let min_word_search = buffer_snapshot.clip_point(
 5480            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5481            Bias::Left,
 5482        );
 5483        let max_word_search = buffer_snapshot.clip_point(
 5484            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5485            Bias::Right,
 5486        );
 5487        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5488            ..buffer_snapshot.point_to_offset(max_word_search);
 5489
 5490        let skip_digits = query
 5491            .as_ref()
 5492            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5493
 5494        let (mut words, provider_responses) = match &provider {
 5495            Some(provider) => {
 5496                let provider_responses = provider.completions(
 5497                    position.excerpt_id,
 5498                    &buffer,
 5499                    buffer_position,
 5500                    completion_context,
 5501                    window,
 5502                    cx,
 5503                );
 5504
 5505                let words = match completion_settings.words {
 5506                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5507                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5508                        .background_spawn(async move {
 5509                            buffer_snapshot.words_in_range(WordsQuery {
 5510                                fuzzy_contents: None,
 5511                                range: word_search_range,
 5512                                skip_digits,
 5513                            })
 5514                        }),
 5515                };
 5516
 5517                (words, provider_responses)
 5518            }
 5519            None => (
 5520                cx.background_spawn(async move {
 5521                    buffer_snapshot.words_in_range(WordsQuery {
 5522                        fuzzy_contents: None,
 5523                        range: word_search_range,
 5524                        skip_digits,
 5525                    })
 5526                }),
 5527                Task::ready(Ok(Vec::new())),
 5528            ),
 5529        };
 5530
 5531        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5532
 5533        let id = post_inc(&mut self.next_completion_id);
 5534        let task = cx.spawn_in(window, async move |editor, cx| {
 5535            let Ok(()) = editor.update(cx, |this, _| {
 5536                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5537            }) else {
 5538                return;
 5539            };
 5540
 5541            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5542            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5543            let mut completions = Vec::new();
 5544            let mut is_incomplete = false;
 5545            if let Some(provider_responses) = provider_responses.await.log_err() {
 5546                if !provider_responses.is_empty() {
 5547                    for response in provider_responses {
 5548                        completions.extend(response.completions);
 5549                        is_incomplete = is_incomplete || response.is_incomplete;
 5550                    }
 5551                    if completion_settings.words == WordsCompletionMode::Fallback {
 5552                        words = Task::ready(BTreeMap::default());
 5553                    }
 5554                }
 5555            }
 5556
 5557            let mut words = words.await;
 5558            if let Some(word_to_exclude) = &word_to_exclude {
 5559                words.remove(word_to_exclude);
 5560            }
 5561            for lsp_completion in &completions {
 5562                words.remove(&lsp_completion.new_text);
 5563            }
 5564            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5565                replace_range: word_replace_range.clone(),
 5566                new_text: word.clone(),
 5567                label: CodeLabel::plain(word, None),
 5568                icon_path: None,
 5569                documentation: None,
 5570                source: CompletionSource::BufferWord {
 5571                    word_range,
 5572                    resolved: false,
 5573                },
 5574                insert_text_mode: Some(InsertTextMode::AS_IS),
 5575                confirm: None,
 5576            }));
 5577
 5578            let menu = if completions.is_empty() {
 5579                None
 5580            } else {
 5581                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5582                    let languages = editor
 5583                        .workspace
 5584                        .as_ref()
 5585                        .and_then(|(workspace, _)| workspace.upgrade())
 5586                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5587                    let menu = CompletionsMenu::new(
 5588                        id,
 5589                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5590                        sort_completions,
 5591                        show_completion_documentation,
 5592                        position,
 5593                        query.clone(),
 5594                        is_incomplete,
 5595                        buffer.clone(),
 5596                        completions.into(),
 5597                        snippet_sort_order,
 5598                        languages,
 5599                        language,
 5600                        cx,
 5601                    );
 5602
 5603                    let query = if filter_completions { query } else { None };
 5604                    let matches_task = if let Some(query) = query {
 5605                        menu.do_async_filtering(query, cx)
 5606                    } else {
 5607                        Task::ready(menu.unfiltered_matches())
 5608                    };
 5609                    (menu, matches_task)
 5610                }) else {
 5611                    return;
 5612                };
 5613
 5614                let matches = matches_task.await;
 5615
 5616                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5617                    // Newer menu already set, so exit.
 5618                    match editor.context_menu.borrow().as_ref() {
 5619                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5620                            if prev_menu.id > id {
 5621                                return;
 5622                            }
 5623                        }
 5624                        _ => {}
 5625                    };
 5626
 5627                    // Only valid to take prev_menu because it the new menu is immediately set
 5628                    // below, or the menu is hidden.
 5629                    match editor.context_menu.borrow_mut().take() {
 5630                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5631                            let position_matches =
 5632                                if prev_menu.initial_position == menu.initial_position {
 5633                                    true
 5634                                } else {
 5635                                    let snapshot = editor.buffer.read(cx).read(cx);
 5636                                    prev_menu.initial_position.to_offset(&snapshot)
 5637                                        == menu.initial_position.to_offset(&snapshot)
 5638                                };
 5639                            if position_matches {
 5640                                // Preserve markdown cache before `set_filter_results` because it will
 5641                                // try to populate the documentation cache.
 5642                                menu.preserve_markdown_cache(prev_menu);
 5643                            }
 5644                        }
 5645                        _ => {}
 5646                    };
 5647
 5648                    menu.set_filter_results(matches, provider, window, cx);
 5649                }) else {
 5650                    return;
 5651                };
 5652
 5653                menu.visible().then_some(menu)
 5654            };
 5655
 5656            editor
 5657                .update_in(cx, |editor, window, cx| {
 5658                    if editor.focus_handle.is_focused(window) {
 5659                        if let Some(menu) = menu {
 5660                            *editor.context_menu.borrow_mut() =
 5661                                Some(CodeContextMenu::Completions(menu));
 5662
 5663                            crate::hover_popover::hide_hover(editor, cx);
 5664                            if editor.show_edit_predictions_in_menu() {
 5665                                editor.update_visible_inline_completion(window, cx);
 5666                            } else {
 5667                                editor.discard_inline_completion(false, cx);
 5668                            }
 5669
 5670                            cx.notify();
 5671                            return;
 5672                        }
 5673                    }
 5674
 5675                    if editor.completion_tasks.len() <= 1 {
 5676                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5677                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5678                        // If it was already hidden and we don't show inline completions in the menu, we should
 5679                        // also show the inline-completion when available.
 5680                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5681                            editor.update_visible_inline_completion(window, cx);
 5682                        }
 5683                    }
 5684                })
 5685                .ok();
 5686        });
 5687
 5688        self.completion_tasks.push((id, task));
 5689    }
 5690
 5691    #[cfg(feature = "test-support")]
 5692    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5693        let menu = self.context_menu.borrow();
 5694        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5695            let completions = menu.completions.borrow();
 5696            Some(completions.to_vec())
 5697        } else {
 5698            None
 5699        }
 5700    }
 5701
 5702    pub fn with_completions_menu_matching_id<R>(
 5703        &self,
 5704        id: CompletionId,
 5705        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5706    ) -> R {
 5707        let mut context_menu = self.context_menu.borrow_mut();
 5708        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5709            return f(None);
 5710        };
 5711        if completions_menu.id != id {
 5712            return f(None);
 5713        }
 5714        f(Some(completions_menu))
 5715    }
 5716
 5717    pub fn confirm_completion(
 5718        &mut self,
 5719        action: &ConfirmCompletion,
 5720        window: &mut Window,
 5721        cx: &mut Context<Self>,
 5722    ) -> Option<Task<Result<()>>> {
 5723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5724        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5725    }
 5726
 5727    pub fn confirm_completion_insert(
 5728        &mut self,
 5729        _: &ConfirmCompletionInsert,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5735    }
 5736
 5737    pub fn confirm_completion_replace(
 5738        &mut self,
 5739        _: &ConfirmCompletionReplace,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5745    }
 5746
 5747    pub fn compose_completion(
 5748        &mut self,
 5749        action: &ComposeCompletion,
 5750        window: &mut Window,
 5751        cx: &mut Context<Self>,
 5752    ) -> Option<Task<Result<()>>> {
 5753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5754        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5755    }
 5756
 5757    fn do_completion(
 5758        &mut self,
 5759        item_ix: Option<usize>,
 5760        intent: CompletionIntent,
 5761        window: &mut Window,
 5762        cx: &mut Context<Editor>,
 5763    ) -> Option<Task<Result<()>>> {
 5764        use language::ToOffset as _;
 5765
 5766        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5767        else {
 5768            return None;
 5769        };
 5770
 5771        let candidate_id = {
 5772            let entries = completions_menu.entries.borrow();
 5773            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5774            if self.show_edit_predictions_in_menu() {
 5775                self.discard_inline_completion(true, cx);
 5776            }
 5777            mat.candidate_id
 5778        };
 5779
 5780        let completion = completions_menu
 5781            .completions
 5782            .borrow()
 5783            .get(candidate_id)?
 5784            .clone();
 5785        cx.stop_propagation();
 5786
 5787        let buffer_handle = completions_menu.buffer.clone();
 5788
 5789        let CompletionEdit {
 5790            new_text,
 5791            snippet,
 5792            replace_range,
 5793        } = process_completion_for_edit(
 5794            &completion,
 5795            intent,
 5796            &buffer_handle,
 5797            &completions_menu.initial_position.text_anchor,
 5798            cx,
 5799        );
 5800
 5801        let buffer = buffer_handle.read(cx);
 5802        let snapshot = self.buffer.read(cx).snapshot(cx);
 5803        let newest_anchor = self.selections.newest_anchor();
 5804        let replace_range_multibuffer = {
 5805            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5806            let multibuffer_anchor = snapshot
 5807                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5808                .unwrap()
 5809                ..snapshot
 5810                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5811                    .unwrap();
 5812            multibuffer_anchor.start.to_offset(&snapshot)
 5813                ..multibuffer_anchor.end.to_offset(&snapshot)
 5814        };
 5815        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5816            return None;
 5817        }
 5818
 5819        let old_text = buffer
 5820            .text_for_range(replace_range.clone())
 5821            .collect::<String>();
 5822        let lookbehind = newest_anchor
 5823            .start
 5824            .text_anchor
 5825            .to_offset(buffer)
 5826            .saturating_sub(replace_range.start);
 5827        let lookahead = replace_range
 5828            .end
 5829            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5830        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5831        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5832
 5833        let selections = self.selections.all::<usize>(cx);
 5834        let mut ranges = Vec::new();
 5835        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5836
 5837        for selection in &selections {
 5838            let range = if selection.id == newest_anchor.id {
 5839                replace_range_multibuffer.clone()
 5840            } else {
 5841                let mut range = selection.range();
 5842
 5843                // if prefix is present, don't duplicate it
 5844                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5845                    range.start = range.start.saturating_sub(lookbehind);
 5846
 5847                    // if suffix is also present, mimic the newest cursor and replace it
 5848                    if selection.id != newest_anchor.id
 5849                        && snapshot.contains_str_at(range.end, suffix)
 5850                    {
 5851                        range.end += lookahead;
 5852                    }
 5853                }
 5854                range
 5855            };
 5856
 5857            ranges.push(range.clone());
 5858
 5859            if !self.linked_edit_ranges.is_empty() {
 5860                let start_anchor = snapshot.anchor_before(range.start);
 5861                let end_anchor = snapshot.anchor_after(range.end);
 5862                if let Some(ranges) = self
 5863                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5864                {
 5865                    for (buffer, edits) in ranges {
 5866                        linked_edits
 5867                            .entry(buffer.clone())
 5868                            .or_default()
 5869                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5870                    }
 5871                }
 5872            }
 5873        }
 5874
 5875        let common_prefix_len = old_text
 5876            .chars()
 5877            .zip(new_text.chars())
 5878            .take_while(|(a, b)| a == b)
 5879            .map(|(a, _)| a.len_utf8())
 5880            .sum::<usize>();
 5881
 5882        cx.emit(EditorEvent::InputHandled {
 5883            utf16_range_to_replace: None,
 5884            text: new_text[common_prefix_len..].into(),
 5885        });
 5886
 5887        self.transact(window, cx, |this, window, cx| {
 5888            if let Some(mut snippet) = snippet {
 5889                snippet.text = new_text.to_string();
 5890                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5891            } else {
 5892                this.buffer.update(cx, |buffer, cx| {
 5893                    let auto_indent = match completion.insert_text_mode {
 5894                        Some(InsertTextMode::AS_IS) => None,
 5895                        _ => this.autoindent_mode.clone(),
 5896                    };
 5897                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5898                    buffer.edit(edits, auto_indent, cx);
 5899                });
 5900            }
 5901            for (buffer, edits) in linked_edits {
 5902                buffer.update(cx, |buffer, cx| {
 5903                    let snapshot = buffer.snapshot();
 5904                    let edits = edits
 5905                        .into_iter()
 5906                        .map(|(range, text)| {
 5907                            use text::ToPoint as TP;
 5908                            let end_point = TP::to_point(&range.end, &snapshot);
 5909                            let start_point = TP::to_point(&range.start, &snapshot);
 5910                            (start_point..end_point, text)
 5911                        })
 5912                        .sorted_by_key(|(range, _)| range.start);
 5913                    buffer.edit(edits, None, cx);
 5914                })
 5915            }
 5916
 5917            this.refresh_inline_completion(true, false, window, cx);
 5918        });
 5919
 5920        let show_new_completions_on_confirm = completion
 5921            .confirm
 5922            .as_ref()
 5923            .map_or(false, |confirm| confirm(intent, window, cx));
 5924        if show_new_completions_on_confirm {
 5925            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5926        }
 5927
 5928        let provider = self.completion_provider.as_ref()?;
 5929        drop(completion);
 5930        let apply_edits = provider.apply_additional_edits_for_completion(
 5931            buffer_handle,
 5932            completions_menu.completions.clone(),
 5933            candidate_id,
 5934            true,
 5935            cx,
 5936        );
 5937
 5938        let editor_settings = EditorSettings::get_global(cx);
 5939        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5940            // After the code completion is finished, users often want to know what signatures are needed.
 5941            // so we should automatically call signature_help
 5942            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5943        }
 5944
 5945        Some(cx.foreground_executor().spawn(async move {
 5946            apply_edits.await?;
 5947            Ok(())
 5948        }))
 5949    }
 5950
 5951    pub fn toggle_code_actions(
 5952        &mut self,
 5953        action: &ToggleCodeActions,
 5954        window: &mut Window,
 5955        cx: &mut Context<Self>,
 5956    ) {
 5957        let quick_launch = action.quick_launch;
 5958        let mut context_menu = self.context_menu.borrow_mut();
 5959        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5960            if code_actions.deployed_from == action.deployed_from {
 5961                // Toggle if we're selecting the same one
 5962                *context_menu = None;
 5963                cx.notify();
 5964                return;
 5965            } else {
 5966                // Otherwise, clear it and start a new one
 5967                *context_menu = None;
 5968                cx.notify();
 5969            }
 5970        }
 5971        drop(context_menu);
 5972        let snapshot = self.snapshot(window, cx);
 5973        let deployed_from = action.deployed_from.clone();
 5974        let action = action.clone();
 5975        self.completion_tasks.clear();
 5976        self.discard_inline_completion(false, cx);
 5977
 5978        let multibuffer_point = match &action.deployed_from {
 5979            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5980                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5981            }
 5982            _ => self.selections.newest::<Point>(cx).head(),
 5983        };
 5984        let Some((buffer, buffer_row)) = snapshot
 5985            .buffer_snapshot
 5986            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5987            .and_then(|(buffer_snapshot, range)| {
 5988                self.buffer()
 5989                    .read(cx)
 5990                    .buffer(buffer_snapshot.remote_id())
 5991                    .map(|buffer| (buffer, range.start.row))
 5992            })
 5993        else {
 5994            return;
 5995        };
 5996        let buffer_id = buffer.read(cx).remote_id();
 5997        let tasks = self
 5998            .tasks
 5999            .get(&(buffer_id, buffer_row))
 6000            .map(|t| Arc::new(t.to_owned()));
 6001
 6002        if !self.focus_handle.is_focused(window) {
 6003            return;
 6004        }
 6005        let project = self.project.clone();
 6006
 6007        let code_actions_task = match deployed_from {
 6008            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6009            _ => self.code_actions(buffer_row, window, cx),
 6010        };
 6011
 6012        let runnable_task = match deployed_from {
 6013            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6014            _ => {
 6015                let mut task_context_task = Task::ready(None);
 6016                if let Some(tasks) = &tasks {
 6017                    if let Some(project) = project {
 6018                        task_context_task =
 6019                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6020                    }
 6021                }
 6022
 6023                cx.spawn_in(window, {
 6024                    let buffer = buffer.clone();
 6025                    async move |editor, cx| {
 6026                        let task_context = task_context_task.await;
 6027
 6028                        let resolved_tasks =
 6029                            tasks
 6030                                .zip(task_context.clone())
 6031                                .map(|(tasks, task_context)| ResolvedTasks {
 6032                                    templates: tasks.resolve(&task_context).collect(),
 6033                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6034                                        multibuffer_point.row,
 6035                                        tasks.column,
 6036                                    )),
 6037                                });
 6038                        let debug_scenarios = editor
 6039                            .update(cx, |editor, cx| {
 6040                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6041                            })?
 6042                            .await;
 6043                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6044                    }
 6045                })
 6046            }
 6047        };
 6048
 6049        cx.spawn_in(window, async move |editor, cx| {
 6050            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6051            let code_actions = code_actions_task.await;
 6052            let spawn_straight_away = quick_launch
 6053                && resolved_tasks
 6054                    .as_ref()
 6055                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6056                && code_actions
 6057                    .as_ref()
 6058                    .map_or(true, |actions| actions.is_empty())
 6059                && debug_scenarios.is_empty();
 6060
 6061            editor.update_in(cx, |editor, window, cx| {
 6062                crate::hover_popover::hide_hover(editor, cx);
 6063                let actions = CodeActionContents::new(
 6064                    resolved_tasks,
 6065                    code_actions,
 6066                    debug_scenarios,
 6067                    task_context.unwrap_or_default(),
 6068                );
 6069
 6070                // Don't show the menu if there are no actions available
 6071                if actions.is_empty() {
 6072                    cx.notify();
 6073                    return Task::ready(Ok(()));
 6074                }
 6075
 6076                *editor.context_menu.borrow_mut() =
 6077                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6078                        buffer,
 6079                        actions,
 6080                        selected_item: Default::default(),
 6081                        scroll_handle: UniformListScrollHandle::default(),
 6082                        deployed_from,
 6083                    }));
 6084                cx.notify();
 6085                if spawn_straight_away {
 6086                    if let Some(task) = editor.confirm_code_action(
 6087                        &ConfirmCodeAction { item_ix: Some(0) },
 6088                        window,
 6089                        cx,
 6090                    ) {
 6091                        return task;
 6092                    }
 6093                }
 6094
 6095                Task::ready(Ok(()))
 6096            })
 6097        })
 6098        .detach_and_log_err(cx);
 6099    }
 6100
 6101    fn debug_scenarios(
 6102        &mut self,
 6103        resolved_tasks: &Option<ResolvedTasks>,
 6104        buffer: &Entity<Buffer>,
 6105        cx: &mut App,
 6106    ) -> Task<Vec<task::DebugScenario>> {
 6107        maybe!({
 6108            let project = self.project.as_ref()?;
 6109            let dap_store = project.read(cx).dap_store();
 6110            let mut scenarios = vec![];
 6111            let resolved_tasks = resolved_tasks.as_ref()?;
 6112            let buffer = buffer.read(cx);
 6113            let language = buffer.language()?;
 6114            let file = buffer.file();
 6115            let debug_adapter = language_settings(language.name().into(), file, cx)
 6116                .debuggers
 6117                .first()
 6118                .map(SharedString::from)
 6119                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6120
 6121            dap_store.update(cx, |dap_store, cx| {
 6122                for (_, task) in &resolved_tasks.templates {
 6123                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6124                        task.original_task().clone(),
 6125                        debug_adapter.clone().into(),
 6126                        task.display_label().to_owned().into(),
 6127                        cx,
 6128                    );
 6129                    scenarios.push(maybe_scenario);
 6130                }
 6131            });
 6132            Some(cx.background_spawn(async move {
 6133                let scenarios = futures::future::join_all(scenarios)
 6134                    .await
 6135                    .into_iter()
 6136                    .flatten()
 6137                    .collect::<Vec<_>>();
 6138                scenarios
 6139            }))
 6140        })
 6141        .unwrap_or_else(|| Task::ready(vec![]))
 6142    }
 6143
 6144    fn code_actions(
 6145        &mut self,
 6146        buffer_row: u32,
 6147        window: &mut Window,
 6148        cx: &mut Context<Self>,
 6149    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6150        let mut task = self.code_actions_task.take();
 6151        cx.spawn_in(window, async move |editor, cx| {
 6152            while let Some(prev_task) = task {
 6153                prev_task.await.log_err();
 6154                task = editor
 6155                    .update(cx, |this, _| this.code_actions_task.take())
 6156                    .ok()?;
 6157            }
 6158
 6159            editor
 6160                .update(cx, |editor, cx| {
 6161                    editor
 6162                        .available_code_actions
 6163                        .clone()
 6164                        .and_then(|(location, code_actions)| {
 6165                            let snapshot = location.buffer.read(cx).snapshot();
 6166                            let point_range = location.range.to_point(&snapshot);
 6167                            let point_range = point_range.start.row..=point_range.end.row;
 6168                            if point_range.contains(&buffer_row) {
 6169                                Some(code_actions)
 6170                            } else {
 6171                                None
 6172                            }
 6173                        })
 6174                })
 6175                .ok()
 6176                .flatten()
 6177        })
 6178    }
 6179
 6180    pub fn confirm_code_action(
 6181        &mut self,
 6182        action: &ConfirmCodeAction,
 6183        window: &mut Window,
 6184        cx: &mut Context<Self>,
 6185    ) -> Option<Task<Result<()>>> {
 6186        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6187
 6188        let actions_menu =
 6189            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6190                menu
 6191            } else {
 6192                return None;
 6193            };
 6194
 6195        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6196        let action = actions_menu.actions.get(action_ix)?;
 6197        let title = action.label();
 6198        let buffer = actions_menu.buffer;
 6199        let workspace = self.workspace()?;
 6200
 6201        match action {
 6202            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6203                workspace.update(cx, |workspace, cx| {
 6204                    workspace.schedule_resolved_task(
 6205                        task_source_kind,
 6206                        resolved_task,
 6207                        false,
 6208                        window,
 6209                        cx,
 6210                    );
 6211
 6212                    Some(Task::ready(Ok(())))
 6213                })
 6214            }
 6215            CodeActionsItem::CodeAction {
 6216                excerpt_id,
 6217                action,
 6218                provider,
 6219            } => {
 6220                let apply_code_action =
 6221                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6222                let workspace = workspace.downgrade();
 6223                Some(cx.spawn_in(window, async move |editor, cx| {
 6224                    let project_transaction = apply_code_action.await?;
 6225                    Self::open_project_transaction(
 6226                        &editor,
 6227                        workspace,
 6228                        project_transaction,
 6229                        title,
 6230                        cx,
 6231                    )
 6232                    .await
 6233                }))
 6234            }
 6235            CodeActionsItem::DebugScenario(scenario) => {
 6236                let context = actions_menu.actions.context.clone();
 6237
 6238                workspace.update(cx, |workspace, cx| {
 6239                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6240                    workspace.start_debug_session(
 6241                        scenario,
 6242                        context,
 6243                        Some(buffer),
 6244                        None,
 6245                        window,
 6246                        cx,
 6247                    );
 6248                });
 6249                Some(Task::ready(Ok(())))
 6250            }
 6251        }
 6252    }
 6253
 6254    pub async fn open_project_transaction(
 6255        this: &WeakEntity<Editor>,
 6256        workspace: WeakEntity<Workspace>,
 6257        transaction: ProjectTransaction,
 6258        title: String,
 6259        cx: &mut AsyncWindowContext,
 6260    ) -> Result<()> {
 6261        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6262        cx.update(|_, cx| {
 6263            entries.sort_unstable_by_key(|(buffer, _)| {
 6264                buffer.read(cx).file().map(|f| f.path().clone())
 6265            });
 6266        })?;
 6267
 6268        // If the project transaction's edits are all contained within this editor, then
 6269        // avoid opening a new editor to display them.
 6270
 6271        if let Some((buffer, transaction)) = entries.first() {
 6272            if entries.len() == 1 {
 6273                let excerpt = this.update(cx, |editor, cx| {
 6274                    editor
 6275                        .buffer()
 6276                        .read(cx)
 6277                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6278                })?;
 6279                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6280                    if excerpted_buffer == *buffer {
 6281                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6282                            let excerpt_range = excerpt_range.to_offset(buffer);
 6283                            buffer
 6284                                .edited_ranges_for_transaction::<usize>(transaction)
 6285                                .all(|range| {
 6286                                    excerpt_range.start <= range.start
 6287                                        && excerpt_range.end >= range.end
 6288                                })
 6289                        })?;
 6290
 6291                        if all_edits_within_excerpt {
 6292                            return Ok(());
 6293                        }
 6294                    }
 6295                }
 6296            }
 6297        } else {
 6298            return Ok(());
 6299        }
 6300
 6301        let mut ranges_to_highlight = Vec::new();
 6302        let excerpt_buffer = cx.new(|cx| {
 6303            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6304            for (buffer_handle, transaction) in &entries {
 6305                let edited_ranges = buffer_handle
 6306                    .read(cx)
 6307                    .edited_ranges_for_transaction::<Point>(transaction)
 6308                    .collect::<Vec<_>>();
 6309                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6310                    PathKey::for_buffer(buffer_handle, cx),
 6311                    buffer_handle.clone(),
 6312                    edited_ranges,
 6313                    DEFAULT_MULTIBUFFER_CONTEXT,
 6314                    cx,
 6315                );
 6316
 6317                ranges_to_highlight.extend(ranges);
 6318            }
 6319            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6320            multibuffer
 6321        })?;
 6322
 6323        workspace.update_in(cx, |workspace, window, cx| {
 6324            let project = workspace.project().clone();
 6325            let editor =
 6326                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6327            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6328            editor.update(cx, |editor, cx| {
 6329                editor.highlight_background::<Self>(
 6330                    &ranges_to_highlight,
 6331                    |theme| theme.colors().editor_highlighted_line_background,
 6332                    cx,
 6333                );
 6334            });
 6335        })?;
 6336
 6337        Ok(())
 6338    }
 6339
 6340    pub fn clear_code_action_providers(&mut self) {
 6341        self.code_action_providers.clear();
 6342        self.available_code_actions.take();
 6343    }
 6344
 6345    pub fn add_code_action_provider(
 6346        &mut self,
 6347        provider: Rc<dyn CodeActionProvider>,
 6348        window: &mut Window,
 6349        cx: &mut Context<Self>,
 6350    ) {
 6351        if self
 6352            .code_action_providers
 6353            .iter()
 6354            .any(|existing_provider| existing_provider.id() == provider.id())
 6355        {
 6356            return;
 6357        }
 6358
 6359        self.code_action_providers.push(provider);
 6360        self.refresh_code_actions(window, cx);
 6361    }
 6362
 6363    pub fn remove_code_action_provider(
 6364        &mut self,
 6365        id: Arc<str>,
 6366        window: &mut Window,
 6367        cx: &mut Context<Self>,
 6368    ) {
 6369        self.code_action_providers
 6370            .retain(|provider| provider.id() != id);
 6371        self.refresh_code_actions(window, cx);
 6372    }
 6373
 6374    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6375        !self.code_action_providers.is_empty()
 6376            && EditorSettings::get_global(cx).toolbar.code_actions
 6377    }
 6378
 6379    pub fn has_available_code_actions(&self) -> bool {
 6380        self.available_code_actions
 6381            .as_ref()
 6382            .is_some_and(|(_, actions)| !actions.is_empty())
 6383    }
 6384
 6385    fn render_inline_code_actions(
 6386        &self,
 6387        icon_size: ui::IconSize,
 6388        display_row: DisplayRow,
 6389        is_active: bool,
 6390        cx: &mut Context<Self>,
 6391    ) -> AnyElement {
 6392        let show_tooltip = !self.context_menu_visible();
 6393        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6394            .icon_size(icon_size)
 6395            .shape(ui::IconButtonShape::Square)
 6396            .style(ButtonStyle::Transparent)
 6397            .icon_color(ui::Color::Hidden)
 6398            .toggle_state(is_active)
 6399            .when(show_tooltip, |this| {
 6400                this.tooltip({
 6401                    let focus_handle = self.focus_handle.clone();
 6402                    move |window, cx| {
 6403                        Tooltip::for_action_in(
 6404                            "Toggle Code Actions",
 6405                            &ToggleCodeActions {
 6406                                deployed_from: None,
 6407                                quick_launch: false,
 6408                            },
 6409                            &focus_handle,
 6410                            window,
 6411                            cx,
 6412                        )
 6413                    }
 6414                })
 6415            })
 6416            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6417                window.focus(&editor.focus_handle(cx));
 6418                editor.toggle_code_actions(
 6419                    &crate::actions::ToggleCodeActions {
 6420                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6421                            display_row,
 6422                        )),
 6423                        quick_launch: false,
 6424                    },
 6425                    window,
 6426                    cx,
 6427                );
 6428            }))
 6429            .into_any_element()
 6430    }
 6431
 6432    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6433        &self.context_menu
 6434    }
 6435
 6436    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6437        let newest_selection = self.selections.newest_anchor().clone();
 6438        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6439        let buffer = self.buffer.read(cx);
 6440        if newest_selection.head().diff_base_anchor.is_some() {
 6441            return None;
 6442        }
 6443        let (start_buffer, start) =
 6444            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6445        let (end_buffer, end) =
 6446            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6447        if start_buffer != end_buffer {
 6448            return None;
 6449        }
 6450
 6451        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6452            cx.background_executor()
 6453                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6454                .await;
 6455
 6456            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6457                let providers = this.code_action_providers.clone();
 6458                let tasks = this
 6459                    .code_action_providers
 6460                    .iter()
 6461                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6462                    .collect::<Vec<_>>();
 6463                (providers, tasks)
 6464            })?;
 6465
 6466            let mut actions = Vec::new();
 6467            for (provider, provider_actions) in
 6468                providers.into_iter().zip(future::join_all(tasks).await)
 6469            {
 6470                if let Some(provider_actions) = provider_actions.log_err() {
 6471                    actions.extend(provider_actions.into_iter().map(|action| {
 6472                        AvailableCodeAction {
 6473                            excerpt_id: newest_selection.start.excerpt_id,
 6474                            action,
 6475                            provider: provider.clone(),
 6476                        }
 6477                    }));
 6478                }
 6479            }
 6480
 6481            this.update(cx, |this, cx| {
 6482                this.available_code_actions = if actions.is_empty() {
 6483                    None
 6484                } else {
 6485                    Some((
 6486                        Location {
 6487                            buffer: start_buffer,
 6488                            range: start..end,
 6489                        },
 6490                        actions.into(),
 6491                    ))
 6492                };
 6493                cx.notify();
 6494            })
 6495        }));
 6496        None
 6497    }
 6498
 6499    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6500        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6501            self.show_git_blame_inline = false;
 6502
 6503            self.show_git_blame_inline_delay_task =
 6504                Some(cx.spawn_in(window, async move |this, cx| {
 6505                    cx.background_executor().timer(delay).await;
 6506
 6507                    this.update(cx, |this, cx| {
 6508                        this.show_git_blame_inline = true;
 6509                        cx.notify();
 6510                    })
 6511                    .log_err();
 6512                }));
 6513        }
 6514    }
 6515
 6516    fn show_blame_popover(
 6517        &mut self,
 6518        blame_entry: &BlameEntry,
 6519        position: gpui::Point<Pixels>,
 6520        cx: &mut Context<Self>,
 6521    ) {
 6522        if let Some(state) = &mut self.inline_blame_popover {
 6523            state.hide_task.take();
 6524        } else {
 6525            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6526            let blame_entry = blame_entry.clone();
 6527            let show_task = cx.spawn(async move |editor, cx| {
 6528                cx.background_executor()
 6529                    .timer(std::time::Duration::from_millis(delay))
 6530                    .await;
 6531                editor
 6532                    .update(cx, |editor, cx| {
 6533                        editor.inline_blame_popover_show_task.take();
 6534                        let Some(blame) = editor.blame.as_ref() else {
 6535                            return;
 6536                        };
 6537                        let blame = blame.read(cx);
 6538                        let details = blame.details_for_entry(&blame_entry);
 6539                        let markdown = cx.new(|cx| {
 6540                            Markdown::new(
 6541                                details
 6542                                    .as_ref()
 6543                                    .map(|message| message.message.clone())
 6544                                    .unwrap_or_default(),
 6545                                None,
 6546                                None,
 6547                                cx,
 6548                            )
 6549                        });
 6550                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6551                            position,
 6552                            hide_task: None,
 6553                            popover_bounds: None,
 6554                            popover_state: InlineBlamePopoverState {
 6555                                scroll_handle: ScrollHandle::new(),
 6556                                commit_message: details,
 6557                                markdown,
 6558                            },
 6559                        });
 6560                        cx.notify();
 6561                    })
 6562                    .ok();
 6563            });
 6564            self.inline_blame_popover_show_task = Some(show_task);
 6565        }
 6566    }
 6567
 6568    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6569        self.inline_blame_popover_show_task.take();
 6570        if let Some(state) = &mut self.inline_blame_popover {
 6571            let hide_task = cx.spawn(async move |editor, cx| {
 6572                cx.background_executor()
 6573                    .timer(std::time::Duration::from_millis(100))
 6574                    .await;
 6575                editor
 6576                    .update(cx, |editor, cx| {
 6577                        editor.inline_blame_popover.take();
 6578                        cx.notify();
 6579                    })
 6580                    .ok();
 6581            });
 6582            state.hide_task = Some(hide_task);
 6583        }
 6584    }
 6585
 6586    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6587        if self.pending_rename.is_some() {
 6588            return None;
 6589        }
 6590
 6591        let provider = self.semantics_provider.clone()?;
 6592        let buffer = self.buffer.read(cx);
 6593        let newest_selection = self.selections.newest_anchor().clone();
 6594        let cursor_position = newest_selection.head();
 6595        let (cursor_buffer, cursor_buffer_position) =
 6596            buffer.text_anchor_for_position(cursor_position, cx)?;
 6597        let (tail_buffer, tail_buffer_position) =
 6598            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6599        if cursor_buffer != tail_buffer {
 6600            return None;
 6601        }
 6602
 6603        let snapshot = cursor_buffer.read(cx).snapshot();
 6604        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6605        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6606        if start_word_range != end_word_range {
 6607            self.document_highlights_task.take();
 6608            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6609            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6610            return None;
 6611        }
 6612
 6613        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6614        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6615            cx.background_executor()
 6616                .timer(Duration::from_millis(debounce))
 6617                .await;
 6618
 6619            let highlights = if let Some(highlights) = cx
 6620                .update(|cx| {
 6621                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6622                })
 6623                .ok()
 6624                .flatten()
 6625            {
 6626                highlights.await.log_err()
 6627            } else {
 6628                None
 6629            };
 6630
 6631            if let Some(highlights) = highlights {
 6632                this.update(cx, |this, cx| {
 6633                    if this.pending_rename.is_some() {
 6634                        return;
 6635                    }
 6636
 6637                    let buffer_id = cursor_position.buffer_id;
 6638                    let buffer = this.buffer.read(cx);
 6639                    if !buffer
 6640                        .text_anchor_for_position(cursor_position, cx)
 6641                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6642                    {
 6643                        return;
 6644                    }
 6645
 6646                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6647                    let mut write_ranges = Vec::new();
 6648                    let mut read_ranges = Vec::new();
 6649                    for highlight in highlights {
 6650                        for (excerpt_id, excerpt_range) in
 6651                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6652                        {
 6653                            let start = highlight
 6654                                .range
 6655                                .start
 6656                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6657                            let end = highlight
 6658                                .range
 6659                                .end
 6660                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6661                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6662                                continue;
 6663                            }
 6664
 6665                            let range = Anchor {
 6666                                buffer_id,
 6667                                excerpt_id,
 6668                                text_anchor: start,
 6669                                diff_base_anchor: None,
 6670                            }..Anchor {
 6671                                buffer_id,
 6672                                excerpt_id,
 6673                                text_anchor: end,
 6674                                diff_base_anchor: None,
 6675                            };
 6676                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6677                                write_ranges.push(range);
 6678                            } else {
 6679                                read_ranges.push(range);
 6680                            }
 6681                        }
 6682                    }
 6683
 6684                    this.highlight_background::<DocumentHighlightRead>(
 6685                        &read_ranges,
 6686                        |theme| theme.colors().editor_document_highlight_read_background,
 6687                        cx,
 6688                    );
 6689                    this.highlight_background::<DocumentHighlightWrite>(
 6690                        &write_ranges,
 6691                        |theme| theme.colors().editor_document_highlight_write_background,
 6692                        cx,
 6693                    );
 6694                    cx.notify();
 6695                })
 6696                .log_err();
 6697            }
 6698        }));
 6699        None
 6700    }
 6701
 6702    fn prepare_highlight_query_from_selection(
 6703        &mut self,
 6704        cx: &mut Context<Editor>,
 6705    ) -> Option<(String, Range<Anchor>)> {
 6706        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6707            return None;
 6708        }
 6709        if !EditorSettings::get_global(cx).selection_highlight {
 6710            return None;
 6711        }
 6712        if self.selections.count() != 1 || self.selections.line_mode {
 6713            return None;
 6714        }
 6715        let selection = self.selections.newest::<Point>(cx);
 6716        if selection.is_empty() || selection.start.row != selection.end.row {
 6717            return None;
 6718        }
 6719        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6720        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6721        let query = multi_buffer_snapshot
 6722            .text_for_range(selection_anchor_range.clone())
 6723            .collect::<String>();
 6724        if query.trim().is_empty() {
 6725            return None;
 6726        }
 6727        Some((query, selection_anchor_range))
 6728    }
 6729
 6730    fn update_selection_occurrence_highlights(
 6731        &mut self,
 6732        query_text: String,
 6733        query_range: Range<Anchor>,
 6734        multi_buffer_range_to_query: Range<Point>,
 6735        use_debounce: bool,
 6736        window: &mut Window,
 6737        cx: &mut Context<Editor>,
 6738    ) -> Task<()> {
 6739        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6740        cx.spawn_in(window, async move |editor, cx| {
 6741            if use_debounce {
 6742                cx.background_executor()
 6743                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6744                    .await;
 6745            }
 6746            let match_task = cx.background_spawn(async move {
 6747                let buffer_ranges = multi_buffer_snapshot
 6748                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6749                    .into_iter()
 6750                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6751                let mut match_ranges = Vec::new();
 6752                let Ok(regex) = project::search::SearchQuery::text(
 6753                    query_text.clone(),
 6754                    false,
 6755                    false,
 6756                    false,
 6757                    Default::default(),
 6758                    Default::default(),
 6759                    false,
 6760                    None,
 6761                ) else {
 6762                    return Vec::default();
 6763                };
 6764                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6765                    match_ranges.extend(
 6766                        regex
 6767                            .search(&buffer_snapshot, Some(search_range.clone()))
 6768                            .await
 6769                            .into_iter()
 6770                            .filter_map(|match_range| {
 6771                                let match_start = buffer_snapshot
 6772                                    .anchor_after(search_range.start + match_range.start);
 6773                                let match_end = buffer_snapshot
 6774                                    .anchor_before(search_range.start + match_range.end);
 6775                                let match_anchor_range = Anchor::range_in_buffer(
 6776                                    excerpt_id,
 6777                                    buffer_snapshot.remote_id(),
 6778                                    match_start..match_end,
 6779                                );
 6780                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6781                            }),
 6782                    );
 6783                }
 6784                match_ranges
 6785            });
 6786            let match_ranges = match_task.await;
 6787            editor
 6788                .update_in(cx, |editor, _, cx| {
 6789                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6790                    if !match_ranges.is_empty() {
 6791                        editor.highlight_background::<SelectedTextHighlight>(
 6792                            &match_ranges,
 6793                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6794                            cx,
 6795                        )
 6796                    }
 6797                })
 6798                .log_err();
 6799        })
 6800    }
 6801
 6802    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6803        struct NewlineFold;
 6804        let type_id = std::any::TypeId::of::<NewlineFold>();
 6805        if !self.mode.is_single_line() {
 6806            return;
 6807        }
 6808        let snapshot = self.snapshot(window, cx);
 6809        if snapshot.buffer_snapshot.max_point().row == 0 {
 6810            return;
 6811        }
 6812        let task = cx.background_spawn(async move {
 6813            let new_newlines = snapshot
 6814                .buffer_chars_at(0)
 6815                .filter_map(|(c, i)| {
 6816                    if c == '\n' {
 6817                        Some(
 6818                            snapshot.buffer_snapshot.anchor_after(i)
 6819                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6820                        )
 6821                    } else {
 6822                        None
 6823                    }
 6824                })
 6825                .collect::<Vec<_>>();
 6826            let existing_newlines = snapshot
 6827                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6828                .filter_map(|fold| {
 6829                    if fold.placeholder.type_tag == Some(type_id) {
 6830                        Some(fold.range.start..fold.range.end)
 6831                    } else {
 6832                        None
 6833                    }
 6834                })
 6835                .collect::<Vec<_>>();
 6836
 6837            (new_newlines, existing_newlines)
 6838        });
 6839        self.folding_newlines = cx.spawn(async move |this, cx| {
 6840            let (new_newlines, existing_newlines) = task.await;
 6841            if new_newlines == existing_newlines {
 6842                return;
 6843            }
 6844            let placeholder = FoldPlaceholder {
 6845                render: Arc::new(move |_, _, cx| {
 6846                    div()
 6847                        .bg(cx.theme().status().hint_background)
 6848                        .border_b_1()
 6849                        .size_full()
 6850                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6851                        .border_color(cx.theme().status().hint)
 6852                        .child("\\n")
 6853                        .into_any()
 6854                }),
 6855                constrain_width: false,
 6856                merge_adjacent: false,
 6857                type_tag: Some(type_id),
 6858            };
 6859            let creases = new_newlines
 6860                .into_iter()
 6861                .map(|range| Crease::simple(range, placeholder.clone()))
 6862                .collect();
 6863            this.update(cx, |this, cx| {
 6864                this.display_map.update(cx, |display_map, cx| {
 6865                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6866                    display_map.fold(creases, cx);
 6867                });
 6868            })
 6869            .ok();
 6870        });
 6871    }
 6872
 6873    fn refresh_selected_text_highlights(
 6874        &mut self,
 6875        on_buffer_edit: bool,
 6876        window: &mut Window,
 6877        cx: &mut Context<Editor>,
 6878    ) {
 6879        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6880        else {
 6881            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6882            self.quick_selection_highlight_task.take();
 6883            self.debounced_selection_highlight_task.take();
 6884            return;
 6885        };
 6886        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6887        if on_buffer_edit
 6888            || self
 6889                .quick_selection_highlight_task
 6890                .as_ref()
 6891                .map_or(true, |(prev_anchor_range, _)| {
 6892                    prev_anchor_range != &query_range
 6893                })
 6894        {
 6895            let multi_buffer_visible_start = self
 6896                .scroll_manager
 6897                .anchor()
 6898                .anchor
 6899                .to_point(&multi_buffer_snapshot);
 6900            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6901                multi_buffer_visible_start
 6902                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6903                Bias::Left,
 6904            );
 6905            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6906            self.quick_selection_highlight_task = Some((
 6907                query_range.clone(),
 6908                self.update_selection_occurrence_highlights(
 6909                    query_text.clone(),
 6910                    query_range.clone(),
 6911                    multi_buffer_visible_range,
 6912                    false,
 6913                    window,
 6914                    cx,
 6915                ),
 6916            ));
 6917        }
 6918        if on_buffer_edit
 6919            || self
 6920                .debounced_selection_highlight_task
 6921                .as_ref()
 6922                .map_or(true, |(prev_anchor_range, _)| {
 6923                    prev_anchor_range != &query_range
 6924                })
 6925        {
 6926            let multi_buffer_start = multi_buffer_snapshot
 6927                .anchor_before(0)
 6928                .to_point(&multi_buffer_snapshot);
 6929            let multi_buffer_end = multi_buffer_snapshot
 6930                .anchor_after(multi_buffer_snapshot.len())
 6931                .to_point(&multi_buffer_snapshot);
 6932            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6933            self.debounced_selection_highlight_task = Some((
 6934                query_range.clone(),
 6935                self.update_selection_occurrence_highlights(
 6936                    query_text,
 6937                    query_range,
 6938                    multi_buffer_full_range,
 6939                    true,
 6940                    window,
 6941                    cx,
 6942                ),
 6943            ));
 6944        }
 6945    }
 6946
 6947    pub fn refresh_inline_completion(
 6948        &mut self,
 6949        debounce: bool,
 6950        user_requested: bool,
 6951        window: &mut Window,
 6952        cx: &mut Context<Self>,
 6953    ) -> Option<()> {
 6954        let provider = self.edit_prediction_provider()?;
 6955        let cursor = self.selections.newest_anchor().head();
 6956        let (buffer, cursor_buffer_position) =
 6957            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6958
 6959        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6960            self.discard_inline_completion(false, cx);
 6961            return None;
 6962        }
 6963
 6964        if !user_requested
 6965            && (!self.should_show_edit_predictions()
 6966                || !self.is_focused(window)
 6967                || buffer.read(cx).is_empty())
 6968        {
 6969            self.discard_inline_completion(false, cx);
 6970            return None;
 6971        }
 6972
 6973        self.update_visible_inline_completion(window, cx);
 6974        provider.refresh(
 6975            self.project.clone(),
 6976            buffer,
 6977            cursor_buffer_position,
 6978            debounce,
 6979            cx,
 6980        );
 6981        Some(())
 6982    }
 6983
 6984    fn show_edit_predictions_in_menu(&self) -> bool {
 6985        match self.edit_prediction_settings {
 6986            EditPredictionSettings::Disabled => false,
 6987            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6988        }
 6989    }
 6990
 6991    pub fn edit_predictions_enabled(&self) -> bool {
 6992        match self.edit_prediction_settings {
 6993            EditPredictionSettings::Disabled => false,
 6994            EditPredictionSettings::Enabled { .. } => true,
 6995        }
 6996    }
 6997
 6998    fn edit_prediction_requires_modifier(&self) -> bool {
 6999        match self.edit_prediction_settings {
 7000            EditPredictionSettings::Disabled => false,
 7001            EditPredictionSettings::Enabled {
 7002                preview_requires_modifier,
 7003                ..
 7004            } => preview_requires_modifier,
 7005        }
 7006    }
 7007
 7008    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7009        if self.edit_prediction_provider.is_none() {
 7010            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7011        } else {
 7012            let selection = self.selections.newest_anchor();
 7013            let cursor = selection.head();
 7014
 7015            if let Some((buffer, cursor_buffer_position)) =
 7016                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7017            {
 7018                self.edit_prediction_settings =
 7019                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7020            }
 7021        }
 7022    }
 7023
 7024    fn edit_prediction_settings_at_position(
 7025        &self,
 7026        buffer: &Entity<Buffer>,
 7027        buffer_position: language::Anchor,
 7028        cx: &App,
 7029    ) -> EditPredictionSettings {
 7030        if !self.mode.is_full()
 7031            || !self.show_inline_completions_override.unwrap_or(true)
 7032            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7033        {
 7034            return EditPredictionSettings::Disabled;
 7035        }
 7036
 7037        let buffer = buffer.read(cx);
 7038
 7039        let file = buffer.file();
 7040
 7041        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7042            return EditPredictionSettings::Disabled;
 7043        };
 7044
 7045        let by_provider = matches!(
 7046            self.menu_inline_completions_policy,
 7047            MenuInlineCompletionsPolicy::ByProvider
 7048        );
 7049
 7050        let show_in_menu = by_provider
 7051            && self
 7052                .edit_prediction_provider
 7053                .as_ref()
 7054                .map_or(false, |provider| {
 7055                    provider.provider.show_completions_in_menu()
 7056                });
 7057
 7058        let preview_requires_modifier =
 7059            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7060
 7061        EditPredictionSettings::Enabled {
 7062            show_in_menu,
 7063            preview_requires_modifier,
 7064        }
 7065    }
 7066
 7067    fn should_show_edit_predictions(&self) -> bool {
 7068        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7069    }
 7070
 7071    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7072        matches!(
 7073            self.edit_prediction_preview,
 7074            EditPredictionPreview::Active { .. }
 7075        )
 7076    }
 7077
 7078    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7079        let cursor = self.selections.newest_anchor().head();
 7080        if let Some((buffer, cursor_position)) =
 7081            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7082        {
 7083            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7084        } else {
 7085            false
 7086        }
 7087    }
 7088
 7089    pub fn supports_minimap(&self, cx: &App) -> bool {
 7090        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7091    }
 7092
 7093    fn edit_predictions_enabled_in_buffer(
 7094        &self,
 7095        buffer: &Entity<Buffer>,
 7096        buffer_position: language::Anchor,
 7097        cx: &App,
 7098    ) -> bool {
 7099        maybe!({
 7100            if self.read_only(cx) {
 7101                return Some(false);
 7102            }
 7103            let provider = self.edit_prediction_provider()?;
 7104            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7105                return Some(false);
 7106            }
 7107            let buffer = buffer.read(cx);
 7108            let Some(file) = buffer.file() else {
 7109                return Some(true);
 7110            };
 7111            let settings = all_language_settings(Some(file), cx);
 7112            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7113        })
 7114        .unwrap_or(false)
 7115    }
 7116
 7117    fn cycle_inline_completion(
 7118        &mut self,
 7119        direction: Direction,
 7120        window: &mut Window,
 7121        cx: &mut Context<Self>,
 7122    ) -> Option<()> {
 7123        let provider = self.edit_prediction_provider()?;
 7124        let cursor = self.selections.newest_anchor().head();
 7125        let (buffer, cursor_buffer_position) =
 7126            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7127        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7128            return None;
 7129        }
 7130
 7131        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7132        self.update_visible_inline_completion(window, cx);
 7133
 7134        Some(())
 7135    }
 7136
 7137    pub fn show_inline_completion(
 7138        &mut self,
 7139        _: &ShowEditPrediction,
 7140        window: &mut Window,
 7141        cx: &mut Context<Self>,
 7142    ) {
 7143        if !self.has_active_inline_completion() {
 7144            self.refresh_inline_completion(false, true, window, cx);
 7145            return;
 7146        }
 7147
 7148        self.update_visible_inline_completion(window, cx);
 7149    }
 7150
 7151    pub fn display_cursor_names(
 7152        &mut self,
 7153        _: &DisplayCursorNames,
 7154        window: &mut Window,
 7155        cx: &mut Context<Self>,
 7156    ) {
 7157        self.show_cursor_names(window, cx);
 7158    }
 7159
 7160    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7161        self.show_cursor_names = true;
 7162        cx.notify();
 7163        cx.spawn_in(window, async move |this, cx| {
 7164            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7165            this.update(cx, |this, cx| {
 7166                this.show_cursor_names = false;
 7167                cx.notify()
 7168            })
 7169            .ok()
 7170        })
 7171        .detach();
 7172    }
 7173
 7174    pub fn next_edit_prediction(
 7175        &mut self,
 7176        _: &NextEditPrediction,
 7177        window: &mut Window,
 7178        cx: &mut Context<Self>,
 7179    ) {
 7180        if self.has_active_inline_completion() {
 7181            self.cycle_inline_completion(Direction::Next, window, cx);
 7182        } else {
 7183            let is_copilot_disabled = self
 7184                .refresh_inline_completion(false, true, window, cx)
 7185                .is_none();
 7186            if is_copilot_disabled {
 7187                cx.propagate();
 7188            }
 7189        }
 7190    }
 7191
 7192    pub fn previous_edit_prediction(
 7193        &mut self,
 7194        _: &PreviousEditPrediction,
 7195        window: &mut Window,
 7196        cx: &mut Context<Self>,
 7197    ) {
 7198        if self.has_active_inline_completion() {
 7199            self.cycle_inline_completion(Direction::Prev, window, cx);
 7200        } else {
 7201            let is_copilot_disabled = self
 7202                .refresh_inline_completion(false, true, window, cx)
 7203                .is_none();
 7204            if is_copilot_disabled {
 7205                cx.propagate();
 7206            }
 7207        }
 7208    }
 7209
 7210    pub fn accept_edit_prediction(
 7211        &mut self,
 7212        _: &AcceptEditPrediction,
 7213        window: &mut Window,
 7214        cx: &mut Context<Self>,
 7215    ) {
 7216        if self.show_edit_predictions_in_menu() {
 7217            self.hide_context_menu(window, cx);
 7218        }
 7219
 7220        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7221            return;
 7222        };
 7223
 7224        self.report_inline_completion_event(
 7225            active_inline_completion.completion_id.clone(),
 7226            true,
 7227            cx,
 7228        );
 7229
 7230        match &active_inline_completion.completion {
 7231            InlineCompletion::Move { target, .. } => {
 7232                let target = *target;
 7233
 7234                if let Some(position_map) = &self.last_position_map {
 7235                    if position_map
 7236                        .visible_row_range
 7237                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7238                        || !self.edit_prediction_requires_modifier()
 7239                    {
 7240                        self.unfold_ranges(&[target..target], true, false, cx);
 7241                        // Note that this is also done in vim's handler of the Tab action.
 7242                        self.change_selections(
 7243                            SelectionEffects::scroll(Autoscroll::newest()),
 7244                            window,
 7245                            cx,
 7246                            |selections| {
 7247                                selections.select_anchor_ranges([target..target]);
 7248                            },
 7249                        );
 7250                        self.clear_row_highlights::<EditPredictionPreview>();
 7251
 7252                        self.edit_prediction_preview
 7253                            .set_previous_scroll_position(None);
 7254                    } else {
 7255                        self.edit_prediction_preview
 7256                            .set_previous_scroll_position(Some(
 7257                                position_map.snapshot.scroll_anchor,
 7258                            ));
 7259
 7260                        self.highlight_rows::<EditPredictionPreview>(
 7261                            target..target,
 7262                            cx.theme().colors().editor_highlighted_line_background,
 7263                            RowHighlightOptions {
 7264                                autoscroll: true,
 7265                                ..Default::default()
 7266                            },
 7267                            cx,
 7268                        );
 7269                        self.request_autoscroll(Autoscroll::fit(), cx);
 7270                    }
 7271                }
 7272            }
 7273            InlineCompletion::Edit { edits, .. } => {
 7274                if let Some(provider) = self.edit_prediction_provider() {
 7275                    provider.accept(cx);
 7276                }
 7277
 7278                // Store the transaction ID and selections before applying the edit
 7279                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7280
 7281                let snapshot = self.buffer.read(cx).snapshot(cx);
 7282                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7283
 7284                self.buffer.update(cx, |buffer, cx| {
 7285                    buffer.edit(edits.iter().cloned(), None, cx)
 7286                });
 7287
 7288                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7289                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7290                });
 7291
 7292                let selections = self.selections.disjoint_anchors();
 7293                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7294                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7295                    if has_new_transaction {
 7296                        self.selection_history
 7297                            .insert_transaction(transaction_id_now, selections);
 7298                    }
 7299                }
 7300
 7301                self.update_visible_inline_completion(window, cx);
 7302                if self.active_inline_completion.is_none() {
 7303                    self.refresh_inline_completion(true, true, window, cx);
 7304                }
 7305
 7306                cx.notify();
 7307            }
 7308        }
 7309
 7310        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7311    }
 7312
 7313    pub fn accept_partial_inline_completion(
 7314        &mut self,
 7315        _: &AcceptPartialEditPrediction,
 7316        window: &mut Window,
 7317        cx: &mut Context<Self>,
 7318    ) {
 7319        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7320            return;
 7321        };
 7322        if self.selections.count() != 1 {
 7323            return;
 7324        }
 7325
 7326        self.report_inline_completion_event(
 7327            active_inline_completion.completion_id.clone(),
 7328            true,
 7329            cx,
 7330        );
 7331
 7332        match &active_inline_completion.completion {
 7333            InlineCompletion::Move { target, .. } => {
 7334                let target = *target;
 7335                self.change_selections(
 7336                    SelectionEffects::scroll(Autoscroll::newest()),
 7337                    window,
 7338                    cx,
 7339                    |selections| {
 7340                        selections.select_anchor_ranges([target..target]);
 7341                    },
 7342                );
 7343            }
 7344            InlineCompletion::Edit { edits, .. } => {
 7345                // Find an insertion that starts at the cursor position.
 7346                let snapshot = self.buffer.read(cx).snapshot(cx);
 7347                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7348                let insertion = edits.iter().find_map(|(range, text)| {
 7349                    let range = range.to_offset(&snapshot);
 7350                    if range.is_empty() && range.start == cursor_offset {
 7351                        Some(text)
 7352                    } else {
 7353                        None
 7354                    }
 7355                });
 7356
 7357                if let Some(text) = insertion {
 7358                    let mut partial_completion = text
 7359                        .chars()
 7360                        .by_ref()
 7361                        .take_while(|c| c.is_alphabetic())
 7362                        .collect::<String>();
 7363                    if partial_completion.is_empty() {
 7364                        partial_completion = text
 7365                            .chars()
 7366                            .by_ref()
 7367                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7368                            .collect::<String>();
 7369                    }
 7370
 7371                    cx.emit(EditorEvent::InputHandled {
 7372                        utf16_range_to_replace: None,
 7373                        text: partial_completion.clone().into(),
 7374                    });
 7375
 7376                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7377
 7378                    self.refresh_inline_completion(true, true, window, cx);
 7379                    cx.notify();
 7380                } else {
 7381                    self.accept_edit_prediction(&Default::default(), window, cx);
 7382                }
 7383            }
 7384        }
 7385    }
 7386
 7387    fn discard_inline_completion(
 7388        &mut self,
 7389        should_report_inline_completion_event: bool,
 7390        cx: &mut Context<Self>,
 7391    ) -> bool {
 7392        if should_report_inline_completion_event {
 7393            let completion_id = self
 7394                .active_inline_completion
 7395                .as_ref()
 7396                .and_then(|active_completion| active_completion.completion_id.clone());
 7397
 7398            self.report_inline_completion_event(completion_id, false, cx);
 7399        }
 7400
 7401        if let Some(provider) = self.edit_prediction_provider() {
 7402            provider.discard(cx);
 7403        }
 7404
 7405        self.take_active_inline_completion(cx)
 7406    }
 7407
 7408    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7409        let Some(provider) = self.edit_prediction_provider() else {
 7410            return;
 7411        };
 7412
 7413        let Some((_, buffer, _)) = self
 7414            .buffer
 7415            .read(cx)
 7416            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7417        else {
 7418            return;
 7419        };
 7420
 7421        let extension = buffer
 7422            .read(cx)
 7423            .file()
 7424            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7425
 7426        let event_type = match accepted {
 7427            true => "Edit Prediction Accepted",
 7428            false => "Edit Prediction Discarded",
 7429        };
 7430        telemetry::event!(
 7431            event_type,
 7432            provider = provider.name(),
 7433            prediction_id = id,
 7434            suggestion_accepted = accepted,
 7435            file_extension = extension,
 7436        );
 7437    }
 7438
 7439    pub fn has_active_inline_completion(&self) -> bool {
 7440        self.active_inline_completion.is_some()
 7441    }
 7442
 7443    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7444        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7445            return false;
 7446        };
 7447
 7448        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7449        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7450        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7451        true
 7452    }
 7453
 7454    /// Returns true when we're displaying the edit prediction popover below the cursor
 7455    /// like we are not previewing and the LSP autocomplete menu is visible
 7456    /// or we are in `when_holding_modifier` mode.
 7457    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7458        if self.edit_prediction_preview_is_active()
 7459            || !self.show_edit_predictions_in_menu()
 7460            || !self.edit_predictions_enabled()
 7461        {
 7462            return false;
 7463        }
 7464
 7465        if self.has_visible_completions_menu() {
 7466            return true;
 7467        }
 7468
 7469        has_completion && self.edit_prediction_requires_modifier()
 7470    }
 7471
 7472    fn handle_modifiers_changed(
 7473        &mut self,
 7474        modifiers: Modifiers,
 7475        position_map: &PositionMap,
 7476        window: &mut Window,
 7477        cx: &mut Context<Self>,
 7478    ) {
 7479        if self.show_edit_predictions_in_menu() {
 7480            self.update_edit_prediction_preview(&modifiers, window, cx);
 7481        }
 7482
 7483        self.update_selection_mode(&modifiers, position_map, window, cx);
 7484
 7485        let mouse_position = window.mouse_position();
 7486        if !position_map.text_hitbox.is_hovered(window) {
 7487            return;
 7488        }
 7489
 7490        self.update_hovered_link(
 7491            position_map.point_for_position(mouse_position),
 7492            &position_map.snapshot,
 7493            modifiers,
 7494            window,
 7495            cx,
 7496        )
 7497    }
 7498
 7499    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7500        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7501        if invert {
 7502            match multi_cursor_setting {
 7503                MultiCursorModifier::Alt => modifiers.alt,
 7504                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7505            }
 7506        } else {
 7507            match multi_cursor_setting {
 7508                MultiCursorModifier::Alt => modifiers.secondary(),
 7509                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7510            }
 7511        }
 7512    }
 7513
 7514    fn columnar_selection_mode(
 7515        modifiers: &Modifiers,
 7516        cx: &mut Context<Self>,
 7517    ) -> Option<ColumnarMode> {
 7518        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7519            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7520                Some(ColumnarMode::FromMouse)
 7521            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7522                Some(ColumnarMode::FromSelection)
 7523            } else {
 7524                None
 7525            }
 7526        } else {
 7527            None
 7528        }
 7529    }
 7530
 7531    fn update_selection_mode(
 7532        &mut self,
 7533        modifiers: &Modifiers,
 7534        position_map: &PositionMap,
 7535        window: &mut Window,
 7536        cx: &mut Context<Self>,
 7537    ) {
 7538        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7539            return;
 7540        };
 7541        if self.selections.pending.is_none() {
 7542            return;
 7543        }
 7544
 7545        let mouse_position = window.mouse_position();
 7546        let point_for_position = position_map.point_for_position(mouse_position);
 7547        let position = point_for_position.previous_valid;
 7548
 7549        self.select(
 7550            SelectPhase::BeginColumnar {
 7551                position,
 7552                reset: false,
 7553                mode,
 7554                goal_column: point_for_position.exact_unclipped.column(),
 7555            },
 7556            window,
 7557            cx,
 7558        );
 7559    }
 7560
 7561    fn update_edit_prediction_preview(
 7562        &mut self,
 7563        modifiers: &Modifiers,
 7564        window: &mut Window,
 7565        cx: &mut Context<Self>,
 7566    ) {
 7567        let mut modifiers_held = false;
 7568        if let Some(accept_keystroke) = self
 7569            .accept_edit_prediction_keybind(false, window, cx)
 7570            .keystroke()
 7571        {
 7572            modifiers_held = modifiers_held
 7573                || (&accept_keystroke.modifiers == modifiers
 7574                    && accept_keystroke.modifiers.modified());
 7575        };
 7576        if let Some(accept_partial_keystroke) = self
 7577            .accept_edit_prediction_keybind(true, window, cx)
 7578            .keystroke()
 7579        {
 7580            modifiers_held = modifiers_held
 7581                || (&accept_partial_keystroke.modifiers == modifiers
 7582                    && accept_partial_keystroke.modifiers.modified());
 7583        }
 7584
 7585        if modifiers_held {
 7586            if matches!(
 7587                self.edit_prediction_preview,
 7588                EditPredictionPreview::Inactive { .. }
 7589            ) {
 7590                self.edit_prediction_preview = EditPredictionPreview::Active {
 7591                    previous_scroll_position: None,
 7592                    since: Instant::now(),
 7593                };
 7594
 7595                self.update_visible_inline_completion(window, cx);
 7596                cx.notify();
 7597            }
 7598        } else if let EditPredictionPreview::Active {
 7599            previous_scroll_position,
 7600            since,
 7601        } = self.edit_prediction_preview
 7602        {
 7603            if let (Some(previous_scroll_position), Some(position_map)) =
 7604                (previous_scroll_position, self.last_position_map.as_ref())
 7605            {
 7606                self.set_scroll_position(
 7607                    previous_scroll_position
 7608                        .scroll_position(&position_map.snapshot.display_snapshot),
 7609                    window,
 7610                    cx,
 7611                );
 7612            }
 7613
 7614            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7615                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7616            };
 7617            self.clear_row_highlights::<EditPredictionPreview>();
 7618            self.update_visible_inline_completion(window, cx);
 7619            cx.notify();
 7620        }
 7621    }
 7622
 7623    fn update_visible_inline_completion(
 7624        &mut self,
 7625        _window: &mut Window,
 7626        cx: &mut Context<Self>,
 7627    ) -> Option<()> {
 7628        let selection = self.selections.newest_anchor();
 7629        let cursor = selection.head();
 7630        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7631        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7632        let excerpt_id = cursor.excerpt_id;
 7633
 7634        let show_in_menu = self.show_edit_predictions_in_menu();
 7635        let completions_menu_has_precedence = !show_in_menu
 7636            && (self.context_menu.borrow().is_some()
 7637                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7638
 7639        if completions_menu_has_precedence
 7640            || !offset_selection.is_empty()
 7641            || self
 7642                .active_inline_completion
 7643                .as_ref()
 7644                .map_or(false, |completion| {
 7645                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7646                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7647                    !invalidation_range.contains(&offset_selection.head())
 7648                })
 7649        {
 7650            self.discard_inline_completion(false, cx);
 7651            return None;
 7652        }
 7653
 7654        self.take_active_inline_completion(cx);
 7655        let Some(provider) = self.edit_prediction_provider() else {
 7656            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7657            return None;
 7658        };
 7659
 7660        let (buffer, cursor_buffer_position) =
 7661            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7662
 7663        self.edit_prediction_settings =
 7664            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7665
 7666        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7667
 7668        if self.edit_prediction_indent_conflict {
 7669            let cursor_point = cursor.to_point(&multibuffer);
 7670
 7671            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7672
 7673            if let Some((_, indent)) = indents.iter().next() {
 7674                if indent.len == cursor_point.column {
 7675                    self.edit_prediction_indent_conflict = false;
 7676                }
 7677            }
 7678        }
 7679
 7680        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7681        let edits = inline_completion
 7682            .edits
 7683            .into_iter()
 7684            .flat_map(|(range, new_text)| {
 7685                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7686                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7687                Some((start..end, new_text))
 7688            })
 7689            .collect::<Vec<_>>();
 7690        if edits.is_empty() {
 7691            return None;
 7692        }
 7693
 7694        let first_edit_start = edits.first().unwrap().0.start;
 7695        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7696        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7697
 7698        let last_edit_end = edits.last().unwrap().0.end;
 7699        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7700        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7701
 7702        let cursor_row = cursor.to_point(&multibuffer).row;
 7703
 7704        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7705
 7706        let mut inlay_ids = Vec::new();
 7707        let invalidation_row_range;
 7708        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7709            Some(cursor_row..edit_end_row)
 7710        } else if cursor_row > edit_end_row {
 7711            Some(edit_start_row..cursor_row)
 7712        } else {
 7713            None
 7714        };
 7715        let is_move =
 7716            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7717        let completion = if is_move {
 7718            invalidation_row_range =
 7719                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7720            let target = first_edit_start;
 7721            InlineCompletion::Move { target, snapshot }
 7722        } else {
 7723            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7724                && !self.inline_completions_hidden_for_vim_mode;
 7725
 7726            if show_completions_in_buffer {
 7727                if edits
 7728                    .iter()
 7729                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7730                {
 7731                    let mut inlays = Vec::new();
 7732                    for (range, new_text) in &edits {
 7733                        let inlay = Inlay::inline_completion(
 7734                            post_inc(&mut self.next_inlay_id),
 7735                            range.start,
 7736                            new_text.as_str(),
 7737                        );
 7738                        inlay_ids.push(inlay.id);
 7739                        inlays.push(inlay);
 7740                    }
 7741
 7742                    self.splice_inlays(&[], inlays, cx);
 7743                } else {
 7744                    let background_color = cx.theme().status().deleted_background;
 7745                    self.highlight_text::<InlineCompletionHighlight>(
 7746                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7747                        HighlightStyle {
 7748                            background_color: Some(background_color),
 7749                            ..Default::default()
 7750                        },
 7751                        cx,
 7752                    );
 7753                }
 7754            }
 7755
 7756            invalidation_row_range = edit_start_row..edit_end_row;
 7757
 7758            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7759                if provider.show_tab_accept_marker() {
 7760                    EditDisplayMode::TabAccept
 7761                } else {
 7762                    EditDisplayMode::Inline
 7763                }
 7764            } else {
 7765                EditDisplayMode::DiffPopover
 7766            };
 7767
 7768            InlineCompletion::Edit {
 7769                edits,
 7770                edit_preview: inline_completion.edit_preview,
 7771                display_mode,
 7772                snapshot,
 7773            }
 7774        };
 7775
 7776        let invalidation_range = multibuffer
 7777            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7778            ..multibuffer.anchor_after(Point::new(
 7779                invalidation_row_range.end,
 7780                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7781            ));
 7782
 7783        self.stale_inline_completion_in_menu = None;
 7784        self.active_inline_completion = Some(InlineCompletionState {
 7785            inlay_ids,
 7786            completion,
 7787            completion_id: inline_completion.id,
 7788            invalidation_range,
 7789        });
 7790
 7791        cx.notify();
 7792
 7793        Some(())
 7794    }
 7795
 7796    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7797        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7798    }
 7799
 7800    fn clear_tasks(&mut self) {
 7801        self.tasks.clear()
 7802    }
 7803
 7804    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7805        if self.tasks.insert(key, value).is_some() {
 7806            // This case should hopefully be rare, but just in case...
 7807            log::error!(
 7808                "multiple different run targets found on a single line, only the last target will be rendered"
 7809            )
 7810        }
 7811    }
 7812
 7813    /// Get all display points of breakpoints that will be rendered within editor
 7814    ///
 7815    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7816    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7817    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7818    fn active_breakpoints(
 7819        &self,
 7820        range: Range<DisplayRow>,
 7821        window: &mut Window,
 7822        cx: &mut Context<Self>,
 7823    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7824        let mut breakpoint_display_points = HashMap::default();
 7825
 7826        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7827            return breakpoint_display_points;
 7828        };
 7829
 7830        let snapshot = self.snapshot(window, cx);
 7831
 7832        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7833        let Some(project) = self.project.as_ref() else {
 7834            return breakpoint_display_points;
 7835        };
 7836
 7837        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7838            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7839
 7840        for (buffer_snapshot, range, excerpt_id) in
 7841            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7842        {
 7843            let Some(buffer) = project
 7844                .read(cx)
 7845                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7846            else {
 7847                continue;
 7848            };
 7849            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7850                &buffer,
 7851                Some(
 7852                    buffer_snapshot.anchor_before(range.start)
 7853                        ..buffer_snapshot.anchor_after(range.end),
 7854                ),
 7855                buffer_snapshot,
 7856                cx,
 7857            );
 7858            for (breakpoint, state) in breakpoints {
 7859                let multi_buffer_anchor =
 7860                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7861                let position = multi_buffer_anchor
 7862                    .to_point(&multi_buffer_snapshot)
 7863                    .to_display_point(&snapshot);
 7864
 7865                breakpoint_display_points.insert(
 7866                    position.row(),
 7867                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7868                );
 7869            }
 7870        }
 7871
 7872        breakpoint_display_points
 7873    }
 7874
 7875    fn breakpoint_context_menu(
 7876        &self,
 7877        anchor: Anchor,
 7878        window: &mut Window,
 7879        cx: &mut Context<Self>,
 7880    ) -> Entity<ui::ContextMenu> {
 7881        let weak_editor = cx.weak_entity();
 7882        let focus_handle = self.focus_handle(cx);
 7883
 7884        let row = self
 7885            .buffer
 7886            .read(cx)
 7887            .snapshot(cx)
 7888            .summary_for_anchor::<Point>(&anchor)
 7889            .row;
 7890
 7891        let breakpoint = self
 7892            .breakpoint_at_row(row, window, cx)
 7893            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7894
 7895        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7896            "Edit Log Breakpoint"
 7897        } else {
 7898            "Set Log Breakpoint"
 7899        };
 7900
 7901        let condition_breakpoint_msg = if breakpoint
 7902            .as_ref()
 7903            .is_some_and(|bp| bp.1.condition.is_some())
 7904        {
 7905            "Edit Condition Breakpoint"
 7906        } else {
 7907            "Set Condition Breakpoint"
 7908        };
 7909
 7910        let hit_condition_breakpoint_msg = if breakpoint
 7911            .as_ref()
 7912            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7913        {
 7914            "Edit Hit Condition Breakpoint"
 7915        } else {
 7916            "Set Hit Condition Breakpoint"
 7917        };
 7918
 7919        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7920            "Unset Breakpoint"
 7921        } else {
 7922            "Set Breakpoint"
 7923        };
 7924
 7925        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7926
 7927        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7928            BreakpointState::Enabled => Some("Disable"),
 7929            BreakpointState::Disabled => Some("Enable"),
 7930        });
 7931
 7932        let (anchor, breakpoint) =
 7933            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7934
 7935        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7936            menu.on_blur_subscription(Subscription::new(|| {}))
 7937                .context(focus_handle)
 7938                .when(run_to_cursor, |this| {
 7939                    let weak_editor = weak_editor.clone();
 7940                    this.entry("Run to cursor", None, move |window, cx| {
 7941                        weak_editor
 7942                            .update(cx, |editor, cx| {
 7943                                editor.change_selections(
 7944                                    SelectionEffects::no_scroll(),
 7945                                    window,
 7946                                    cx,
 7947                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7948                                );
 7949                            })
 7950                            .ok();
 7951
 7952                        window.dispatch_action(Box::new(RunToCursor), cx);
 7953                    })
 7954                    .separator()
 7955                })
 7956                .when_some(toggle_state_msg, |this, msg| {
 7957                    this.entry(msg, None, {
 7958                        let weak_editor = weak_editor.clone();
 7959                        let breakpoint = breakpoint.clone();
 7960                        move |_window, cx| {
 7961                            weak_editor
 7962                                .update(cx, |this, cx| {
 7963                                    this.edit_breakpoint_at_anchor(
 7964                                        anchor,
 7965                                        breakpoint.as_ref().clone(),
 7966                                        BreakpointEditAction::InvertState,
 7967                                        cx,
 7968                                    );
 7969                                })
 7970                                .log_err();
 7971                        }
 7972                    })
 7973                })
 7974                .entry(set_breakpoint_msg, None, {
 7975                    let weak_editor = weak_editor.clone();
 7976                    let breakpoint = breakpoint.clone();
 7977                    move |_window, cx| {
 7978                        weak_editor
 7979                            .update(cx, |this, cx| {
 7980                                this.edit_breakpoint_at_anchor(
 7981                                    anchor,
 7982                                    breakpoint.as_ref().clone(),
 7983                                    BreakpointEditAction::Toggle,
 7984                                    cx,
 7985                                );
 7986                            })
 7987                            .log_err();
 7988                    }
 7989                })
 7990                .entry(log_breakpoint_msg, None, {
 7991                    let breakpoint = breakpoint.clone();
 7992                    let weak_editor = weak_editor.clone();
 7993                    move |window, cx| {
 7994                        weak_editor
 7995                            .update(cx, |this, cx| {
 7996                                this.add_edit_breakpoint_block(
 7997                                    anchor,
 7998                                    breakpoint.as_ref(),
 7999                                    BreakpointPromptEditAction::Log,
 8000                                    window,
 8001                                    cx,
 8002                                );
 8003                            })
 8004                            .log_err();
 8005                    }
 8006                })
 8007                .entry(condition_breakpoint_msg, None, {
 8008                    let breakpoint = breakpoint.clone();
 8009                    let weak_editor = weak_editor.clone();
 8010                    move |window, cx| {
 8011                        weak_editor
 8012                            .update(cx, |this, cx| {
 8013                                this.add_edit_breakpoint_block(
 8014                                    anchor,
 8015                                    breakpoint.as_ref(),
 8016                                    BreakpointPromptEditAction::Condition,
 8017                                    window,
 8018                                    cx,
 8019                                );
 8020                            })
 8021                            .log_err();
 8022                    }
 8023                })
 8024                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8025                    weak_editor
 8026                        .update(cx, |this, cx| {
 8027                            this.add_edit_breakpoint_block(
 8028                                anchor,
 8029                                breakpoint.as_ref(),
 8030                                BreakpointPromptEditAction::HitCondition,
 8031                                window,
 8032                                cx,
 8033                            );
 8034                        })
 8035                        .log_err();
 8036                })
 8037        })
 8038    }
 8039
 8040    fn render_breakpoint(
 8041        &self,
 8042        position: Anchor,
 8043        row: DisplayRow,
 8044        breakpoint: &Breakpoint,
 8045        state: Option<BreakpointSessionState>,
 8046        cx: &mut Context<Self>,
 8047    ) -> IconButton {
 8048        let is_rejected = state.is_some_and(|s| !s.verified);
 8049        // Is it a breakpoint that shows up when hovering over gutter?
 8050        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8051            (false, false),
 8052            |PhantomBreakpointIndicator {
 8053                 is_active,
 8054                 display_row,
 8055                 collides_with_existing_breakpoint,
 8056             }| {
 8057                (
 8058                    is_active && display_row == row,
 8059                    collides_with_existing_breakpoint,
 8060                )
 8061            },
 8062        );
 8063
 8064        let (color, icon) = {
 8065            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8066                (false, false) => ui::IconName::DebugBreakpoint,
 8067                (true, false) => ui::IconName::DebugLogBreakpoint,
 8068                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8069                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8070            };
 8071
 8072            let color = if is_phantom {
 8073                Color::Hint
 8074            } else if is_rejected {
 8075                Color::Disabled
 8076            } else {
 8077                Color::Debugger
 8078            };
 8079
 8080            (color, icon)
 8081        };
 8082
 8083        let breakpoint = Arc::from(breakpoint.clone());
 8084
 8085        let alt_as_text = gpui::Keystroke {
 8086            modifiers: Modifiers::secondary_key(),
 8087            ..Default::default()
 8088        };
 8089        let primary_action_text = if breakpoint.is_disabled() {
 8090            "Enable breakpoint"
 8091        } else if is_phantom && !collides_with_existing {
 8092            "Set breakpoint"
 8093        } else {
 8094            "Unset breakpoint"
 8095        };
 8096        let focus_handle = self.focus_handle.clone();
 8097
 8098        let meta = if is_rejected {
 8099            SharedString::from("No executable code is associated with this line.")
 8100        } else if collides_with_existing && !breakpoint.is_disabled() {
 8101            SharedString::from(format!(
 8102                "{alt_as_text}-click to disable,\nright-click for more options."
 8103            ))
 8104        } else {
 8105            SharedString::from("Right-click for more options.")
 8106        };
 8107        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8108            .icon_size(IconSize::XSmall)
 8109            .size(ui::ButtonSize::None)
 8110            .when(is_rejected, |this| {
 8111                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8112            })
 8113            .icon_color(color)
 8114            .style(ButtonStyle::Transparent)
 8115            .on_click(cx.listener({
 8116                let breakpoint = breakpoint.clone();
 8117
 8118                move |editor, event: &ClickEvent, window, cx| {
 8119                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8120                        BreakpointEditAction::InvertState
 8121                    } else {
 8122                        BreakpointEditAction::Toggle
 8123                    };
 8124
 8125                    window.focus(&editor.focus_handle(cx));
 8126                    editor.edit_breakpoint_at_anchor(
 8127                        position,
 8128                        breakpoint.as_ref().clone(),
 8129                        edit_action,
 8130                        cx,
 8131                    );
 8132                }
 8133            }))
 8134            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8135                editor.set_breakpoint_context_menu(
 8136                    row,
 8137                    Some(position),
 8138                    event.down.position,
 8139                    window,
 8140                    cx,
 8141                );
 8142            }))
 8143            .tooltip(move |window, cx| {
 8144                Tooltip::with_meta_in(
 8145                    primary_action_text,
 8146                    Some(&ToggleBreakpoint),
 8147                    meta.clone(),
 8148                    &focus_handle,
 8149                    window,
 8150                    cx,
 8151                )
 8152            })
 8153    }
 8154
 8155    fn build_tasks_context(
 8156        project: &Entity<Project>,
 8157        buffer: &Entity<Buffer>,
 8158        buffer_row: u32,
 8159        tasks: &Arc<RunnableTasks>,
 8160        cx: &mut Context<Self>,
 8161    ) -> Task<Option<task::TaskContext>> {
 8162        let position = Point::new(buffer_row, tasks.column);
 8163        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8164        let location = Location {
 8165            buffer: buffer.clone(),
 8166            range: range_start..range_start,
 8167        };
 8168        // Fill in the environmental variables from the tree-sitter captures
 8169        let mut captured_task_variables = TaskVariables::default();
 8170        for (capture_name, value) in tasks.extra_variables.clone() {
 8171            captured_task_variables.insert(
 8172                task::VariableName::Custom(capture_name.into()),
 8173                value.clone(),
 8174            );
 8175        }
 8176        project.update(cx, |project, cx| {
 8177            project.task_store().update(cx, |task_store, cx| {
 8178                task_store.task_context_for_location(captured_task_variables, location, cx)
 8179            })
 8180        })
 8181    }
 8182
 8183    pub fn spawn_nearest_task(
 8184        &mut self,
 8185        action: &SpawnNearestTask,
 8186        window: &mut Window,
 8187        cx: &mut Context<Self>,
 8188    ) {
 8189        let Some((workspace, _)) = self.workspace.clone() else {
 8190            return;
 8191        };
 8192        let Some(project) = self.project.clone() else {
 8193            return;
 8194        };
 8195
 8196        // Try to find a closest, enclosing node using tree-sitter that has a
 8197        // task
 8198        let Some((buffer, buffer_row, tasks)) = self
 8199            .find_enclosing_node_task(cx)
 8200            // Or find the task that's closest in row-distance.
 8201            .or_else(|| self.find_closest_task(cx))
 8202        else {
 8203            return;
 8204        };
 8205
 8206        let reveal_strategy = action.reveal;
 8207        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8208        cx.spawn_in(window, async move |_, cx| {
 8209            let context = task_context.await?;
 8210            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8211
 8212            let resolved = &mut resolved_task.resolved;
 8213            resolved.reveal = reveal_strategy;
 8214
 8215            workspace
 8216                .update_in(cx, |workspace, window, cx| {
 8217                    workspace.schedule_resolved_task(
 8218                        task_source_kind,
 8219                        resolved_task,
 8220                        false,
 8221                        window,
 8222                        cx,
 8223                    );
 8224                })
 8225                .ok()
 8226        })
 8227        .detach();
 8228    }
 8229
 8230    fn find_closest_task(
 8231        &mut self,
 8232        cx: &mut Context<Self>,
 8233    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8234        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8235
 8236        let ((buffer_id, row), tasks) = self
 8237            .tasks
 8238            .iter()
 8239            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8240
 8241        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8242        let tasks = Arc::new(tasks.to_owned());
 8243        Some((buffer, *row, tasks))
 8244    }
 8245
 8246    fn find_enclosing_node_task(
 8247        &mut self,
 8248        cx: &mut Context<Self>,
 8249    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8250        let snapshot = self.buffer.read(cx).snapshot(cx);
 8251        let offset = self.selections.newest::<usize>(cx).head();
 8252        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8253        let buffer_id = excerpt.buffer().remote_id();
 8254
 8255        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8256        let mut cursor = layer.node().walk();
 8257
 8258        while cursor.goto_first_child_for_byte(offset).is_some() {
 8259            if cursor.node().end_byte() == offset {
 8260                cursor.goto_next_sibling();
 8261            }
 8262        }
 8263
 8264        // Ascend to the smallest ancestor that contains the range and has a task.
 8265        loop {
 8266            let node = cursor.node();
 8267            let node_range = node.byte_range();
 8268            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8269
 8270            // Check if this node contains our offset
 8271            if node_range.start <= offset && node_range.end >= offset {
 8272                // If it contains offset, check for task
 8273                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8274                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8275                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8276                }
 8277            }
 8278
 8279            if !cursor.goto_parent() {
 8280                break;
 8281            }
 8282        }
 8283        None
 8284    }
 8285
 8286    fn render_run_indicator(
 8287        &self,
 8288        _style: &EditorStyle,
 8289        is_active: bool,
 8290        row: DisplayRow,
 8291        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8292        cx: &mut Context<Self>,
 8293    ) -> IconButton {
 8294        let color = Color::Muted;
 8295        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8296
 8297        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8298            .shape(ui::IconButtonShape::Square)
 8299            .icon_size(IconSize::XSmall)
 8300            .icon_color(color)
 8301            .toggle_state(is_active)
 8302            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8303                let quick_launch = e.down.button == MouseButton::Left;
 8304                window.focus(&editor.focus_handle(cx));
 8305                editor.toggle_code_actions(
 8306                    &ToggleCodeActions {
 8307                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8308                        quick_launch,
 8309                    },
 8310                    window,
 8311                    cx,
 8312                );
 8313            }))
 8314            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8315                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8316            }))
 8317    }
 8318
 8319    pub fn context_menu_visible(&self) -> bool {
 8320        !self.edit_prediction_preview_is_active()
 8321            && self
 8322                .context_menu
 8323                .borrow()
 8324                .as_ref()
 8325                .map_or(false, |menu| menu.visible())
 8326    }
 8327
 8328    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8329        self.context_menu
 8330            .borrow()
 8331            .as_ref()
 8332            .map(|menu| menu.origin())
 8333    }
 8334
 8335    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8336        self.context_menu_options = Some(options);
 8337    }
 8338
 8339    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8340    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8341
 8342    fn render_edit_prediction_popover(
 8343        &mut self,
 8344        text_bounds: &Bounds<Pixels>,
 8345        content_origin: gpui::Point<Pixels>,
 8346        right_margin: Pixels,
 8347        editor_snapshot: &EditorSnapshot,
 8348        visible_row_range: Range<DisplayRow>,
 8349        scroll_top: f32,
 8350        scroll_bottom: f32,
 8351        line_layouts: &[LineWithInvisibles],
 8352        line_height: Pixels,
 8353        scroll_pixel_position: gpui::Point<Pixels>,
 8354        newest_selection_head: Option<DisplayPoint>,
 8355        editor_width: Pixels,
 8356        style: &EditorStyle,
 8357        window: &mut Window,
 8358        cx: &mut App,
 8359    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8360        if self.mode().is_minimap() {
 8361            return None;
 8362        }
 8363        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8364
 8365        if self.edit_prediction_visible_in_cursor_popover(true) {
 8366            return None;
 8367        }
 8368
 8369        match &active_inline_completion.completion {
 8370            InlineCompletion::Move { target, .. } => {
 8371                let target_display_point = target.to_display_point(editor_snapshot);
 8372
 8373                if self.edit_prediction_requires_modifier() {
 8374                    if !self.edit_prediction_preview_is_active() {
 8375                        return None;
 8376                    }
 8377
 8378                    self.render_edit_prediction_modifier_jump_popover(
 8379                        text_bounds,
 8380                        content_origin,
 8381                        visible_row_range,
 8382                        line_layouts,
 8383                        line_height,
 8384                        scroll_pixel_position,
 8385                        newest_selection_head,
 8386                        target_display_point,
 8387                        window,
 8388                        cx,
 8389                    )
 8390                } else {
 8391                    self.render_edit_prediction_eager_jump_popover(
 8392                        text_bounds,
 8393                        content_origin,
 8394                        editor_snapshot,
 8395                        visible_row_range,
 8396                        scroll_top,
 8397                        scroll_bottom,
 8398                        line_height,
 8399                        scroll_pixel_position,
 8400                        target_display_point,
 8401                        editor_width,
 8402                        window,
 8403                        cx,
 8404                    )
 8405                }
 8406            }
 8407            InlineCompletion::Edit {
 8408                display_mode: EditDisplayMode::Inline,
 8409                ..
 8410            } => None,
 8411            InlineCompletion::Edit {
 8412                display_mode: EditDisplayMode::TabAccept,
 8413                edits,
 8414                ..
 8415            } => {
 8416                let range = &edits.first()?.0;
 8417                let target_display_point = range.end.to_display_point(editor_snapshot);
 8418
 8419                self.render_edit_prediction_end_of_line_popover(
 8420                    "Accept",
 8421                    editor_snapshot,
 8422                    visible_row_range,
 8423                    target_display_point,
 8424                    line_height,
 8425                    scroll_pixel_position,
 8426                    content_origin,
 8427                    editor_width,
 8428                    window,
 8429                    cx,
 8430                )
 8431            }
 8432            InlineCompletion::Edit {
 8433                edits,
 8434                edit_preview,
 8435                display_mode: EditDisplayMode::DiffPopover,
 8436                snapshot,
 8437            } => self.render_edit_prediction_diff_popover(
 8438                text_bounds,
 8439                content_origin,
 8440                right_margin,
 8441                editor_snapshot,
 8442                visible_row_range,
 8443                line_layouts,
 8444                line_height,
 8445                scroll_pixel_position,
 8446                newest_selection_head,
 8447                editor_width,
 8448                style,
 8449                edits,
 8450                edit_preview,
 8451                snapshot,
 8452                window,
 8453                cx,
 8454            ),
 8455        }
 8456    }
 8457
 8458    fn render_edit_prediction_modifier_jump_popover(
 8459        &mut self,
 8460        text_bounds: &Bounds<Pixels>,
 8461        content_origin: gpui::Point<Pixels>,
 8462        visible_row_range: Range<DisplayRow>,
 8463        line_layouts: &[LineWithInvisibles],
 8464        line_height: Pixels,
 8465        scroll_pixel_position: gpui::Point<Pixels>,
 8466        newest_selection_head: Option<DisplayPoint>,
 8467        target_display_point: DisplayPoint,
 8468        window: &mut Window,
 8469        cx: &mut App,
 8470    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8471        let scrolled_content_origin =
 8472            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8473
 8474        const SCROLL_PADDING_Y: Pixels = px(12.);
 8475
 8476        if target_display_point.row() < visible_row_range.start {
 8477            return self.render_edit_prediction_scroll_popover(
 8478                |_| SCROLL_PADDING_Y,
 8479                IconName::ArrowUp,
 8480                visible_row_range,
 8481                line_layouts,
 8482                newest_selection_head,
 8483                scrolled_content_origin,
 8484                window,
 8485                cx,
 8486            );
 8487        } else if target_display_point.row() >= visible_row_range.end {
 8488            return self.render_edit_prediction_scroll_popover(
 8489                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8490                IconName::ArrowDown,
 8491                visible_row_range,
 8492                line_layouts,
 8493                newest_selection_head,
 8494                scrolled_content_origin,
 8495                window,
 8496                cx,
 8497            );
 8498        }
 8499
 8500        const POLE_WIDTH: Pixels = px(2.);
 8501
 8502        let line_layout =
 8503            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8504        let target_column = target_display_point.column() as usize;
 8505
 8506        let target_x = line_layout.x_for_index(target_column);
 8507        let target_y =
 8508            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8509
 8510        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8511
 8512        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8513        border_color.l += 0.001;
 8514
 8515        let mut element = v_flex()
 8516            .items_end()
 8517            .when(flag_on_right, |el| el.items_start())
 8518            .child(if flag_on_right {
 8519                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8520                    .rounded_bl(px(0.))
 8521                    .rounded_tl(px(0.))
 8522                    .border_l_2()
 8523                    .border_color(border_color)
 8524            } else {
 8525                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8526                    .rounded_br(px(0.))
 8527                    .rounded_tr(px(0.))
 8528                    .border_r_2()
 8529                    .border_color(border_color)
 8530            })
 8531            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8532            .into_any();
 8533
 8534        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8535
 8536        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8537            - point(
 8538                if flag_on_right {
 8539                    POLE_WIDTH
 8540                } else {
 8541                    size.width - POLE_WIDTH
 8542                },
 8543                size.height - line_height,
 8544            );
 8545
 8546        origin.x = origin.x.max(content_origin.x);
 8547
 8548        element.prepaint_at(origin, window, cx);
 8549
 8550        Some((element, origin))
 8551    }
 8552
 8553    fn render_edit_prediction_scroll_popover(
 8554        &mut self,
 8555        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8556        scroll_icon: IconName,
 8557        visible_row_range: Range<DisplayRow>,
 8558        line_layouts: &[LineWithInvisibles],
 8559        newest_selection_head: Option<DisplayPoint>,
 8560        scrolled_content_origin: gpui::Point<Pixels>,
 8561        window: &mut Window,
 8562        cx: &mut App,
 8563    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8564        let mut element = self
 8565            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8566            .into_any();
 8567
 8568        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8569
 8570        let cursor = newest_selection_head?;
 8571        let cursor_row_layout =
 8572            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8573        let cursor_column = cursor.column() as usize;
 8574
 8575        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8576
 8577        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8578
 8579        element.prepaint_at(origin, window, cx);
 8580        Some((element, origin))
 8581    }
 8582
 8583    fn render_edit_prediction_eager_jump_popover(
 8584        &mut self,
 8585        text_bounds: &Bounds<Pixels>,
 8586        content_origin: gpui::Point<Pixels>,
 8587        editor_snapshot: &EditorSnapshot,
 8588        visible_row_range: Range<DisplayRow>,
 8589        scroll_top: f32,
 8590        scroll_bottom: f32,
 8591        line_height: Pixels,
 8592        scroll_pixel_position: gpui::Point<Pixels>,
 8593        target_display_point: DisplayPoint,
 8594        editor_width: Pixels,
 8595        window: &mut Window,
 8596        cx: &mut App,
 8597    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8598        if target_display_point.row().as_f32() < scroll_top {
 8599            let mut element = self
 8600                .render_edit_prediction_line_popover(
 8601                    "Jump to Edit",
 8602                    Some(IconName::ArrowUp),
 8603                    window,
 8604                    cx,
 8605                )?
 8606                .into_any();
 8607
 8608            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8609            let offset = point(
 8610                (text_bounds.size.width - size.width) / 2.,
 8611                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8612            );
 8613
 8614            let origin = text_bounds.origin + offset;
 8615            element.prepaint_at(origin, window, cx);
 8616            Some((element, origin))
 8617        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8618            let mut element = self
 8619                .render_edit_prediction_line_popover(
 8620                    "Jump to Edit",
 8621                    Some(IconName::ArrowDown),
 8622                    window,
 8623                    cx,
 8624                )?
 8625                .into_any();
 8626
 8627            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8628            let offset = point(
 8629                (text_bounds.size.width - size.width) / 2.,
 8630                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8631            );
 8632
 8633            let origin = text_bounds.origin + offset;
 8634            element.prepaint_at(origin, window, cx);
 8635            Some((element, origin))
 8636        } else {
 8637            self.render_edit_prediction_end_of_line_popover(
 8638                "Jump to Edit",
 8639                editor_snapshot,
 8640                visible_row_range,
 8641                target_display_point,
 8642                line_height,
 8643                scroll_pixel_position,
 8644                content_origin,
 8645                editor_width,
 8646                window,
 8647                cx,
 8648            )
 8649        }
 8650    }
 8651
 8652    fn render_edit_prediction_end_of_line_popover(
 8653        self: &mut Editor,
 8654        label: &'static str,
 8655        editor_snapshot: &EditorSnapshot,
 8656        visible_row_range: Range<DisplayRow>,
 8657        target_display_point: DisplayPoint,
 8658        line_height: Pixels,
 8659        scroll_pixel_position: gpui::Point<Pixels>,
 8660        content_origin: gpui::Point<Pixels>,
 8661        editor_width: Pixels,
 8662        window: &mut Window,
 8663        cx: &mut App,
 8664    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8665        let target_line_end = DisplayPoint::new(
 8666            target_display_point.row(),
 8667            editor_snapshot.line_len(target_display_point.row()),
 8668        );
 8669
 8670        let mut element = self
 8671            .render_edit_prediction_line_popover(label, None, window, cx)?
 8672            .into_any();
 8673
 8674        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8675
 8676        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8677
 8678        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8679        let mut origin = start_point
 8680            + line_origin
 8681            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8682        origin.x = origin.x.max(content_origin.x);
 8683
 8684        let max_x = content_origin.x + editor_width - size.width;
 8685
 8686        if origin.x > max_x {
 8687            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8688
 8689            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8690                origin.y += offset;
 8691                IconName::ArrowUp
 8692            } else {
 8693                origin.y -= offset;
 8694                IconName::ArrowDown
 8695            };
 8696
 8697            element = self
 8698                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8699                .into_any();
 8700
 8701            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8702
 8703            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8704        }
 8705
 8706        element.prepaint_at(origin, window, cx);
 8707        Some((element, origin))
 8708    }
 8709
 8710    fn render_edit_prediction_diff_popover(
 8711        self: &Editor,
 8712        text_bounds: &Bounds<Pixels>,
 8713        content_origin: gpui::Point<Pixels>,
 8714        right_margin: Pixels,
 8715        editor_snapshot: &EditorSnapshot,
 8716        visible_row_range: Range<DisplayRow>,
 8717        line_layouts: &[LineWithInvisibles],
 8718        line_height: Pixels,
 8719        scroll_pixel_position: gpui::Point<Pixels>,
 8720        newest_selection_head: Option<DisplayPoint>,
 8721        editor_width: Pixels,
 8722        style: &EditorStyle,
 8723        edits: &Vec<(Range<Anchor>, String)>,
 8724        edit_preview: &Option<language::EditPreview>,
 8725        snapshot: &language::BufferSnapshot,
 8726        window: &mut Window,
 8727        cx: &mut App,
 8728    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8729        let edit_start = edits
 8730            .first()
 8731            .unwrap()
 8732            .0
 8733            .start
 8734            .to_display_point(editor_snapshot);
 8735        let edit_end = edits
 8736            .last()
 8737            .unwrap()
 8738            .0
 8739            .end
 8740            .to_display_point(editor_snapshot);
 8741
 8742        let is_visible = visible_row_range.contains(&edit_start.row())
 8743            || visible_row_range.contains(&edit_end.row());
 8744        if !is_visible {
 8745            return None;
 8746        }
 8747
 8748        let highlighted_edits =
 8749            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8750
 8751        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8752        let line_count = highlighted_edits.text.lines().count();
 8753
 8754        const BORDER_WIDTH: Pixels = px(1.);
 8755
 8756        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8757        let has_keybind = keybind.is_some();
 8758
 8759        let mut element = h_flex()
 8760            .items_start()
 8761            .child(
 8762                h_flex()
 8763                    .bg(cx.theme().colors().editor_background)
 8764                    .border(BORDER_WIDTH)
 8765                    .shadow_xs()
 8766                    .border_color(cx.theme().colors().border)
 8767                    .rounded_l_lg()
 8768                    .when(line_count > 1, |el| el.rounded_br_lg())
 8769                    .pr_1()
 8770                    .child(styled_text),
 8771            )
 8772            .child(
 8773                h_flex()
 8774                    .h(line_height + BORDER_WIDTH * 2.)
 8775                    .px_1p5()
 8776                    .gap_1()
 8777                    // Workaround: For some reason, there's a gap if we don't do this
 8778                    .ml(-BORDER_WIDTH)
 8779                    .shadow(vec![gpui::BoxShadow {
 8780                        color: gpui::black().opacity(0.05),
 8781                        offset: point(px(1.), px(1.)),
 8782                        blur_radius: px(2.),
 8783                        spread_radius: px(0.),
 8784                    }])
 8785                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8786                    .border(BORDER_WIDTH)
 8787                    .border_color(cx.theme().colors().border)
 8788                    .rounded_r_lg()
 8789                    .id("edit_prediction_diff_popover_keybind")
 8790                    .when(!has_keybind, |el| {
 8791                        let status_colors = cx.theme().status();
 8792
 8793                        el.bg(status_colors.error_background)
 8794                            .border_color(status_colors.error.opacity(0.6))
 8795                            .child(Icon::new(IconName::Info).color(Color::Error))
 8796                            .cursor_default()
 8797                            .hoverable_tooltip(move |_window, cx| {
 8798                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8799                            })
 8800                    })
 8801                    .children(keybind),
 8802            )
 8803            .into_any();
 8804
 8805        let longest_row =
 8806            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8807        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8808            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8809        } else {
 8810            layout_line(
 8811                longest_row,
 8812                editor_snapshot,
 8813                style,
 8814                editor_width,
 8815                |_| false,
 8816                window,
 8817                cx,
 8818            )
 8819            .width
 8820        };
 8821
 8822        let viewport_bounds =
 8823            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8824                right: -right_margin,
 8825                ..Default::default()
 8826            });
 8827
 8828        let x_after_longest =
 8829            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8830                - scroll_pixel_position.x;
 8831
 8832        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8833
 8834        // Fully visible if it can be displayed within the window (allow overlapping other
 8835        // panes). However, this is only allowed if the popover starts within text_bounds.
 8836        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8837            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8838
 8839        let mut origin = if can_position_to_the_right {
 8840            point(
 8841                x_after_longest,
 8842                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8843                    - scroll_pixel_position.y,
 8844            )
 8845        } else {
 8846            let cursor_row = newest_selection_head.map(|head| head.row());
 8847            let above_edit = edit_start
 8848                .row()
 8849                .0
 8850                .checked_sub(line_count as u32)
 8851                .map(DisplayRow);
 8852            let below_edit = Some(edit_end.row() + 1);
 8853            let above_cursor =
 8854                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8855            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8856
 8857            // Place the edit popover adjacent to the edit if there is a location
 8858            // available that is onscreen and does not obscure the cursor. Otherwise,
 8859            // place it adjacent to the cursor.
 8860            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8861                .into_iter()
 8862                .flatten()
 8863                .find(|&start_row| {
 8864                    let end_row = start_row + line_count as u32;
 8865                    visible_row_range.contains(&start_row)
 8866                        && visible_row_range.contains(&end_row)
 8867                        && cursor_row.map_or(true, |cursor_row| {
 8868                            !((start_row..end_row).contains(&cursor_row))
 8869                        })
 8870                })?;
 8871
 8872            content_origin
 8873                + point(
 8874                    -scroll_pixel_position.x,
 8875                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8876                )
 8877        };
 8878
 8879        origin.x -= BORDER_WIDTH;
 8880
 8881        window.defer_draw(element, origin, 1);
 8882
 8883        // Do not return an element, since it will already be drawn due to defer_draw.
 8884        None
 8885    }
 8886
 8887    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8888        px(30.)
 8889    }
 8890
 8891    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8892        if self.read_only(cx) {
 8893            cx.theme().players().read_only()
 8894        } else {
 8895            self.style.as_ref().unwrap().local_player
 8896        }
 8897    }
 8898
 8899    fn render_edit_prediction_accept_keybind(
 8900        &self,
 8901        window: &mut Window,
 8902        cx: &App,
 8903    ) -> Option<AnyElement> {
 8904        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8905        let accept_keystroke = accept_binding.keystroke()?;
 8906
 8907        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8908
 8909        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8910            Color::Accent
 8911        } else {
 8912            Color::Muted
 8913        };
 8914
 8915        h_flex()
 8916            .px_0p5()
 8917            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8918            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8919            .text_size(TextSize::XSmall.rems(cx))
 8920            .child(h_flex().children(ui::render_modifiers(
 8921                &accept_keystroke.modifiers,
 8922                PlatformStyle::platform(),
 8923                Some(modifiers_color),
 8924                Some(IconSize::XSmall.rems().into()),
 8925                true,
 8926            )))
 8927            .when(is_platform_style_mac, |parent| {
 8928                parent.child(accept_keystroke.key.clone())
 8929            })
 8930            .when(!is_platform_style_mac, |parent| {
 8931                parent.child(
 8932                    Key::new(
 8933                        util::capitalize(&accept_keystroke.key),
 8934                        Some(Color::Default),
 8935                    )
 8936                    .size(Some(IconSize::XSmall.rems().into())),
 8937                )
 8938            })
 8939            .into_any()
 8940            .into()
 8941    }
 8942
 8943    fn render_edit_prediction_line_popover(
 8944        &self,
 8945        label: impl Into<SharedString>,
 8946        icon: Option<IconName>,
 8947        window: &mut Window,
 8948        cx: &App,
 8949    ) -> Option<Stateful<Div>> {
 8950        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8951
 8952        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8953        let has_keybind = keybind.is_some();
 8954
 8955        let result = h_flex()
 8956            .id("ep-line-popover")
 8957            .py_0p5()
 8958            .pl_1()
 8959            .pr(padding_right)
 8960            .gap_1()
 8961            .rounded_md()
 8962            .border_1()
 8963            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8964            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8965            .shadow_xs()
 8966            .when(!has_keybind, |el| {
 8967                let status_colors = cx.theme().status();
 8968
 8969                el.bg(status_colors.error_background)
 8970                    .border_color(status_colors.error.opacity(0.6))
 8971                    .pl_2()
 8972                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8973                    .cursor_default()
 8974                    .hoverable_tooltip(move |_window, cx| {
 8975                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8976                    })
 8977            })
 8978            .children(keybind)
 8979            .child(
 8980                Label::new(label)
 8981                    .size(LabelSize::Small)
 8982                    .when(!has_keybind, |el| {
 8983                        el.color(cx.theme().status().error.into()).strikethrough()
 8984                    }),
 8985            )
 8986            .when(!has_keybind, |el| {
 8987                el.child(
 8988                    h_flex().ml_1().child(
 8989                        Icon::new(IconName::Info)
 8990                            .size(IconSize::Small)
 8991                            .color(cx.theme().status().error.into()),
 8992                    ),
 8993                )
 8994            })
 8995            .when_some(icon, |element, icon| {
 8996                element.child(
 8997                    div()
 8998                        .mt(px(1.5))
 8999                        .child(Icon::new(icon).size(IconSize::Small)),
 9000                )
 9001            });
 9002
 9003        Some(result)
 9004    }
 9005
 9006    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9007        let accent_color = cx.theme().colors().text_accent;
 9008        let editor_bg_color = cx.theme().colors().editor_background;
 9009        editor_bg_color.blend(accent_color.opacity(0.1))
 9010    }
 9011
 9012    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9013        let accent_color = cx.theme().colors().text_accent;
 9014        let editor_bg_color = cx.theme().colors().editor_background;
 9015        editor_bg_color.blend(accent_color.opacity(0.6))
 9016    }
 9017
 9018    fn render_edit_prediction_cursor_popover(
 9019        &self,
 9020        min_width: Pixels,
 9021        max_width: Pixels,
 9022        cursor_point: Point,
 9023        style: &EditorStyle,
 9024        accept_keystroke: Option<&gpui::Keystroke>,
 9025        _window: &Window,
 9026        cx: &mut Context<Editor>,
 9027    ) -> Option<AnyElement> {
 9028        let provider = self.edit_prediction_provider.as_ref()?;
 9029
 9030        if provider.provider.needs_terms_acceptance(cx) {
 9031            return Some(
 9032                h_flex()
 9033                    .min_w(min_width)
 9034                    .flex_1()
 9035                    .px_2()
 9036                    .py_1()
 9037                    .gap_3()
 9038                    .elevation_2(cx)
 9039                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9040                    .id("accept-terms")
 9041                    .cursor_pointer()
 9042                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9043                    .on_click(cx.listener(|this, _event, window, cx| {
 9044                        cx.stop_propagation();
 9045                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9046                        window.dispatch_action(
 9047                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9048                            cx,
 9049                        );
 9050                    }))
 9051                    .child(
 9052                        h_flex()
 9053                            .flex_1()
 9054                            .gap_2()
 9055                            .child(Icon::new(IconName::ZedPredict))
 9056                            .child(Label::new("Accept Terms of Service"))
 9057                            .child(div().w_full())
 9058                            .child(
 9059                                Icon::new(IconName::ArrowUpRight)
 9060                                    .color(Color::Muted)
 9061                                    .size(IconSize::Small),
 9062                            )
 9063                            .into_any_element(),
 9064                    )
 9065                    .into_any(),
 9066            );
 9067        }
 9068
 9069        let is_refreshing = provider.provider.is_refreshing(cx);
 9070
 9071        fn pending_completion_container() -> Div {
 9072            h_flex()
 9073                .h_full()
 9074                .flex_1()
 9075                .gap_2()
 9076                .child(Icon::new(IconName::ZedPredict))
 9077        }
 9078
 9079        let completion = match &self.active_inline_completion {
 9080            Some(prediction) => {
 9081                if !self.has_visible_completions_menu() {
 9082                    const RADIUS: Pixels = px(6.);
 9083                    const BORDER_WIDTH: Pixels = px(1.);
 9084
 9085                    return Some(
 9086                        h_flex()
 9087                            .elevation_2(cx)
 9088                            .border(BORDER_WIDTH)
 9089                            .border_color(cx.theme().colors().border)
 9090                            .when(accept_keystroke.is_none(), |el| {
 9091                                el.border_color(cx.theme().status().error)
 9092                            })
 9093                            .rounded(RADIUS)
 9094                            .rounded_tl(px(0.))
 9095                            .overflow_hidden()
 9096                            .child(div().px_1p5().child(match &prediction.completion {
 9097                                InlineCompletion::Move { target, snapshot } => {
 9098                                    use text::ToPoint as _;
 9099                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9100                                    {
 9101                                        Icon::new(IconName::ZedPredictDown)
 9102                                    } else {
 9103                                        Icon::new(IconName::ZedPredictUp)
 9104                                    }
 9105                                }
 9106                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9107                            }))
 9108                            .child(
 9109                                h_flex()
 9110                                    .gap_1()
 9111                                    .py_1()
 9112                                    .px_2()
 9113                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9114                                    .border_l_1()
 9115                                    .border_color(cx.theme().colors().border)
 9116                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9117                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9118                                        el.child(
 9119                                            Label::new("Hold")
 9120                                                .size(LabelSize::Small)
 9121                                                .when(accept_keystroke.is_none(), |el| {
 9122                                                    el.strikethrough()
 9123                                                })
 9124                                                .line_height_style(LineHeightStyle::UiLabel),
 9125                                        )
 9126                                    })
 9127                                    .id("edit_prediction_cursor_popover_keybind")
 9128                                    .when(accept_keystroke.is_none(), |el| {
 9129                                        let status_colors = cx.theme().status();
 9130
 9131                                        el.bg(status_colors.error_background)
 9132                                            .border_color(status_colors.error.opacity(0.6))
 9133                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9134                                            .cursor_default()
 9135                                            .hoverable_tooltip(move |_window, cx| {
 9136                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9137                                                    .into()
 9138                                            })
 9139                                    })
 9140                                    .when_some(
 9141                                        accept_keystroke.as_ref(),
 9142                                        |el, accept_keystroke| {
 9143                                            el.child(h_flex().children(ui::render_modifiers(
 9144                                                &accept_keystroke.modifiers,
 9145                                                PlatformStyle::platform(),
 9146                                                Some(Color::Default),
 9147                                                Some(IconSize::XSmall.rems().into()),
 9148                                                false,
 9149                                            )))
 9150                                        },
 9151                                    ),
 9152                            )
 9153                            .into_any(),
 9154                    );
 9155                }
 9156
 9157                self.render_edit_prediction_cursor_popover_preview(
 9158                    prediction,
 9159                    cursor_point,
 9160                    style,
 9161                    cx,
 9162                )?
 9163            }
 9164
 9165            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9166                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9167                    stale_completion,
 9168                    cursor_point,
 9169                    style,
 9170                    cx,
 9171                )?,
 9172
 9173                None => {
 9174                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9175                }
 9176            },
 9177
 9178            None => pending_completion_container().child(Label::new("No Prediction")),
 9179        };
 9180
 9181        let completion = if is_refreshing {
 9182            completion
 9183                .with_animation(
 9184                    "loading-completion",
 9185                    Animation::new(Duration::from_secs(2))
 9186                        .repeat()
 9187                        .with_easing(pulsating_between(0.4, 0.8)),
 9188                    |label, delta| label.opacity(delta),
 9189                )
 9190                .into_any_element()
 9191        } else {
 9192            completion.into_any_element()
 9193        };
 9194
 9195        let has_completion = self.active_inline_completion.is_some();
 9196
 9197        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9198        Some(
 9199            h_flex()
 9200                .min_w(min_width)
 9201                .max_w(max_width)
 9202                .flex_1()
 9203                .elevation_2(cx)
 9204                .border_color(cx.theme().colors().border)
 9205                .child(
 9206                    div()
 9207                        .flex_1()
 9208                        .py_1()
 9209                        .px_2()
 9210                        .overflow_hidden()
 9211                        .child(completion),
 9212                )
 9213                .when_some(accept_keystroke, |el, accept_keystroke| {
 9214                    if !accept_keystroke.modifiers.modified() {
 9215                        return el;
 9216                    }
 9217
 9218                    el.child(
 9219                        h_flex()
 9220                            .h_full()
 9221                            .border_l_1()
 9222                            .rounded_r_lg()
 9223                            .border_color(cx.theme().colors().border)
 9224                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9225                            .gap_1()
 9226                            .py_1()
 9227                            .px_2()
 9228                            .child(
 9229                                h_flex()
 9230                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9231                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9232                                    .child(h_flex().children(ui::render_modifiers(
 9233                                        &accept_keystroke.modifiers,
 9234                                        PlatformStyle::platform(),
 9235                                        Some(if !has_completion {
 9236                                            Color::Muted
 9237                                        } else {
 9238                                            Color::Default
 9239                                        }),
 9240                                        None,
 9241                                        false,
 9242                                    ))),
 9243                            )
 9244                            .child(Label::new("Preview").into_any_element())
 9245                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9246                    )
 9247                })
 9248                .into_any(),
 9249        )
 9250    }
 9251
 9252    fn render_edit_prediction_cursor_popover_preview(
 9253        &self,
 9254        completion: &InlineCompletionState,
 9255        cursor_point: Point,
 9256        style: &EditorStyle,
 9257        cx: &mut Context<Editor>,
 9258    ) -> Option<Div> {
 9259        use text::ToPoint as _;
 9260
 9261        fn render_relative_row_jump(
 9262            prefix: impl Into<String>,
 9263            current_row: u32,
 9264            target_row: u32,
 9265        ) -> Div {
 9266            let (row_diff, arrow) = if target_row < current_row {
 9267                (current_row - target_row, IconName::ArrowUp)
 9268            } else {
 9269                (target_row - current_row, IconName::ArrowDown)
 9270            };
 9271
 9272            h_flex()
 9273                .child(
 9274                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9275                        .color(Color::Muted)
 9276                        .size(LabelSize::Small),
 9277                )
 9278                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9279        }
 9280
 9281        match &completion.completion {
 9282            InlineCompletion::Move {
 9283                target, snapshot, ..
 9284            } => Some(
 9285                h_flex()
 9286                    .px_2()
 9287                    .gap_2()
 9288                    .flex_1()
 9289                    .child(
 9290                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9291                            Icon::new(IconName::ZedPredictDown)
 9292                        } else {
 9293                            Icon::new(IconName::ZedPredictUp)
 9294                        },
 9295                    )
 9296                    .child(Label::new("Jump to Edit")),
 9297            ),
 9298
 9299            InlineCompletion::Edit {
 9300                edits,
 9301                edit_preview,
 9302                snapshot,
 9303                display_mode: _,
 9304            } => {
 9305                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9306
 9307                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9308                    &snapshot,
 9309                    &edits,
 9310                    edit_preview.as_ref()?,
 9311                    true,
 9312                    cx,
 9313                )
 9314                .first_line_preview();
 9315
 9316                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9317                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9318
 9319                let preview = h_flex()
 9320                    .gap_1()
 9321                    .min_w_16()
 9322                    .child(styled_text)
 9323                    .when(has_more_lines, |parent| parent.child(""));
 9324
 9325                let left = if first_edit_row != cursor_point.row {
 9326                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9327                        .into_any_element()
 9328                } else {
 9329                    Icon::new(IconName::ZedPredict).into_any_element()
 9330                };
 9331
 9332                Some(
 9333                    h_flex()
 9334                        .h_full()
 9335                        .flex_1()
 9336                        .gap_2()
 9337                        .pr_1()
 9338                        .overflow_x_hidden()
 9339                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9340                        .child(left)
 9341                        .child(preview),
 9342                )
 9343            }
 9344        }
 9345    }
 9346
 9347    pub fn render_context_menu(
 9348        &self,
 9349        style: &EditorStyle,
 9350        max_height_in_lines: u32,
 9351        window: &mut Window,
 9352        cx: &mut Context<Editor>,
 9353    ) -> Option<AnyElement> {
 9354        let menu = self.context_menu.borrow();
 9355        let menu = menu.as_ref()?;
 9356        if !menu.visible() {
 9357            return None;
 9358        };
 9359        Some(menu.render(style, max_height_in_lines, window, cx))
 9360    }
 9361
 9362    fn render_context_menu_aside(
 9363        &mut self,
 9364        max_size: Size<Pixels>,
 9365        window: &mut Window,
 9366        cx: &mut Context<Editor>,
 9367    ) -> Option<AnyElement> {
 9368        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9369            if menu.visible() {
 9370                menu.render_aside(max_size, window, cx)
 9371            } else {
 9372                None
 9373            }
 9374        })
 9375    }
 9376
 9377    fn hide_context_menu(
 9378        &mut self,
 9379        window: &mut Window,
 9380        cx: &mut Context<Self>,
 9381    ) -> Option<CodeContextMenu> {
 9382        cx.notify();
 9383        self.completion_tasks.clear();
 9384        let context_menu = self.context_menu.borrow_mut().take();
 9385        self.stale_inline_completion_in_menu.take();
 9386        self.update_visible_inline_completion(window, cx);
 9387        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9388            if let Some(completion_provider) = &self.completion_provider {
 9389                completion_provider.selection_changed(None, window, cx);
 9390            }
 9391        }
 9392        context_menu
 9393    }
 9394
 9395    fn show_snippet_choices(
 9396        &mut self,
 9397        choices: &Vec<String>,
 9398        selection: Range<Anchor>,
 9399        cx: &mut Context<Self>,
 9400    ) {
 9401        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9402            (Some(a), Some(b)) if a == b => a,
 9403            _ => {
 9404                log::error!("expected anchor range to have matching buffer IDs");
 9405                return;
 9406            }
 9407        };
 9408        let multi_buffer = self.buffer().read(cx);
 9409        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9410            return;
 9411        };
 9412
 9413        let id = post_inc(&mut self.next_completion_id);
 9414        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9415        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9416            CompletionsMenu::new_snippet_choices(
 9417                id,
 9418                true,
 9419                choices,
 9420                selection,
 9421                buffer,
 9422                snippet_sort_order,
 9423            ),
 9424        ));
 9425    }
 9426
 9427    pub fn insert_snippet(
 9428        &mut self,
 9429        insertion_ranges: &[Range<usize>],
 9430        snippet: Snippet,
 9431        window: &mut Window,
 9432        cx: &mut Context<Self>,
 9433    ) -> Result<()> {
 9434        struct Tabstop<T> {
 9435            is_end_tabstop: bool,
 9436            ranges: Vec<Range<T>>,
 9437            choices: Option<Vec<String>>,
 9438        }
 9439
 9440        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9441            let snippet_text: Arc<str> = snippet.text.clone().into();
 9442            let edits = insertion_ranges
 9443                .iter()
 9444                .cloned()
 9445                .map(|range| (range, snippet_text.clone()));
 9446            let autoindent_mode = AutoindentMode::Block {
 9447                original_indent_columns: Vec::new(),
 9448            };
 9449            buffer.edit(edits, Some(autoindent_mode), cx);
 9450
 9451            let snapshot = &*buffer.read(cx);
 9452            let snippet = &snippet;
 9453            snippet
 9454                .tabstops
 9455                .iter()
 9456                .map(|tabstop| {
 9457                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9458                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9459                    });
 9460                    let mut tabstop_ranges = tabstop
 9461                        .ranges
 9462                        .iter()
 9463                        .flat_map(|tabstop_range| {
 9464                            let mut delta = 0_isize;
 9465                            insertion_ranges.iter().map(move |insertion_range| {
 9466                                let insertion_start = insertion_range.start as isize + delta;
 9467                                delta +=
 9468                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9469
 9470                                let start = ((insertion_start + tabstop_range.start) as usize)
 9471                                    .min(snapshot.len());
 9472                                let end = ((insertion_start + tabstop_range.end) as usize)
 9473                                    .min(snapshot.len());
 9474                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9475                            })
 9476                        })
 9477                        .collect::<Vec<_>>();
 9478                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9479
 9480                    Tabstop {
 9481                        is_end_tabstop,
 9482                        ranges: tabstop_ranges,
 9483                        choices: tabstop.choices.clone(),
 9484                    }
 9485                })
 9486                .collect::<Vec<_>>()
 9487        });
 9488        if let Some(tabstop) = tabstops.first() {
 9489            self.change_selections(Default::default(), window, cx, |s| {
 9490                // Reverse order so that the first range is the newest created selection.
 9491                // Completions will use it and autoscroll will prioritize it.
 9492                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9493            });
 9494
 9495            if let Some(choices) = &tabstop.choices {
 9496                if let Some(selection) = tabstop.ranges.first() {
 9497                    self.show_snippet_choices(choices, selection.clone(), cx)
 9498                }
 9499            }
 9500
 9501            // If we're already at the last tabstop and it's at the end of the snippet,
 9502            // we're done, we don't need to keep the state around.
 9503            if !tabstop.is_end_tabstop {
 9504                let choices = tabstops
 9505                    .iter()
 9506                    .map(|tabstop| tabstop.choices.clone())
 9507                    .collect();
 9508
 9509                let ranges = tabstops
 9510                    .into_iter()
 9511                    .map(|tabstop| tabstop.ranges)
 9512                    .collect::<Vec<_>>();
 9513
 9514                self.snippet_stack.push(SnippetState {
 9515                    active_index: 0,
 9516                    ranges,
 9517                    choices,
 9518                });
 9519            }
 9520
 9521            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9522            if self.autoclose_regions.is_empty() {
 9523                let snapshot = self.buffer.read(cx).snapshot(cx);
 9524                for selection in &mut self.selections.all::<Point>(cx) {
 9525                    let selection_head = selection.head();
 9526                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9527                        continue;
 9528                    };
 9529
 9530                    let mut bracket_pair = None;
 9531                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9532                    let prev_chars = snapshot
 9533                        .reversed_chars_at(selection_head)
 9534                        .collect::<String>();
 9535                    for (pair, enabled) in scope.brackets() {
 9536                        if enabled
 9537                            && pair.close
 9538                            && prev_chars.starts_with(pair.start.as_str())
 9539                            && next_chars.starts_with(pair.end.as_str())
 9540                        {
 9541                            bracket_pair = Some(pair.clone());
 9542                            break;
 9543                        }
 9544                    }
 9545                    if let Some(pair) = bracket_pair {
 9546                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9547                        let autoclose_enabled =
 9548                            self.use_autoclose && snapshot_settings.use_autoclose;
 9549                        if autoclose_enabled {
 9550                            let start = snapshot.anchor_after(selection_head);
 9551                            let end = snapshot.anchor_after(selection_head);
 9552                            self.autoclose_regions.push(AutocloseRegion {
 9553                                selection_id: selection.id,
 9554                                range: start..end,
 9555                                pair,
 9556                            });
 9557                        }
 9558                    }
 9559                }
 9560            }
 9561        }
 9562        Ok(())
 9563    }
 9564
 9565    pub fn move_to_next_snippet_tabstop(
 9566        &mut self,
 9567        window: &mut Window,
 9568        cx: &mut Context<Self>,
 9569    ) -> bool {
 9570        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9571    }
 9572
 9573    pub fn move_to_prev_snippet_tabstop(
 9574        &mut self,
 9575        window: &mut Window,
 9576        cx: &mut Context<Self>,
 9577    ) -> bool {
 9578        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9579    }
 9580
 9581    pub fn move_to_snippet_tabstop(
 9582        &mut self,
 9583        bias: Bias,
 9584        window: &mut Window,
 9585        cx: &mut Context<Self>,
 9586    ) -> bool {
 9587        if let Some(mut snippet) = self.snippet_stack.pop() {
 9588            match bias {
 9589                Bias::Left => {
 9590                    if snippet.active_index > 0 {
 9591                        snippet.active_index -= 1;
 9592                    } else {
 9593                        self.snippet_stack.push(snippet);
 9594                        return false;
 9595                    }
 9596                }
 9597                Bias::Right => {
 9598                    if snippet.active_index + 1 < snippet.ranges.len() {
 9599                        snippet.active_index += 1;
 9600                    } else {
 9601                        self.snippet_stack.push(snippet);
 9602                        return false;
 9603                    }
 9604                }
 9605            }
 9606            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9607                self.change_selections(Default::default(), window, cx, |s| {
 9608                    // Reverse order so that the first range is the newest created selection.
 9609                    // Completions will use it and autoscroll will prioritize it.
 9610                    s.select_ranges(current_ranges.iter().rev().cloned())
 9611                });
 9612
 9613                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9614                    if let Some(selection) = current_ranges.first() {
 9615                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9616                    }
 9617                }
 9618
 9619                // If snippet state is not at the last tabstop, push it back on the stack
 9620                if snippet.active_index + 1 < snippet.ranges.len() {
 9621                    self.snippet_stack.push(snippet);
 9622                }
 9623                return true;
 9624            }
 9625        }
 9626
 9627        false
 9628    }
 9629
 9630    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9631        self.transact(window, cx, |this, window, cx| {
 9632            this.select_all(&SelectAll, window, cx);
 9633            this.insert("", window, cx);
 9634        });
 9635    }
 9636
 9637    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9639        self.transact(window, cx, |this, window, cx| {
 9640            this.select_autoclose_pair(window, cx);
 9641            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9642            if !this.linked_edit_ranges.is_empty() {
 9643                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9644                let snapshot = this.buffer.read(cx).snapshot(cx);
 9645
 9646                for selection in selections.iter() {
 9647                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9648                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9649                    if selection_start.buffer_id != selection_end.buffer_id {
 9650                        continue;
 9651                    }
 9652                    if let Some(ranges) =
 9653                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9654                    {
 9655                        for (buffer, entries) in ranges {
 9656                            linked_ranges.entry(buffer).or_default().extend(entries);
 9657                        }
 9658                    }
 9659                }
 9660            }
 9661
 9662            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9663            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9664            for selection in &mut selections {
 9665                if selection.is_empty() {
 9666                    let old_head = selection.head();
 9667                    let mut new_head =
 9668                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9669                            .to_point(&display_map);
 9670                    if let Some((buffer, line_buffer_range)) = display_map
 9671                        .buffer_snapshot
 9672                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9673                    {
 9674                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9675                        let indent_len = match indent_size.kind {
 9676                            IndentKind::Space => {
 9677                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9678                            }
 9679                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9680                        };
 9681                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9682                            let indent_len = indent_len.get();
 9683                            new_head = cmp::min(
 9684                                new_head,
 9685                                MultiBufferPoint::new(
 9686                                    old_head.row,
 9687                                    ((old_head.column - 1) / indent_len) * indent_len,
 9688                                ),
 9689                            );
 9690                        }
 9691                    }
 9692
 9693                    selection.set_head(new_head, SelectionGoal::None);
 9694                }
 9695            }
 9696
 9697            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9698            this.insert("", window, cx);
 9699            let empty_str: Arc<str> = Arc::from("");
 9700            for (buffer, edits) in linked_ranges {
 9701                let snapshot = buffer.read(cx).snapshot();
 9702                use text::ToPoint as TP;
 9703
 9704                let edits = edits
 9705                    .into_iter()
 9706                    .map(|range| {
 9707                        let end_point = TP::to_point(&range.end, &snapshot);
 9708                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9709
 9710                        if end_point == start_point {
 9711                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9712                                .saturating_sub(1);
 9713                            start_point =
 9714                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9715                        };
 9716
 9717                        (start_point..end_point, empty_str.clone())
 9718                    })
 9719                    .sorted_by_key(|(range, _)| range.start)
 9720                    .collect::<Vec<_>>();
 9721                buffer.update(cx, |this, cx| {
 9722                    this.edit(edits, None, cx);
 9723                })
 9724            }
 9725            this.refresh_inline_completion(true, false, window, cx);
 9726            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9727        });
 9728    }
 9729
 9730    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9731        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9732        self.transact(window, cx, |this, window, cx| {
 9733            this.change_selections(Default::default(), window, cx, |s| {
 9734                s.move_with(|map, selection| {
 9735                    if selection.is_empty() {
 9736                        let cursor = movement::right(map, selection.head());
 9737                        selection.end = cursor;
 9738                        selection.reversed = true;
 9739                        selection.goal = SelectionGoal::None;
 9740                    }
 9741                })
 9742            });
 9743            this.insert("", window, cx);
 9744            this.refresh_inline_completion(true, false, window, cx);
 9745        });
 9746    }
 9747
 9748    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9749        if self.mode.is_single_line() {
 9750            cx.propagate();
 9751            return;
 9752        }
 9753
 9754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9755        if self.move_to_prev_snippet_tabstop(window, cx) {
 9756            return;
 9757        }
 9758        self.outdent(&Outdent, window, cx);
 9759    }
 9760
 9761    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9762        if self.mode.is_single_line() {
 9763            cx.propagate();
 9764            return;
 9765        }
 9766
 9767        if self.move_to_next_snippet_tabstop(window, cx) {
 9768            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9769            return;
 9770        }
 9771        if self.read_only(cx) {
 9772            return;
 9773        }
 9774        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9775        let mut selections = self.selections.all_adjusted(cx);
 9776        let buffer = self.buffer.read(cx);
 9777        let snapshot = buffer.snapshot(cx);
 9778        let rows_iter = selections.iter().map(|s| s.head().row);
 9779        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9780
 9781        let has_some_cursor_in_whitespace = selections
 9782            .iter()
 9783            .filter(|selection| selection.is_empty())
 9784            .any(|selection| {
 9785                let cursor = selection.head();
 9786                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9787                cursor.column < current_indent.len
 9788            });
 9789
 9790        let mut edits = Vec::new();
 9791        let mut prev_edited_row = 0;
 9792        let mut row_delta = 0;
 9793        for selection in &mut selections {
 9794            if selection.start.row != prev_edited_row {
 9795                row_delta = 0;
 9796            }
 9797            prev_edited_row = selection.end.row;
 9798
 9799            // If the selection is non-empty, then increase the indentation of the selected lines.
 9800            if !selection.is_empty() {
 9801                row_delta =
 9802                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9803                continue;
 9804            }
 9805
 9806            let cursor = selection.head();
 9807            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9808            if let Some(suggested_indent) =
 9809                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9810            {
 9811                // Don't do anything if already at suggested indent
 9812                // and there is any other cursor which is not
 9813                if has_some_cursor_in_whitespace
 9814                    && cursor.column == current_indent.len
 9815                    && current_indent.len == suggested_indent.len
 9816                {
 9817                    continue;
 9818                }
 9819
 9820                // Adjust line and move cursor to suggested indent
 9821                // if cursor is not at suggested indent
 9822                if cursor.column < suggested_indent.len
 9823                    && cursor.column <= current_indent.len
 9824                    && current_indent.len <= suggested_indent.len
 9825                {
 9826                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9827                    selection.end = selection.start;
 9828                    if row_delta == 0 {
 9829                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9830                            cursor.row,
 9831                            current_indent,
 9832                            suggested_indent,
 9833                        ));
 9834                        row_delta = suggested_indent.len - current_indent.len;
 9835                    }
 9836                    continue;
 9837                }
 9838
 9839                // If current indent is more than suggested indent
 9840                // only move cursor to current indent and skip indent
 9841                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9842                    selection.start = Point::new(cursor.row, current_indent.len);
 9843                    selection.end = selection.start;
 9844                    continue;
 9845                }
 9846            }
 9847
 9848            // Otherwise, insert a hard or soft tab.
 9849            let settings = buffer.language_settings_at(cursor, cx);
 9850            let tab_size = if settings.hard_tabs {
 9851                IndentSize::tab()
 9852            } else {
 9853                let tab_size = settings.tab_size.get();
 9854                let indent_remainder = snapshot
 9855                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9856                    .flat_map(str::chars)
 9857                    .fold(row_delta % tab_size, |counter: u32, c| {
 9858                        if c == '\t' {
 9859                            0
 9860                        } else {
 9861                            (counter + 1) % tab_size
 9862                        }
 9863                    });
 9864
 9865                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9866                IndentSize::spaces(chars_to_next_tab_stop)
 9867            };
 9868            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9869            selection.end = selection.start;
 9870            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9871            row_delta += tab_size.len;
 9872        }
 9873
 9874        self.transact(window, cx, |this, window, cx| {
 9875            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9876            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9877            this.refresh_inline_completion(true, false, window, cx);
 9878        });
 9879    }
 9880
 9881    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9882        if self.read_only(cx) {
 9883            return;
 9884        }
 9885        if self.mode.is_single_line() {
 9886            cx.propagate();
 9887            return;
 9888        }
 9889
 9890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9891        let mut selections = self.selections.all::<Point>(cx);
 9892        let mut prev_edited_row = 0;
 9893        let mut row_delta = 0;
 9894        let mut edits = Vec::new();
 9895        let buffer = self.buffer.read(cx);
 9896        let snapshot = buffer.snapshot(cx);
 9897        for selection in &mut selections {
 9898            if selection.start.row != prev_edited_row {
 9899                row_delta = 0;
 9900            }
 9901            prev_edited_row = selection.end.row;
 9902
 9903            row_delta =
 9904                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9905        }
 9906
 9907        self.transact(window, cx, |this, window, cx| {
 9908            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9909            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9910        });
 9911    }
 9912
 9913    fn indent_selection(
 9914        buffer: &MultiBuffer,
 9915        snapshot: &MultiBufferSnapshot,
 9916        selection: &mut Selection<Point>,
 9917        edits: &mut Vec<(Range<Point>, String)>,
 9918        delta_for_start_row: u32,
 9919        cx: &App,
 9920    ) -> u32 {
 9921        let settings = buffer.language_settings_at(selection.start, cx);
 9922        let tab_size = settings.tab_size.get();
 9923        let indent_kind = if settings.hard_tabs {
 9924            IndentKind::Tab
 9925        } else {
 9926            IndentKind::Space
 9927        };
 9928        let mut start_row = selection.start.row;
 9929        let mut end_row = selection.end.row + 1;
 9930
 9931        // If a selection ends at the beginning of a line, don't indent
 9932        // that last line.
 9933        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9934            end_row -= 1;
 9935        }
 9936
 9937        // Avoid re-indenting a row that has already been indented by a
 9938        // previous selection, but still update this selection's column
 9939        // to reflect that indentation.
 9940        if delta_for_start_row > 0 {
 9941            start_row += 1;
 9942            selection.start.column += delta_for_start_row;
 9943            if selection.end.row == selection.start.row {
 9944                selection.end.column += delta_for_start_row;
 9945            }
 9946        }
 9947
 9948        let mut delta_for_end_row = 0;
 9949        let has_multiple_rows = start_row + 1 != end_row;
 9950        for row in start_row..end_row {
 9951            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9952            let indent_delta = match (current_indent.kind, indent_kind) {
 9953                (IndentKind::Space, IndentKind::Space) => {
 9954                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9955                    IndentSize::spaces(columns_to_next_tab_stop)
 9956                }
 9957                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9958                (_, IndentKind::Tab) => IndentSize::tab(),
 9959            };
 9960
 9961            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9962                0
 9963            } else {
 9964                selection.start.column
 9965            };
 9966            let row_start = Point::new(row, start);
 9967            edits.push((
 9968                row_start..row_start,
 9969                indent_delta.chars().collect::<String>(),
 9970            ));
 9971
 9972            // Update this selection's endpoints to reflect the indentation.
 9973            if row == selection.start.row {
 9974                selection.start.column += indent_delta.len;
 9975            }
 9976            if row == selection.end.row {
 9977                selection.end.column += indent_delta.len;
 9978                delta_for_end_row = indent_delta.len;
 9979            }
 9980        }
 9981
 9982        if selection.start.row == selection.end.row {
 9983            delta_for_start_row + delta_for_end_row
 9984        } else {
 9985            delta_for_end_row
 9986        }
 9987    }
 9988
 9989    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9990        if self.read_only(cx) {
 9991            return;
 9992        }
 9993        if self.mode.is_single_line() {
 9994            cx.propagate();
 9995            return;
 9996        }
 9997
 9998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9999        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10000        let selections = self.selections.all::<Point>(cx);
10001        let mut deletion_ranges = Vec::new();
10002        let mut last_outdent = None;
10003        {
10004            let buffer = self.buffer.read(cx);
10005            let snapshot = buffer.snapshot(cx);
10006            for selection in &selections {
10007                let settings = buffer.language_settings_at(selection.start, cx);
10008                let tab_size = settings.tab_size.get();
10009                let mut rows = selection.spanned_rows(false, &display_map);
10010
10011                // Avoid re-outdenting a row that has already been outdented by a
10012                // previous selection.
10013                if let Some(last_row) = last_outdent {
10014                    if last_row == rows.start {
10015                        rows.start = rows.start.next_row();
10016                    }
10017                }
10018                let has_multiple_rows = rows.len() > 1;
10019                for row in rows.iter_rows() {
10020                    let indent_size = snapshot.indent_size_for_line(row);
10021                    if indent_size.len > 0 {
10022                        let deletion_len = match indent_size.kind {
10023                            IndentKind::Space => {
10024                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10025                                if columns_to_prev_tab_stop == 0 {
10026                                    tab_size
10027                                } else {
10028                                    columns_to_prev_tab_stop
10029                                }
10030                            }
10031                            IndentKind::Tab => 1,
10032                        };
10033                        let start = if has_multiple_rows
10034                            || deletion_len > selection.start.column
10035                            || indent_size.len < selection.start.column
10036                        {
10037                            0
10038                        } else {
10039                            selection.start.column - deletion_len
10040                        };
10041                        deletion_ranges.push(
10042                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10043                        );
10044                        last_outdent = Some(row);
10045                    }
10046                }
10047            }
10048        }
10049
10050        self.transact(window, cx, |this, window, cx| {
10051            this.buffer.update(cx, |buffer, cx| {
10052                let empty_str: Arc<str> = Arc::default();
10053                buffer.edit(
10054                    deletion_ranges
10055                        .into_iter()
10056                        .map(|range| (range, empty_str.clone())),
10057                    None,
10058                    cx,
10059                );
10060            });
10061            let selections = this.selections.all::<usize>(cx);
10062            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10063        });
10064    }
10065
10066    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10067        if self.read_only(cx) {
10068            return;
10069        }
10070        if self.mode.is_single_line() {
10071            cx.propagate();
10072            return;
10073        }
10074
10075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10076        let selections = self
10077            .selections
10078            .all::<usize>(cx)
10079            .into_iter()
10080            .map(|s| s.range());
10081
10082        self.transact(window, cx, |this, window, cx| {
10083            this.buffer.update(cx, |buffer, cx| {
10084                buffer.autoindent_ranges(selections, cx);
10085            });
10086            let selections = this.selections.all::<usize>(cx);
10087            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10088        });
10089    }
10090
10091    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10092        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10093        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10094        let selections = self.selections.all::<Point>(cx);
10095
10096        let mut new_cursors = Vec::new();
10097        let mut edit_ranges = Vec::new();
10098        let mut selections = selections.iter().peekable();
10099        while let Some(selection) = selections.next() {
10100            let mut rows = selection.spanned_rows(false, &display_map);
10101            let goal_display_column = selection.head().to_display_point(&display_map).column();
10102
10103            // Accumulate contiguous regions of rows that we want to delete.
10104            while let Some(next_selection) = selections.peek() {
10105                let next_rows = next_selection.spanned_rows(false, &display_map);
10106                if next_rows.start <= rows.end {
10107                    rows.end = next_rows.end;
10108                    selections.next().unwrap();
10109                } else {
10110                    break;
10111                }
10112            }
10113
10114            let buffer = &display_map.buffer_snapshot;
10115            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10116            let edit_end;
10117            let cursor_buffer_row;
10118            if buffer.max_point().row >= rows.end.0 {
10119                // If there's a line after the range, delete the \n from the end of the row range
10120                // and position the cursor on the next line.
10121                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10122                cursor_buffer_row = rows.end;
10123            } else {
10124                // If there isn't a line after the range, delete the \n from the line before the
10125                // start of the row range and position the cursor there.
10126                edit_start = edit_start.saturating_sub(1);
10127                edit_end = buffer.len();
10128                cursor_buffer_row = rows.start.previous_row();
10129            }
10130
10131            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10132            *cursor.column_mut() =
10133                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10134
10135            new_cursors.push((
10136                selection.id,
10137                buffer.anchor_after(cursor.to_point(&display_map)),
10138            ));
10139            edit_ranges.push(edit_start..edit_end);
10140        }
10141
10142        self.transact(window, cx, |this, window, cx| {
10143            let buffer = this.buffer.update(cx, |buffer, cx| {
10144                let empty_str: Arc<str> = Arc::default();
10145                buffer.edit(
10146                    edit_ranges
10147                        .into_iter()
10148                        .map(|range| (range, empty_str.clone())),
10149                    None,
10150                    cx,
10151                );
10152                buffer.snapshot(cx)
10153            });
10154            let new_selections = new_cursors
10155                .into_iter()
10156                .map(|(id, cursor)| {
10157                    let cursor = cursor.to_point(&buffer);
10158                    Selection {
10159                        id,
10160                        start: cursor,
10161                        end: cursor,
10162                        reversed: false,
10163                        goal: SelectionGoal::None,
10164                    }
10165                })
10166                .collect();
10167
10168            this.change_selections(Default::default(), window, cx, |s| {
10169                s.select(new_selections);
10170            });
10171        });
10172    }
10173
10174    pub fn join_lines_impl(
10175        &mut self,
10176        insert_whitespace: bool,
10177        window: &mut Window,
10178        cx: &mut Context<Self>,
10179    ) {
10180        if self.read_only(cx) {
10181            return;
10182        }
10183        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10184        for selection in self.selections.all::<Point>(cx) {
10185            let start = MultiBufferRow(selection.start.row);
10186            // Treat single line selections as if they include the next line. Otherwise this action
10187            // would do nothing for single line selections individual cursors.
10188            let end = if selection.start.row == selection.end.row {
10189                MultiBufferRow(selection.start.row + 1)
10190            } else {
10191                MultiBufferRow(selection.end.row)
10192            };
10193
10194            if let Some(last_row_range) = row_ranges.last_mut() {
10195                if start <= last_row_range.end {
10196                    last_row_range.end = end;
10197                    continue;
10198                }
10199            }
10200            row_ranges.push(start..end);
10201        }
10202
10203        let snapshot = self.buffer.read(cx).snapshot(cx);
10204        let mut cursor_positions = Vec::new();
10205        for row_range in &row_ranges {
10206            let anchor = snapshot.anchor_before(Point::new(
10207                row_range.end.previous_row().0,
10208                snapshot.line_len(row_range.end.previous_row()),
10209            ));
10210            cursor_positions.push(anchor..anchor);
10211        }
10212
10213        self.transact(window, cx, |this, window, cx| {
10214            for row_range in row_ranges.into_iter().rev() {
10215                for row in row_range.iter_rows().rev() {
10216                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10217                    let next_line_row = row.next_row();
10218                    let indent = snapshot.indent_size_for_line(next_line_row);
10219                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10220
10221                    let replace =
10222                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10223                            " "
10224                        } else {
10225                            ""
10226                        };
10227
10228                    this.buffer.update(cx, |buffer, cx| {
10229                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10230                    });
10231                }
10232            }
10233
10234            this.change_selections(Default::default(), window, cx, |s| {
10235                s.select_anchor_ranges(cursor_positions)
10236            });
10237        });
10238    }
10239
10240    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10242        self.join_lines_impl(true, window, cx);
10243    }
10244
10245    pub fn sort_lines_case_sensitive(
10246        &mut self,
10247        _: &SortLinesCaseSensitive,
10248        window: &mut Window,
10249        cx: &mut Context<Self>,
10250    ) {
10251        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10252    }
10253
10254    pub fn sort_lines_by_length(
10255        &mut self,
10256        _: &SortLinesByLength,
10257        window: &mut Window,
10258        cx: &mut Context<Self>,
10259    ) {
10260        self.manipulate_immutable_lines(window, cx, |lines| {
10261            lines.sort_by_key(|&line| line.chars().count())
10262        })
10263    }
10264
10265    pub fn sort_lines_case_insensitive(
10266        &mut self,
10267        _: &SortLinesCaseInsensitive,
10268        window: &mut Window,
10269        cx: &mut Context<Self>,
10270    ) {
10271        self.manipulate_immutable_lines(window, cx, |lines| {
10272            lines.sort_by_key(|line| line.to_lowercase())
10273        })
10274    }
10275
10276    pub fn unique_lines_case_insensitive(
10277        &mut self,
10278        _: &UniqueLinesCaseInsensitive,
10279        window: &mut Window,
10280        cx: &mut Context<Self>,
10281    ) {
10282        self.manipulate_immutable_lines(window, cx, |lines| {
10283            let mut seen = HashSet::default();
10284            lines.retain(|line| seen.insert(line.to_lowercase()));
10285        })
10286    }
10287
10288    pub fn unique_lines_case_sensitive(
10289        &mut self,
10290        _: &UniqueLinesCaseSensitive,
10291        window: &mut Window,
10292        cx: &mut Context<Self>,
10293    ) {
10294        self.manipulate_immutable_lines(window, cx, |lines| {
10295            let mut seen = HashSet::default();
10296            lines.retain(|line| seen.insert(*line));
10297        })
10298    }
10299
10300    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10301        let Some(project) = self.project.clone() else {
10302            return;
10303        };
10304        self.reload(project, window, cx)
10305            .detach_and_notify_err(window, cx);
10306    }
10307
10308    pub fn restore_file(
10309        &mut self,
10310        _: &::git::RestoreFile,
10311        window: &mut Window,
10312        cx: &mut Context<Self>,
10313    ) {
10314        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10315        let mut buffer_ids = HashSet::default();
10316        let snapshot = self.buffer().read(cx).snapshot(cx);
10317        for selection in self.selections.all::<usize>(cx) {
10318            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10319        }
10320
10321        let buffer = self.buffer().read(cx);
10322        let ranges = buffer_ids
10323            .into_iter()
10324            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10325            .collect::<Vec<_>>();
10326
10327        self.restore_hunks_in_ranges(ranges, window, cx);
10328    }
10329
10330    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10331        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10332        let selections = self
10333            .selections
10334            .all(cx)
10335            .into_iter()
10336            .map(|s| s.range())
10337            .collect();
10338        self.restore_hunks_in_ranges(selections, window, cx);
10339    }
10340
10341    pub fn restore_hunks_in_ranges(
10342        &mut self,
10343        ranges: Vec<Range<Point>>,
10344        window: &mut Window,
10345        cx: &mut Context<Editor>,
10346    ) {
10347        let mut revert_changes = HashMap::default();
10348        let chunk_by = self
10349            .snapshot(window, cx)
10350            .hunks_for_ranges(ranges)
10351            .into_iter()
10352            .chunk_by(|hunk| hunk.buffer_id);
10353        for (buffer_id, hunks) in &chunk_by {
10354            let hunks = hunks.collect::<Vec<_>>();
10355            for hunk in &hunks {
10356                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10357            }
10358            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10359        }
10360        drop(chunk_by);
10361        if !revert_changes.is_empty() {
10362            self.transact(window, cx, |editor, window, cx| {
10363                editor.restore(revert_changes, window, cx);
10364            });
10365        }
10366    }
10367
10368    pub fn open_active_item_in_terminal(
10369        &mut self,
10370        _: &OpenInTerminal,
10371        window: &mut Window,
10372        cx: &mut Context<Self>,
10373    ) {
10374        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10375            let project_path = buffer.read(cx).project_path(cx)?;
10376            let project = self.project.as_ref()?.read(cx);
10377            let entry = project.entry_for_path(&project_path, cx)?;
10378            let parent = match &entry.canonical_path {
10379                Some(canonical_path) => canonical_path.to_path_buf(),
10380                None => project.absolute_path(&project_path, cx)?,
10381            }
10382            .parent()?
10383            .to_path_buf();
10384            Some(parent)
10385        }) {
10386            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10387        }
10388    }
10389
10390    fn set_breakpoint_context_menu(
10391        &mut self,
10392        display_row: DisplayRow,
10393        position: Option<Anchor>,
10394        clicked_point: gpui::Point<Pixels>,
10395        window: &mut Window,
10396        cx: &mut Context<Self>,
10397    ) {
10398        let source = self
10399            .buffer
10400            .read(cx)
10401            .snapshot(cx)
10402            .anchor_before(Point::new(display_row.0, 0u32));
10403
10404        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10405
10406        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10407            self,
10408            source,
10409            clicked_point,
10410            context_menu,
10411            window,
10412            cx,
10413        );
10414    }
10415
10416    fn add_edit_breakpoint_block(
10417        &mut self,
10418        anchor: Anchor,
10419        breakpoint: &Breakpoint,
10420        edit_action: BreakpointPromptEditAction,
10421        window: &mut Window,
10422        cx: &mut Context<Self>,
10423    ) {
10424        let weak_editor = cx.weak_entity();
10425        let bp_prompt = cx.new(|cx| {
10426            BreakpointPromptEditor::new(
10427                weak_editor,
10428                anchor,
10429                breakpoint.clone(),
10430                edit_action,
10431                window,
10432                cx,
10433            )
10434        });
10435
10436        let height = bp_prompt.update(cx, |this, cx| {
10437            this.prompt
10438                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10439        });
10440        let cloned_prompt = bp_prompt.clone();
10441        let blocks = vec![BlockProperties {
10442            style: BlockStyle::Sticky,
10443            placement: BlockPlacement::Above(anchor),
10444            height: Some(height),
10445            render: Arc::new(move |cx| {
10446                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10447                cloned_prompt.clone().into_any_element()
10448            }),
10449            priority: 0,
10450        }];
10451
10452        let focus_handle = bp_prompt.focus_handle(cx);
10453        window.focus(&focus_handle);
10454
10455        let block_ids = self.insert_blocks(blocks, None, cx);
10456        bp_prompt.update(cx, |prompt, _| {
10457            prompt.add_block_ids(block_ids);
10458        });
10459    }
10460
10461    pub(crate) fn breakpoint_at_row(
10462        &self,
10463        row: u32,
10464        window: &mut Window,
10465        cx: &mut Context<Self>,
10466    ) -> Option<(Anchor, Breakpoint)> {
10467        let snapshot = self.snapshot(window, cx);
10468        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10469
10470        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10471    }
10472
10473    pub(crate) fn breakpoint_at_anchor(
10474        &self,
10475        breakpoint_position: Anchor,
10476        snapshot: &EditorSnapshot,
10477        cx: &mut Context<Self>,
10478    ) -> Option<(Anchor, Breakpoint)> {
10479        let project = self.project.clone()?;
10480
10481        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10482            snapshot
10483                .buffer_snapshot
10484                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10485        })?;
10486
10487        let enclosing_excerpt = breakpoint_position.excerpt_id;
10488        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10489        let buffer_snapshot = buffer.read(cx).snapshot();
10490
10491        let row = buffer_snapshot
10492            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10493            .row;
10494
10495        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10496        let anchor_end = snapshot
10497            .buffer_snapshot
10498            .anchor_after(Point::new(row, line_len));
10499
10500        let bp = self
10501            .breakpoint_store
10502            .as_ref()?
10503            .read_with(cx, |breakpoint_store, cx| {
10504                breakpoint_store
10505                    .breakpoints(
10506                        &buffer,
10507                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10508                        &buffer_snapshot,
10509                        cx,
10510                    )
10511                    .next()
10512                    .and_then(|(bp, _)| {
10513                        let breakpoint_row = buffer_snapshot
10514                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10515                            .row;
10516
10517                        if breakpoint_row == row {
10518                            snapshot
10519                                .buffer_snapshot
10520                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10521                                .map(|position| (position, bp.bp.clone()))
10522                        } else {
10523                            None
10524                        }
10525                    })
10526            });
10527        bp
10528    }
10529
10530    pub fn edit_log_breakpoint(
10531        &mut self,
10532        _: &EditLogBreakpoint,
10533        window: &mut Window,
10534        cx: &mut Context<Self>,
10535    ) {
10536        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10537            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10538                message: None,
10539                state: BreakpointState::Enabled,
10540                condition: None,
10541                hit_condition: None,
10542            });
10543
10544            self.add_edit_breakpoint_block(
10545                anchor,
10546                &breakpoint,
10547                BreakpointPromptEditAction::Log,
10548                window,
10549                cx,
10550            );
10551        }
10552    }
10553
10554    fn breakpoints_at_cursors(
10555        &self,
10556        window: &mut Window,
10557        cx: &mut Context<Self>,
10558    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10559        let snapshot = self.snapshot(window, cx);
10560        let cursors = self
10561            .selections
10562            .disjoint_anchors()
10563            .into_iter()
10564            .map(|selection| {
10565                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10566
10567                let breakpoint_position = self
10568                    .breakpoint_at_row(cursor_position.row, window, cx)
10569                    .map(|bp| bp.0)
10570                    .unwrap_or_else(|| {
10571                        snapshot
10572                            .display_snapshot
10573                            .buffer_snapshot
10574                            .anchor_after(Point::new(cursor_position.row, 0))
10575                    });
10576
10577                let breakpoint = self
10578                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10579                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10580
10581                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10582            })
10583            // 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.
10584            .collect::<HashMap<Anchor, _>>();
10585
10586        cursors.into_iter().collect()
10587    }
10588
10589    pub fn enable_breakpoint(
10590        &mut self,
10591        _: &crate::actions::EnableBreakpoint,
10592        window: &mut Window,
10593        cx: &mut Context<Self>,
10594    ) {
10595        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10596            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10597                continue;
10598            };
10599            self.edit_breakpoint_at_anchor(
10600                anchor,
10601                breakpoint,
10602                BreakpointEditAction::InvertState,
10603                cx,
10604            );
10605        }
10606    }
10607
10608    pub fn disable_breakpoint(
10609        &mut self,
10610        _: &crate::actions::DisableBreakpoint,
10611        window: &mut Window,
10612        cx: &mut Context<Self>,
10613    ) {
10614        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10615            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10616                continue;
10617            };
10618            self.edit_breakpoint_at_anchor(
10619                anchor,
10620                breakpoint,
10621                BreakpointEditAction::InvertState,
10622                cx,
10623            );
10624        }
10625    }
10626
10627    pub fn toggle_breakpoint(
10628        &mut self,
10629        _: &crate::actions::ToggleBreakpoint,
10630        window: &mut Window,
10631        cx: &mut Context<Self>,
10632    ) {
10633        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10634            if let Some(breakpoint) = breakpoint {
10635                self.edit_breakpoint_at_anchor(
10636                    anchor,
10637                    breakpoint,
10638                    BreakpointEditAction::Toggle,
10639                    cx,
10640                );
10641            } else {
10642                self.edit_breakpoint_at_anchor(
10643                    anchor,
10644                    Breakpoint::new_standard(),
10645                    BreakpointEditAction::Toggle,
10646                    cx,
10647                );
10648            }
10649        }
10650    }
10651
10652    pub fn edit_breakpoint_at_anchor(
10653        &mut self,
10654        breakpoint_position: Anchor,
10655        breakpoint: Breakpoint,
10656        edit_action: BreakpointEditAction,
10657        cx: &mut Context<Self>,
10658    ) {
10659        let Some(breakpoint_store) = &self.breakpoint_store else {
10660            return;
10661        };
10662
10663        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10664            if breakpoint_position == Anchor::min() {
10665                self.buffer()
10666                    .read(cx)
10667                    .excerpt_buffer_ids()
10668                    .into_iter()
10669                    .next()
10670            } else {
10671                None
10672            }
10673        }) else {
10674            return;
10675        };
10676
10677        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10678            return;
10679        };
10680
10681        breakpoint_store.update(cx, |breakpoint_store, cx| {
10682            breakpoint_store.toggle_breakpoint(
10683                buffer,
10684                BreakpointWithPosition {
10685                    position: breakpoint_position.text_anchor,
10686                    bp: breakpoint,
10687                },
10688                edit_action,
10689                cx,
10690            );
10691        });
10692
10693        cx.notify();
10694    }
10695
10696    #[cfg(any(test, feature = "test-support"))]
10697    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10698        self.breakpoint_store.clone()
10699    }
10700
10701    pub fn prepare_restore_change(
10702        &self,
10703        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10704        hunk: &MultiBufferDiffHunk,
10705        cx: &mut App,
10706    ) -> Option<()> {
10707        if hunk.is_created_file() {
10708            return None;
10709        }
10710        let buffer = self.buffer.read(cx);
10711        let diff = buffer.diff_for(hunk.buffer_id)?;
10712        let buffer = buffer.buffer(hunk.buffer_id)?;
10713        let buffer = buffer.read(cx);
10714        let original_text = diff
10715            .read(cx)
10716            .base_text()
10717            .as_rope()
10718            .slice(hunk.diff_base_byte_range.clone());
10719        let buffer_snapshot = buffer.snapshot();
10720        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10721        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10722            probe
10723                .0
10724                .start
10725                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10726                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10727        }) {
10728            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10729            Some(())
10730        } else {
10731            None
10732        }
10733    }
10734
10735    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10736        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10737    }
10738
10739    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10740        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10741    }
10742
10743    fn manipulate_lines<M>(
10744        &mut self,
10745        window: &mut Window,
10746        cx: &mut Context<Self>,
10747        mut manipulate: M,
10748    ) where
10749        M: FnMut(&str) -> LineManipulationResult,
10750    {
10751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10752
10753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10754        let buffer = self.buffer.read(cx).snapshot(cx);
10755
10756        let mut edits = Vec::new();
10757
10758        let selections = self.selections.all::<Point>(cx);
10759        let mut selections = selections.iter().peekable();
10760        let mut contiguous_row_selections = Vec::new();
10761        let mut new_selections = Vec::new();
10762        let mut added_lines = 0;
10763        let mut removed_lines = 0;
10764
10765        while let Some(selection) = selections.next() {
10766            let (start_row, end_row) = consume_contiguous_rows(
10767                &mut contiguous_row_selections,
10768                selection,
10769                &display_map,
10770                &mut selections,
10771            );
10772
10773            let start_point = Point::new(start_row.0, 0);
10774            let end_point = Point::new(
10775                end_row.previous_row().0,
10776                buffer.line_len(end_row.previous_row()),
10777            );
10778            let text = buffer
10779                .text_for_range(start_point..end_point)
10780                .collect::<String>();
10781
10782            let LineManipulationResult {
10783                new_text,
10784                line_count_before,
10785                line_count_after,
10786            } = manipulate(&text);
10787
10788            edits.push((start_point..end_point, new_text));
10789
10790            // Selections must change based on added and removed line count
10791            let start_row =
10792                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10793            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10794            new_selections.push(Selection {
10795                id: selection.id,
10796                start: start_row,
10797                end: end_row,
10798                goal: SelectionGoal::None,
10799                reversed: selection.reversed,
10800            });
10801
10802            if line_count_after > line_count_before {
10803                added_lines += line_count_after - line_count_before;
10804            } else if line_count_before > line_count_after {
10805                removed_lines += line_count_before - line_count_after;
10806            }
10807        }
10808
10809        self.transact(window, cx, |this, window, cx| {
10810            let buffer = this.buffer.update(cx, |buffer, cx| {
10811                buffer.edit(edits, None, cx);
10812                buffer.snapshot(cx)
10813            });
10814
10815            // Recalculate offsets on newly edited buffer
10816            let new_selections = new_selections
10817                .iter()
10818                .map(|s| {
10819                    let start_point = Point::new(s.start.0, 0);
10820                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10821                    Selection {
10822                        id: s.id,
10823                        start: buffer.point_to_offset(start_point),
10824                        end: buffer.point_to_offset(end_point),
10825                        goal: s.goal,
10826                        reversed: s.reversed,
10827                    }
10828                })
10829                .collect();
10830
10831            this.change_selections(Default::default(), window, cx, |s| {
10832                s.select(new_selections);
10833            });
10834
10835            this.request_autoscroll(Autoscroll::fit(), cx);
10836        });
10837    }
10838
10839    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10840        self.manipulate_text(window, cx, |text| {
10841            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10842            if has_upper_case_characters {
10843                text.to_lowercase()
10844            } else {
10845                text.to_uppercase()
10846            }
10847        })
10848    }
10849
10850    fn manipulate_immutable_lines<Fn>(
10851        &mut self,
10852        window: &mut Window,
10853        cx: &mut Context<Self>,
10854        mut callback: Fn,
10855    ) where
10856        Fn: FnMut(&mut Vec<&str>),
10857    {
10858        self.manipulate_lines(window, cx, |text| {
10859            let mut lines: Vec<&str> = text.split('\n').collect();
10860            let line_count_before = lines.len();
10861
10862            callback(&mut lines);
10863
10864            LineManipulationResult {
10865                new_text: lines.join("\n"),
10866                line_count_before,
10867                line_count_after: lines.len(),
10868            }
10869        });
10870    }
10871
10872    fn manipulate_mutable_lines<Fn>(
10873        &mut self,
10874        window: &mut Window,
10875        cx: &mut Context<Self>,
10876        mut callback: Fn,
10877    ) where
10878        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10879    {
10880        self.manipulate_lines(window, cx, |text| {
10881            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10882            let line_count_before = lines.len();
10883
10884            callback(&mut lines);
10885
10886            LineManipulationResult {
10887                new_text: lines.join("\n"),
10888                line_count_before,
10889                line_count_after: lines.len(),
10890            }
10891        });
10892    }
10893
10894    pub fn convert_indentation_to_spaces(
10895        &mut self,
10896        _: &ConvertIndentationToSpaces,
10897        window: &mut Window,
10898        cx: &mut Context<Self>,
10899    ) {
10900        let settings = self.buffer.read(cx).language_settings(cx);
10901        let tab_size = settings.tab_size.get() as usize;
10902
10903        self.manipulate_mutable_lines(window, cx, |lines| {
10904            // Allocates a reasonably sized scratch buffer once for the whole loop
10905            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10906            // Avoids recomputing spaces that could be inserted many times
10907            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10908                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10909                .collect();
10910
10911            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10912                let mut chars = line.as_ref().chars();
10913                let mut col = 0;
10914                let mut changed = false;
10915
10916                while let Some(ch) = chars.next() {
10917                    match ch {
10918                        ' ' => {
10919                            reindented_line.push(' ');
10920                            col += 1;
10921                        }
10922                        '\t' => {
10923                            // \t are converted to spaces depending on the current column
10924                            let spaces_len = tab_size - (col % tab_size);
10925                            reindented_line.extend(&space_cache[spaces_len - 1]);
10926                            col += spaces_len;
10927                            changed = true;
10928                        }
10929                        _ => {
10930                            // If we dont append before break, the character is consumed
10931                            reindented_line.push(ch);
10932                            break;
10933                        }
10934                    }
10935                }
10936
10937                if !changed {
10938                    reindented_line.clear();
10939                    continue;
10940                }
10941                // Append the rest of the line and replace old reference with new one
10942                reindented_line.extend(chars);
10943                *line = Cow::Owned(reindented_line.clone());
10944                reindented_line.clear();
10945            }
10946        });
10947    }
10948
10949    pub fn convert_indentation_to_tabs(
10950        &mut self,
10951        _: &ConvertIndentationToTabs,
10952        window: &mut Window,
10953        cx: &mut Context<Self>,
10954    ) {
10955        let settings = self.buffer.read(cx).language_settings(cx);
10956        let tab_size = settings.tab_size.get() as usize;
10957
10958        self.manipulate_mutable_lines(window, cx, |lines| {
10959            // Allocates a reasonably sized buffer once for the whole loop
10960            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10961            // Avoids recomputing spaces that could be inserted many times
10962            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10963                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10964                .collect();
10965
10966            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10967                let mut chars = line.chars();
10968                let mut spaces_count = 0;
10969                let mut first_non_indent_char = None;
10970                let mut changed = false;
10971
10972                while let Some(ch) = chars.next() {
10973                    match ch {
10974                        ' ' => {
10975                            // Keep track of spaces. Append \t when we reach tab_size
10976                            spaces_count += 1;
10977                            changed = true;
10978                            if spaces_count == tab_size {
10979                                reindented_line.push('\t');
10980                                spaces_count = 0;
10981                            }
10982                        }
10983                        '\t' => {
10984                            reindented_line.push('\t');
10985                            spaces_count = 0;
10986                        }
10987                        _ => {
10988                            // Dont append it yet, we might have remaining spaces
10989                            first_non_indent_char = Some(ch);
10990                            break;
10991                        }
10992                    }
10993                }
10994
10995                if !changed {
10996                    reindented_line.clear();
10997                    continue;
10998                }
10999                // Remaining spaces that didn't make a full tab stop
11000                if spaces_count > 0 {
11001                    reindented_line.extend(&space_cache[spaces_count - 1]);
11002                }
11003                // If we consume an extra character that was not indentation, add it back
11004                if let Some(extra_char) = first_non_indent_char {
11005                    reindented_line.push(extra_char);
11006                }
11007                // Append the rest of the line and replace old reference with new one
11008                reindented_line.extend(chars);
11009                *line = Cow::Owned(reindented_line.clone());
11010                reindented_line.clear();
11011            }
11012        });
11013    }
11014
11015    pub fn convert_to_upper_case(
11016        &mut self,
11017        _: &ConvertToUpperCase,
11018        window: &mut Window,
11019        cx: &mut Context<Self>,
11020    ) {
11021        self.manipulate_text(window, cx, |text| text.to_uppercase())
11022    }
11023
11024    pub fn convert_to_lower_case(
11025        &mut self,
11026        _: &ConvertToLowerCase,
11027        window: &mut Window,
11028        cx: &mut Context<Self>,
11029    ) {
11030        self.manipulate_text(window, cx, |text| text.to_lowercase())
11031    }
11032
11033    pub fn convert_to_title_case(
11034        &mut self,
11035        _: &ConvertToTitleCase,
11036        window: &mut Window,
11037        cx: &mut Context<Self>,
11038    ) {
11039        self.manipulate_text(window, cx, |text| {
11040            text.split('\n')
11041                .map(|line| line.to_case(Case::Title))
11042                .join("\n")
11043        })
11044    }
11045
11046    pub fn convert_to_snake_case(
11047        &mut self,
11048        _: &ConvertToSnakeCase,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11053    }
11054
11055    pub fn convert_to_kebab_case(
11056        &mut self,
11057        _: &ConvertToKebabCase,
11058        window: &mut Window,
11059        cx: &mut Context<Self>,
11060    ) {
11061        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11062    }
11063
11064    pub fn convert_to_upper_camel_case(
11065        &mut self,
11066        _: &ConvertToUpperCamelCase,
11067        window: &mut Window,
11068        cx: &mut Context<Self>,
11069    ) {
11070        self.manipulate_text(window, cx, |text| {
11071            text.split('\n')
11072                .map(|line| line.to_case(Case::UpperCamel))
11073                .join("\n")
11074        })
11075    }
11076
11077    pub fn convert_to_lower_camel_case(
11078        &mut self,
11079        _: &ConvertToLowerCamelCase,
11080        window: &mut Window,
11081        cx: &mut Context<Self>,
11082    ) {
11083        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11084    }
11085
11086    pub fn convert_to_opposite_case(
11087        &mut self,
11088        _: &ConvertToOppositeCase,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        self.manipulate_text(window, cx, |text| {
11093            text.chars()
11094                .fold(String::with_capacity(text.len()), |mut t, c| {
11095                    if c.is_uppercase() {
11096                        t.extend(c.to_lowercase());
11097                    } else {
11098                        t.extend(c.to_uppercase());
11099                    }
11100                    t
11101                })
11102        })
11103    }
11104
11105    pub fn convert_to_rot13(
11106        &mut self,
11107        _: &ConvertToRot13,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        self.manipulate_text(window, cx, |text| {
11112            text.chars()
11113                .map(|c| match c {
11114                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11115                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11116                    _ => c,
11117                })
11118                .collect()
11119        })
11120    }
11121
11122    pub fn convert_to_rot47(
11123        &mut self,
11124        _: &ConvertToRot47,
11125        window: &mut Window,
11126        cx: &mut Context<Self>,
11127    ) {
11128        self.manipulate_text(window, cx, |text| {
11129            text.chars()
11130                .map(|c| {
11131                    let code_point = c as u32;
11132                    if code_point >= 33 && code_point <= 126 {
11133                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11134                    }
11135                    c
11136                })
11137                .collect()
11138        })
11139    }
11140
11141    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11142    where
11143        Fn: FnMut(&str) -> String,
11144    {
11145        let buffer = self.buffer.read(cx).snapshot(cx);
11146
11147        let mut new_selections = Vec::new();
11148        let mut edits = Vec::new();
11149        let mut selection_adjustment = 0i32;
11150
11151        for selection in self.selections.all::<usize>(cx) {
11152            let selection_is_empty = selection.is_empty();
11153
11154            let (start, end) = if selection_is_empty {
11155                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11156                (word_range.start, word_range.end)
11157            } else {
11158                (selection.start, selection.end)
11159            };
11160
11161            let text = buffer.text_for_range(start..end).collect::<String>();
11162            let old_length = text.len() as i32;
11163            let text = callback(&text);
11164
11165            new_selections.push(Selection {
11166                start: (start as i32 - selection_adjustment) as usize,
11167                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11168                goal: SelectionGoal::None,
11169                ..selection
11170            });
11171
11172            selection_adjustment += old_length - text.len() as i32;
11173
11174            edits.push((start..end, text));
11175        }
11176
11177        self.transact(window, cx, |this, window, cx| {
11178            this.buffer.update(cx, |buffer, cx| {
11179                buffer.edit(edits, None, cx);
11180            });
11181
11182            this.change_selections(Default::default(), window, cx, |s| {
11183                s.select(new_selections);
11184            });
11185
11186            this.request_autoscroll(Autoscroll::fit(), cx);
11187        });
11188    }
11189
11190    pub fn move_selection_on_drop(
11191        &mut self,
11192        selection: &Selection<Anchor>,
11193        target: DisplayPoint,
11194        is_cut: bool,
11195        window: &mut Window,
11196        cx: &mut Context<Self>,
11197    ) {
11198        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11199        let buffer = &display_map.buffer_snapshot;
11200        let mut edits = Vec::new();
11201        let insert_point = display_map
11202            .clip_point(target, Bias::Left)
11203            .to_point(&display_map);
11204        let text = buffer
11205            .text_for_range(selection.start..selection.end)
11206            .collect::<String>();
11207        if is_cut {
11208            edits.push(((selection.start..selection.end), String::new()));
11209        }
11210        let insert_anchor = buffer.anchor_before(insert_point);
11211        edits.push(((insert_anchor..insert_anchor), text));
11212        let last_edit_start = insert_anchor.bias_left(buffer);
11213        let last_edit_end = insert_anchor.bias_right(buffer);
11214        self.transact(window, cx, |this, window, cx| {
11215            this.buffer.update(cx, |buffer, cx| {
11216                buffer.edit(edits, None, cx);
11217            });
11218            this.change_selections(Default::default(), window, cx, |s| {
11219                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11220            });
11221        });
11222    }
11223
11224    pub fn clear_selection_drag_state(&mut self) {
11225        self.selection_drag_state = SelectionDragState::None;
11226    }
11227
11228    pub fn duplicate(
11229        &mut self,
11230        upwards: bool,
11231        whole_lines: bool,
11232        window: &mut Window,
11233        cx: &mut Context<Self>,
11234    ) {
11235        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11236
11237        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11238        let buffer = &display_map.buffer_snapshot;
11239        let selections = self.selections.all::<Point>(cx);
11240
11241        let mut edits = Vec::new();
11242        let mut selections_iter = selections.iter().peekable();
11243        while let Some(selection) = selections_iter.next() {
11244            let mut rows = selection.spanned_rows(false, &display_map);
11245            // duplicate line-wise
11246            if whole_lines || selection.start == selection.end {
11247                // Avoid duplicating the same lines twice.
11248                while let Some(next_selection) = selections_iter.peek() {
11249                    let next_rows = next_selection.spanned_rows(false, &display_map);
11250                    if next_rows.start < rows.end {
11251                        rows.end = next_rows.end;
11252                        selections_iter.next().unwrap();
11253                    } else {
11254                        break;
11255                    }
11256                }
11257
11258                // Copy the text from the selected row region and splice it either at the start
11259                // or end of the region.
11260                let start = Point::new(rows.start.0, 0);
11261                let end = Point::new(
11262                    rows.end.previous_row().0,
11263                    buffer.line_len(rows.end.previous_row()),
11264                );
11265                let text = buffer
11266                    .text_for_range(start..end)
11267                    .chain(Some("\n"))
11268                    .collect::<String>();
11269                let insert_location = if upwards {
11270                    Point::new(rows.end.0, 0)
11271                } else {
11272                    start
11273                };
11274                edits.push((insert_location..insert_location, text));
11275            } else {
11276                // duplicate character-wise
11277                let start = selection.start;
11278                let end = selection.end;
11279                let text = buffer.text_for_range(start..end).collect::<String>();
11280                edits.push((selection.end..selection.end, text));
11281            }
11282        }
11283
11284        self.transact(window, cx, |this, _, cx| {
11285            this.buffer.update(cx, |buffer, cx| {
11286                buffer.edit(edits, None, cx);
11287            });
11288
11289            this.request_autoscroll(Autoscroll::fit(), cx);
11290        });
11291    }
11292
11293    pub fn duplicate_line_up(
11294        &mut self,
11295        _: &DuplicateLineUp,
11296        window: &mut Window,
11297        cx: &mut Context<Self>,
11298    ) {
11299        self.duplicate(true, true, window, cx);
11300    }
11301
11302    pub fn duplicate_line_down(
11303        &mut self,
11304        _: &DuplicateLineDown,
11305        window: &mut Window,
11306        cx: &mut Context<Self>,
11307    ) {
11308        self.duplicate(false, true, window, cx);
11309    }
11310
11311    pub fn duplicate_selection(
11312        &mut self,
11313        _: &DuplicateSelection,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        self.duplicate(false, false, window, cx);
11318    }
11319
11320    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11321        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11322        if self.mode.is_single_line() {
11323            cx.propagate();
11324            return;
11325        }
11326
11327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11328        let buffer = self.buffer.read(cx).snapshot(cx);
11329
11330        let mut edits = Vec::new();
11331        let mut unfold_ranges = Vec::new();
11332        let mut refold_creases = Vec::new();
11333
11334        let selections = self.selections.all::<Point>(cx);
11335        let mut selections = selections.iter().peekable();
11336        let mut contiguous_row_selections = Vec::new();
11337        let mut new_selections = Vec::new();
11338
11339        while let Some(selection) = selections.next() {
11340            // Find all the selections that span a contiguous row range
11341            let (start_row, end_row) = consume_contiguous_rows(
11342                &mut contiguous_row_selections,
11343                selection,
11344                &display_map,
11345                &mut selections,
11346            );
11347
11348            // Move the text spanned by the row range to be before the line preceding the row range
11349            if start_row.0 > 0 {
11350                let range_to_move = Point::new(
11351                    start_row.previous_row().0,
11352                    buffer.line_len(start_row.previous_row()),
11353                )
11354                    ..Point::new(
11355                        end_row.previous_row().0,
11356                        buffer.line_len(end_row.previous_row()),
11357                    );
11358                let insertion_point = display_map
11359                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11360                    .0;
11361
11362                // Don't move lines across excerpts
11363                if buffer
11364                    .excerpt_containing(insertion_point..range_to_move.end)
11365                    .is_some()
11366                {
11367                    let text = buffer
11368                        .text_for_range(range_to_move.clone())
11369                        .flat_map(|s| s.chars())
11370                        .skip(1)
11371                        .chain(['\n'])
11372                        .collect::<String>();
11373
11374                    edits.push((
11375                        buffer.anchor_after(range_to_move.start)
11376                            ..buffer.anchor_before(range_to_move.end),
11377                        String::new(),
11378                    ));
11379                    let insertion_anchor = buffer.anchor_after(insertion_point);
11380                    edits.push((insertion_anchor..insertion_anchor, text));
11381
11382                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11383
11384                    // Move selections up
11385                    new_selections.extend(contiguous_row_selections.drain(..).map(
11386                        |mut selection| {
11387                            selection.start.row -= row_delta;
11388                            selection.end.row -= row_delta;
11389                            selection
11390                        },
11391                    ));
11392
11393                    // Move folds up
11394                    unfold_ranges.push(range_to_move.clone());
11395                    for fold in display_map.folds_in_range(
11396                        buffer.anchor_before(range_to_move.start)
11397                            ..buffer.anchor_after(range_to_move.end),
11398                    ) {
11399                        let mut start = fold.range.start.to_point(&buffer);
11400                        let mut end = fold.range.end.to_point(&buffer);
11401                        start.row -= row_delta;
11402                        end.row -= row_delta;
11403                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11404                    }
11405                }
11406            }
11407
11408            // If we didn't move line(s), preserve the existing selections
11409            new_selections.append(&mut contiguous_row_selections);
11410        }
11411
11412        self.transact(window, cx, |this, window, cx| {
11413            this.unfold_ranges(&unfold_ranges, true, true, cx);
11414            this.buffer.update(cx, |buffer, cx| {
11415                for (range, text) in edits {
11416                    buffer.edit([(range, text)], None, cx);
11417                }
11418            });
11419            this.fold_creases(refold_creases, true, window, cx);
11420            this.change_selections(Default::default(), window, cx, |s| {
11421                s.select(new_selections);
11422            })
11423        });
11424    }
11425
11426    pub fn move_line_down(
11427        &mut self,
11428        _: &MoveLineDown,
11429        window: &mut Window,
11430        cx: &mut Context<Self>,
11431    ) {
11432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11433        if self.mode.is_single_line() {
11434            cx.propagate();
11435            return;
11436        }
11437
11438        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11439        let buffer = self.buffer.read(cx).snapshot(cx);
11440
11441        let mut edits = Vec::new();
11442        let mut unfold_ranges = Vec::new();
11443        let mut refold_creases = Vec::new();
11444
11445        let selections = self.selections.all::<Point>(cx);
11446        let mut selections = selections.iter().peekable();
11447        let mut contiguous_row_selections = Vec::new();
11448        let mut new_selections = Vec::new();
11449
11450        while let Some(selection) = selections.next() {
11451            // Find all the selections that span a contiguous row range
11452            let (start_row, end_row) = consume_contiguous_rows(
11453                &mut contiguous_row_selections,
11454                selection,
11455                &display_map,
11456                &mut selections,
11457            );
11458
11459            // Move the text spanned by the row range to be after the last line of the row range
11460            if end_row.0 <= buffer.max_point().row {
11461                let range_to_move =
11462                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11463                let insertion_point = display_map
11464                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11465                    .0;
11466
11467                // Don't move lines across excerpt boundaries
11468                if buffer
11469                    .excerpt_containing(range_to_move.start..insertion_point)
11470                    .is_some()
11471                {
11472                    let mut text = String::from("\n");
11473                    text.extend(buffer.text_for_range(range_to_move.clone()));
11474                    text.pop(); // Drop trailing newline
11475                    edits.push((
11476                        buffer.anchor_after(range_to_move.start)
11477                            ..buffer.anchor_before(range_to_move.end),
11478                        String::new(),
11479                    ));
11480                    let insertion_anchor = buffer.anchor_after(insertion_point);
11481                    edits.push((insertion_anchor..insertion_anchor, text));
11482
11483                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11484
11485                    // Move selections down
11486                    new_selections.extend(contiguous_row_selections.drain(..).map(
11487                        |mut selection| {
11488                            selection.start.row += row_delta;
11489                            selection.end.row += row_delta;
11490                            selection
11491                        },
11492                    ));
11493
11494                    // Move folds down
11495                    unfold_ranges.push(range_to_move.clone());
11496                    for fold in display_map.folds_in_range(
11497                        buffer.anchor_before(range_to_move.start)
11498                            ..buffer.anchor_after(range_to_move.end),
11499                    ) {
11500                        let mut start = fold.range.start.to_point(&buffer);
11501                        let mut end = fold.range.end.to_point(&buffer);
11502                        start.row += row_delta;
11503                        end.row += row_delta;
11504                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11505                    }
11506                }
11507            }
11508
11509            // If we didn't move line(s), preserve the existing selections
11510            new_selections.append(&mut contiguous_row_selections);
11511        }
11512
11513        self.transact(window, cx, |this, window, cx| {
11514            this.unfold_ranges(&unfold_ranges, true, true, cx);
11515            this.buffer.update(cx, |buffer, cx| {
11516                for (range, text) in edits {
11517                    buffer.edit([(range, text)], None, cx);
11518                }
11519            });
11520            this.fold_creases(refold_creases, true, window, cx);
11521            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11522        });
11523    }
11524
11525    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11527        let text_layout_details = &self.text_layout_details(window);
11528        self.transact(window, cx, |this, window, cx| {
11529            let edits = this.change_selections(Default::default(), window, cx, |s| {
11530                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11531                s.move_with(|display_map, selection| {
11532                    if !selection.is_empty() {
11533                        return;
11534                    }
11535
11536                    let mut head = selection.head();
11537                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11538                    if head.column() == display_map.line_len(head.row()) {
11539                        transpose_offset = display_map
11540                            .buffer_snapshot
11541                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11542                    }
11543
11544                    if transpose_offset == 0 {
11545                        return;
11546                    }
11547
11548                    *head.column_mut() += 1;
11549                    head = display_map.clip_point(head, Bias::Right);
11550                    let goal = SelectionGoal::HorizontalPosition(
11551                        display_map
11552                            .x_for_display_point(head, text_layout_details)
11553                            .into(),
11554                    );
11555                    selection.collapse_to(head, goal);
11556
11557                    let transpose_start = display_map
11558                        .buffer_snapshot
11559                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11560                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11561                        let transpose_end = display_map
11562                            .buffer_snapshot
11563                            .clip_offset(transpose_offset + 1, Bias::Right);
11564                        if let Some(ch) =
11565                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11566                        {
11567                            edits.push((transpose_start..transpose_offset, String::new()));
11568                            edits.push((transpose_end..transpose_end, ch.to_string()));
11569                        }
11570                    }
11571                });
11572                edits
11573            });
11574            this.buffer
11575                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11576            let selections = this.selections.all::<usize>(cx);
11577            this.change_selections(Default::default(), window, cx, |s| {
11578                s.select(selections);
11579            });
11580        });
11581    }
11582
11583    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11584        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11585        if self.mode.is_single_line() {
11586            cx.propagate();
11587            return;
11588        }
11589
11590        self.rewrap_impl(RewrapOptions::default(), cx)
11591    }
11592
11593    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11594        let buffer = self.buffer.read(cx).snapshot(cx);
11595        let selections = self.selections.all::<Point>(cx);
11596
11597        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11598        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11599            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11600                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11601                .peekable();
11602
11603            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11604                row
11605            } else {
11606                return Vec::new();
11607            };
11608
11609            let language_settings = buffer.language_settings_at(selection.head(), cx);
11610            let language_scope = buffer.language_scope_at(selection.head());
11611
11612            let indent_and_prefix_for_row =
11613                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11614                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11615                    let (comment_prefix, rewrap_prefix) =
11616                        if let Some(language_scope) = &language_scope {
11617                            let indent_end = Point::new(row, indent.len);
11618                            let comment_prefix = language_scope
11619                                .line_comment_prefixes()
11620                                .iter()
11621                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11622                                .map(|prefix| prefix.to_string());
11623                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11624                            let line_text_after_indent = buffer
11625                                .text_for_range(indent_end..line_end)
11626                                .collect::<String>();
11627                            let rewrap_prefix = language_scope
11628                                .rewrap_prefixes()
11629                                .iter()
11630                                .find_map(|prefix_regex| {
11631                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11632                                        if mat.start() == 0 {
11633                                            Some(mat.as_str().to_string())
11634                                        } else {
11635                                            None
11636                                        }
11637                                    })
11638                                })
11639                                .flatten();
11640                            (comment_prefix, rewrap_prefix)
11641                        } else {
11642                            (None, None)
11643                        };
11644                    (indent, comment_prefix, rewrap_prefix)
11645                };
11646
11647            let mut ranges = Vec::new();
11648            let from_empty_selection = selection.is_empty();
11649
11650            let mut current_range_start = first_row;
11651            let mut prev_row = first_row;
11652            let (
11653                mut current_range_indent,
11654                mut current_range_comment_prefix,
11655                mut current_range_rewrap_prefix,
11656            ) = indent_and_prefix_for_row(first_row);
11657
11658            for row in non_blank_rows_iter.skip(1) {
11659                let has_paragraph_break = row > prev_row + 1;
11660
11661                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11662                    indent_and_prefix_for_row(row);
11663
11664                let has_indent_change = row_indent != current_range_indent;
11665                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11666
11667                let has_boundary_change = has_comment_change
11668                    || row_rewrap_prefix.is_some()
11669                    || (has_indent_change && current_range_comment_prefix.is_some());
11670
11671                if has_paragraph_break || has_boundary_change {
11672                    ranges.push((
11673                        language_settings.clone(),
11674                        Point::new(current_range_start, 0)
11675                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11676                        current_range_indent,
11677                        current_range_comment_prefix.clone(),
11678                        current_range_rewrap_prefix.clone(),
11679                        from_empty_selection,
11680                    ));
11681                    current_range_start = row;
11682                    current_range_indent = row_indent;
11683                    current_range_comment_prefix = row_comment_prefix;
11684                    current_range_rewrap_prefix = row_rewrap_prefix;
11685                }
11686                prev_row = row;
11687            }
11688
11689            ranges.push((
11690                language_settings.clone(),
11691                Point::new(current_range_start, 0)
11692                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11693                current_range_indent,
11694                current_range_comment_prefix,
11695                current_range_rewrap_prefix,
11696                from_empty_selection,
11697            ));
11698
11699            ranges
11700        });
11701
11702        let mut edits = Vec::new();
11703        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11704
11705        for (
11706            language_settings,
11707            wrap_range,
11708            indent_size,
11709            comment_prefix,
11710            rewrap_prefix,
11711            from_empty_selection,
11712        ) in wrap_ranges
11713        {
11714            let mut start_row = wrap_range.start.row;
11715            let mut end_row = wrap_range.end.row;
11716
11717            // Skip selections that overlap with a range that has already been rewrapped.
11718            let selection_range = start_row..end_row;
11719            if rewrapped_row_ranges
11720                .iter()
11721                .any(|range| range.overlaps(&selection_range))
11722            {
11723                continue;
11724            }
11725
11726            let tab_size = language_settings.tab_size;
11727
11728            let indent_prefix = indent_size.chars().collect::<String>();
11729            let mut line_prefix = indent_prefix.clone();
11730            let mut inside_comment = false;
11731            if let Some(prefix) = &comment_prefix {
11732                line_prefix.push_str(prefix);
11733                inside_comment = true;
11734            }
11735            if let Some(prefix) = &rewrap_prefix {
11736                line_prefix.push_str(prefix);
11737            }
11738
11739            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11740                RewrapBehavior::InComments => inside_comment,
11741                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11742                RewrapBehavior::Anywhere => true,
11743            };
11744
11745            let should_rewrap = options.override_language_settings
11746                || allow_rewrap_based_on_language
11747                || self.hard_wrap.is_some();
11748            if !should_rewrap {
11749                continue;
11750            }
11751
11752            if from_empty_selection {
11753                'expand_upwards: while start_row > 0 {
11754                    let prev_row = start_row - 1;
11755                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11756                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11757                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11758                    {
11759                        start_row = prev_row;
11760                    } else {
11761                        break 'expand_upwards;
11762                    }
11763                }
11764
11765                'expand_downwards: while end_row < buffer.max_point().row {
11766                    let next_row = end_row + 1;
11767                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11768                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11769                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11770                    {
11771                        end_row = next_row;
11772                    } else {
11773                        break 'expand_downwards;
11774                    }
11775                }
11776            }
11777
11778            let start = Point::new(start_row, 0);
11779            let start_offset = start.to_offset(&buffer);
11780            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11781            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11782            let Some(lines_without_prefixes) = selection_text
11783                .lines()
11784                .enumerate()
11785                .map(|(ix, line)| {
11786                    let line_trimmed = line.trim_start();
11787                    if rewrap_prefix.is_some() && ix > 0 {
11788                        Ok(line_trimmed)
11789                    } else {
11790                        line_trimmed
11791                            .strip_prefix(&line_prefix.trim_start())
11792                            .with_context(|| {
11793                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11794                            })
11795                    }
11796                })
11797                .collect::<Result<Vec<_>, _>>()
11798                .log_err()
11799            else {
11800                continue;
11801            };
11802
11803            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11804                buffer
11805                    .language_settings_at(Point::new(start_row, 0), cx)
11806                    .preferred_line_length as usize
11807            });
11808
11809            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11810                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11811            } else {
11812                line_prefix.clone()
11813            };
11814
11815            let wrapped_text = wrap_with_prefix(
11816                line_prefix,
11817                subsequent_lines_prefix,
11818                lines_without_prefixes.join("\n"),
11819                wrap_column,
11820                tab_size,
11821                options.preserve_existing_whitespace,
11822            );
11823
11824            // TODO: should always use char-based diff while still supporting cursor behavior that
11825            // matches vim.
11826            let mut diff_options = DiffOptions::default();
11827            if options.override_language_settings {
11828                diff_options.max_word_diff_len = 0;
11829                diff_options.max_word_diff_line_count = 0;
11830            } else {
11831                diff_options.max_word_diff_len = usize::MAX;
11832                diff_options.max_word_diff_line_count = usize::MAX;
11833            }
11834
11835            for (old_range, new_text) in
11836                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11837            {
11838                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11839                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11840                edits.push((edit_start..edit_end, new_text));
11841            }
11842
11843            rewrapped_row_ranges.push(start_row..=end_row);
11844        }
11845
11846        self.buffer
11847            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11848    }
11849
11850    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11851        let mut text = String::new();
11852        let buffer = self.buffer.read(cx).snapshot(cx);
11853        let mut selections = self.selections.all::<Point>(cx);
11854        let mut clipboard_selections = Vec::with_capacity(selections.len());
11855        {
11856            let max_point = buffer.max_point();
11857            let mut is_first = true;
11858            for selection in &mut selections {
11859                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11860                if is_entire_line {
11861                    selection.start = Point::new(selection.start.row, 0);
11862                    if !selection.is_empty() && selection.end.column == 0 {
11863                        selection.end = cmp::min(max_point, selection.end);
11864                    } else {
11865                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11866                    }
11867                    selection.goal = SelectionGoal::None;
11868                }
11869                if is_first {
11870                    is_first = false;
11871                } else {
11872                    text += "\n";
11873                }
11874                let mut len = 0;
11875                for chunk in buffer.text_for_range(selection.start..selection.end) {
11876                    text.push_str(chunk);
11877                    len += chunk.len();
11878                }
11879                clipboard_selections.push(ClipboardSelection {
11880                    len,
11881                    is_entire_line,
11882                    first_line_indent: buffer
11883                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11884                        .len,
11885                });
11886            }
11887        }
11888
11889        self.transact(window, cx, |this, window, cx| {
11890            this.change_selections(Default::default(), window, cx, |s| {
11891                s.select(selections);
11892            });
11893            this.insert("", window, cx);
11894        });
11895        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11896    }
11897
11898    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11900        let item = self.cut_common(window, cx);
11901        cx.write_to_clipboard(item);
11902    }
11903
11904    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11905        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11906        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11907            s.move_with(|snapshot, sel| {
11908                if sel.is_empty() {
11909                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11910                }
11911            });
11912        });
11913        let item = self.cut_common(window, cx);
11914        cx.set_global(KillRing(item))
11915    }
11916
11917    pub fn kill_ring_yank(
11918        &mut self,
11919        _: &KillRingYank,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) {
11923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11924        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11925            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11926                (kill_ring.text().to_string(), kill_ring.metadata_json())
11927            } else {
11928                return;
11929            }
11930        } else {
11931            return;
11932        };
11933        self.do_paste(&text, metadata, false, window, cx);
11934    }
11935
11936    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11937        self.do_copy(true, cx);
11938    }
11939
11940    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11941        self.do_copy(false, cx);
11942    }
11943
11944    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11945        let selections = self.selections.all::<Point>(cx);
11946        let buffer = self.buffer.read(cx).read(cx);
11947        let mut text = String::new();
11948
11949        let mut clipboard_selections = Vec::with_capacity(selections.len());
11950        {
11951            let max_point = buffer.max_point();
11952            let mut is_first = true;
11953            for selection in &selections {
11954                let mut start = selection.start;
11955                let mut end = selection.end;
11956                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11957                if is_entire_line {
11958                    start = Point::new(start.row, 0);
11959                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11960                }
11961
11962                let mut trimmed_selections = Vec::new();
11963                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11964                    let row = MultiBufferRow(start.row);
11965                    let first_indent = buffer.indent_size_for_line(row);
11966                    if first_indent.len == 0 || start.column > first_indent.len {
11967                        trimmed_selections.push(start..end);
11968                    } else {
11969                        trimmed_selections.push(
11970                            Point::new(row.0, first_indent.len)
11971                                ..Point::new(row.0, buffer.line_len(row)),
11972                        );
11973                        for row in start.row + 1..=end.row {
11974                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11975                            if row == end.row {
11976                                line_len = end.column;
11977                            }
11978                            if line_len == 0 {
11979                                trimmed_selections
11980                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11981                                continue;
11982                            }
11983                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11984                            if row_indent_size.len >= first_indent.len {
11985                                trimmed_selections.push(
11986                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11987                                );
11988                            } else {
11989                                trimmed_selections.clear();
11990                                trimmed_selections.push(start..end);
11991                                break;
11992                            }
11993                        }
11994                    }
11995                } else {
11996                    trimmed_selections.push(start..end);
11997                }
11998
11999                for trimmed_range in trimmed_selections {
12000                    if is_first {
12001                        is_first = false;
12002                    } else {
12003                        text += "\n";
12004                    }
12005                    let mut len = 0;
12006                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12007                        text.push_str(chunk);
12008                        len += chunk.len();
12009                    }
12010                    clipboard_selections.push(ClipboardSelection {
12011                        len,
12012                        is_entire_line,
12013                        first_line_indent: buffer
12014                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12015                            .len,
12016                    });
12017                }
12018            }
12019        }
12020
12021        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12022            text,
12023            clipboard_selections,
12024        ));
12025    }
12026
12027    pub fn do_paste(
12028        &mut self,
12029        text: &String,
12030        clipboard_selections: Option<Vec<ClipboardSelection>>,
12031        handle_entire_lines: bool,
12032        window: &mut Window,
12033        cx: &mut Context<Self>,
12034    ) {
12035        if self.read_only(cx) {
12036            return;
12037        }
12038
12039        let clipboard_text = Cow::Borrowed(text);
12040
12041        self.transact(window, cx, |this, window, cx| {
12042            if let Some(mut clipboard_selections) = clipboard_selections {
12043                let old_selections = this.selections.all::<usize>(cx);
12044                let all_selections_were_entire_line =
12045                    clipboard_selections.iter().all(|s| s.is_entire_line);
12046                let first_selection_indent_column =
12047                    clipboard_selections.first().map(|s| s.first_line_indent);
12048                if clipboard_selections.len() != old_selections.len() {
12049                    clipboard_selections.drain(..);
12050                }
12051                let cursor_offset = this.selections.last::<usize>(cx).head();
12052                let mut auto_indent_on_paste = true;
12053
12054                this.buffer.update(cx, |buffer, cx| {
12055                    let snapshot = buffer.read(cx);
12056                    auto_indent_on_paste = snapshot
12057                        .language_settings_at(cursor_offset, cx)
12058                        .auto_indent_on_paste;
12059
12060                    let mut start_offset = 0;
12061                    let mut edits = Vec::new();
12062                    let mut original_indent_columns = Vec::new();
12063                    for (ix, selection) in old_selections.iter().enumerate() {
12064                        let to_insert;
12065                        let entire_line;
12066                        let original_indent_column;
12067                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12068                            let end_offset = start_offset + clipboard_selection.len;
12069                            to_insert = &clipboard_text[start_offset..end_offset];
12070                            entire_line = clipboard_selection.is_entire_line;
12071                            start_offset = end_offset + 1;
12072                            original_indent_column = Some(clipboard_selection.first_line_indent);
12073                        } else {
12074                            to_insert = clipboard_text.as_str();
12075                            entire_line = all_selections_were_entire_line;
12076                            original_indent_column = first_selection_indent_column
12077                        }
12078
12079                        // If the corresponding selection was empty when this slice of the
12080                        // clipboard text was written, then the entire line containing the
12081                        // selection was copied. If this selection is also currently empty,
12082                        // then paste the line before the current line of the buffer.
12083                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12084                            let column = selection.start.to_point(&snapshot).column as usize;
12085                            let line_start = selection.start - column;
12086                            line_start..line_start
12087                        } else {
12088                            selection.range()
12089                        };
12090
12091                        edits.push((range, to_insert));
12092                        original_indent_columns.push(original_indent_column);
12093                    }
12094                    drop(snapshot);
12095
12096                    buffer.edit(
12097                        edits,
12098                        if auto_indent_on_paste {
12099                            Some(AutoindentMode::Block {
12100                                original_indent_columns,
12101                            })
12102                        } else {
12103                            None
12104                        },
12105                        cx,
12106                    );
12107                });
12108
12109                let selections = this.selections.all::<usize>(cx);
12110                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12111            } else {
12112                this.insert(&clipboard_text, window, cx);
12113            }
12114        });
12115    }
12116
12117    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12119        if let Some(item) = cx.read_from_clipboard() {
12120            let entries = item.entries();
12121
12122            match entries.first() {
12123                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12124                // of all the pasted entries.
12125                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12126                    .do_paste(
12127                        clipboard_string.text(),
12128                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12129                        true,
12130                        window,
12131                        cx,
12132                    ),
12133                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12134            }
12135        }
12136    }
12137
12138    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12139        if self.read_only(cx) {
12140            return;
12141        }
12142
12143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12144
12145        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12146            if let Some((selections, _)) =
12147                self.selection_history.transaction(transaction_id).cloned()
12148            {
12149                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12150                    s.select_anchors(selections.to_vec());
12151                });
12152            } else {
12153                log::error!(
12154                    "No entry in selection_history found for undo. \
12155                     This may correspond to a bug where undo does not update the selection. \
12156                     If this is occurring, please add details to \
12157                     https://github.com/zed-industries/zed/issues/22692"
12158                );
12159            }
12160            self.request_autoscroll(Autoscroll::fit(), cx);
12161            self.unmark_text(window, cx);
12162            self.refresh_inline_completion(true, false, window, cx);
12163            cx.emit(EditorEvent::Edited { transaction_id });
12164            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12165        }
12166    }
12167
12168    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12169        if self.read_only(cx) {
12170            return;
12171        }
12172
12173        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12174
12175        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12176            if let Some((_, Some(selections))) =
12177                self.selection_history.transaction(transaction_id).cloned()
12178            {
12179                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12180                    s.select_anchors(selections.to_vec());
12181                });
12182            } else {
12183                log::error!(
12184                    "No entry in selection_history found for redo. \
12185                     This may correspond to a bug where undo does not update the selection. \
12186                     If this is occurring, please add details to \
12187                     https://github.com/zed-industries/zed/issues/22692"
12188                );
12189            }
12190            self.request_autoscroll(Autoscroll::fit(), cx);
12191            self.unmark_text(window, cx);
12192            self.refresh_inline_completion(true, false, window, cx);
12193            cx.emit(EditorEvent::Edited { transaction_id });
12194        }
12195    }
12196
12197    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12198        self.buffer
12199            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12200    }
12201
12202    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12203        self.buffer
12204            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12205    }
12206
12207    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12208        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12209        self.change_selections(Default::default(), window, cx, |s| {
12210            s.move_with(|map, selection| {
12211                let cursor = if selection.is_empty() {
12212                    movement::left(map, selection.start)
12213                } else {
12214                    selection.start
12215                };
12216                selection.collapse_to(cursor, SelectionGoal::None);
12217            });
12218        })
12219    }
12220
12221    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12222        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12223        self.change_selections(Default::default(), window, cx, |s| {
12224            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12225        })
12226    }
12227
12228    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12229        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12230        self.change_selections(Default::default(), window, cx, |s| {
12231            s.move_with(|map, selection| {
12232                let cursor = if selection.is_empty() {
12233                    movement::right(map, selection.end)
12234                } else {
12235                    selection.end
12236                };
12237                selection.collapse_to(cursor, SelectionGoal::None)
12238            });
12239        })
12240    }
12241
12242    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12244        self.change_selections(Default::default(), window, cx, |s| {
12245            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12246        })
12247    }
12248
12249    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12250        if self.take_rename(true, window, cx).is_some() {
12251            return;
12252        }
12253
12254        if self.mode.is_single_line() {
12255            cx.propagate();
12256            return;
12257        }
12258
12259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12260
12261        let text_layout_details = &self.text_layout_details(window);
12262        let selection_count = self.selections.count();
12263        let first_selection = self.selections.first_anchor();
12264
12265        self.change_selections(Default::default(), window, cx, |s| {
12266            s.move_with(|map, selection| {
12267                if !selection.is_empty() {
12268                    selection.goal = SelectionGoal::None;
12269                }
12270                let (cursor, goal) = movement::up(
12271                    map,
12272                    selection.start,
12273                    selection.goal,
12274                    false,
12275                    text_layout_details,
12276                );
12277                selection.collapse_to(cursor, goal);
12278            });
12279        });
12280
12281        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12282        {
12283            cx.propagate();
12284        }
12285    }
12286
12287    pub fn move_up_by_lines(
12288        &mut self,
12289        action: &MoveUpByLines,
12290        window: &mut Window,
12291        cx: &mut Context<Self>,
12292    ) {
12293        if self.take_rename(true, window, cx).is_some() {
12294            return;
12295        }
12296
12297        if self.mode.is_single_line() {
12298            cx.propagate();
12299            return;
12300        }
12301
12302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12303
12304        let text_layout_details = &self.text_layout_details(window);
12305
12306        self.change_selections(Default::default(), window, cx, |s| {
12307            s.move_with(|map, selection| {
12308                if !selection.is_empty() {
12309                    selection.goal = SelectionGoal::None;
12310                }
12311                let (cursor, goal) = movement::up_by_rows(
12312                    map,
12313                    selection.start,
12314                    action.lines,
12315                    selection.goal,
12316                    false,
12317                    text_layout_details,
12318                );
12319                selection.collapse_to(cursor, goal);
12320            });
12321        })
12322    }
12323
12324    pub fn move_down_by_lines(
12325        &mut self,
12326        action: &MoveDownByLines,
12327        window: &mut Window,
12328        cx: &mut Context<Self>,
12329    ) {
12330        if self.take_rename(true, window, cx).is_some() {
12331            return;
12332        }
12333
12334        if self.mode.is_single_line() {
12335            cx.propagate();
12336            return;
12337        }
12338
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12340
12341        let text_layout_details = &self.text_layout_details(window);
12342
12343        self.change_selections(Default::default(), window, cx, |s| {
12344            s.move_with(|map, selection| {
12345                if !selection.is_empty() {
12346                    selection.goal = SelectionGoal::None;
12347                }
12348                let (cursor, goal) = movement::down_by_rows(
12349                    map,
12350                    selection.start,
12351                    action.lines,
12352                    selection.goal,
12353                    false,
12354                    text_layout_details,
12355                );
12356                selection.collapse_to(cursor, goal);
12357            });
12358        })
12359    }
12360
12361    pub fn select_down_by_lines(
12362        &mut self,
12363        action: &SelectDownByLines,
12364        window: &mut Window,
12365        cx: &mut Context<Self>,
12366    ) {
12367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12368        let text_layout_details = &self.text_layout_details(window);
12369        self.change_selections(Default::default(), window, cx, |s| {
12370            s.move_heads_with(|map, head, goal| {
12371                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12372            })
12373        })
12374    }
12375
12376    pub fn select_up_by_lines(
12377        &mut self,
12378        action: &SelectUpByLines,
12379        window: &mut Window,
12380        cx: &mut Context<Self>,
12381    ) {
12382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12383        let text_layout_details = &self.text_layout_details(window);
12384        self.change_selections(Default::default(), window, cx, |s| {
12385            s.move_heads_with(|map, head, goal| {
12386                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12387            })
12388        })
12389    }
12390
12391    pub fn select_page_up(
12392        &mut self,
12393        _: &SelectPageUp,
12394        window: &mut Window,
12395        cx: &mut Context<Self>,
12396    ) {
12397        let Some(row_count) = self.visible_row_count() else {
12398            return;
12399        };
12400
12401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12402
12403        let text_layout_details = &self.text_layout_details(window);
12404
12405        self.change_selections(Default::default(), window, cx, |s| {
12406            s.move_heads_with(|map, head, goal| {
12407                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12408            })
12409        })
12410    }
12411
12412    pub fn move_page_up(
12413        &mut self,
12414        action: &MovePageUp,
12415        window: &mut Window,
12416        cx: &mut Context<Self>,
12417    ) {
12418        if self.take_rename(true, window, cx).is_some() {
12419            return;
12420        }
12421
12422        if self
12423            .context_menu
12424            .borrow_mut()
12425            .as_mut()
12426            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12427            .unwrap_or(false)
12428        {
12429            return;
12430        }
12431
12432        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12433            cx.propagate();
12434            return;
12435        }
12436
12437        let Some(row_count) = self.visible_row_count() else {
12438            return;
12439        };
12440
12441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12442
12443        let effects = if action.center_cursor {
12444            SelectionEffects::scroll(Autoscroll::center())
12445        } else {
12446            SelectionEffects::default()
12447        };
12448
12449        let text_layout_details = &self.text_layout_details(window);
12450
12451        self.change_selections(effects, window, cx, |s| {
12452            s.move_with(|map, selection| {
12453                if !selection.is_empty() {
12454                    selection.goal = SelectionGoal::None;
12455                }
12456                let (cursor, goal) = movement::up_by_rows(
12457                    map,
12458                    selection.end,
12459                    row_count,
12460                    selection.goal,
12461                    false,
12462                    text_layout_details,
12463                );
12464                selection.collapse_to(cursor, goal);
12465            });
12466        });
12467    }
12468
12469    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12471        let text_layout_details = &self.text_layout_details(window);
12472        self.change_selections(Default::default(), window, cx, |s| {
12473            s.move_heads_with(|map, head, goal| {
12474                movement::up(map, head, goal, false, text_layout_details)
12475            })
12476        })
12477    }
12478
12479    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12480        self.take_rename(true, window, cx);
12481
12482        if self.mode.is_single_line() {
12483            cx.propagate();
12484            return;
12485        }
12486
12487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12488
12489        let text_layout_details = &self.text_layout_details(window);
12490        let selection_count = self.selections.count();
12491        let first_selection = self.selections.first_anchor();
12492
12493        self.change_selections(Default::default(), window, cx, |s| {
12494            s.move_with(|map, selection| {
12495                if !selection.is_empty() {
12496                    selection.goal = SelectionGoal::None;
12497                }
12498                let (cursor, goal) = movement::down(
12499                    map,
12500                    selection.end,
12501                    selection.goal,
12502                    false,
12503                    text_layout_details,
12504                );
12505                selection.collapse_to(cursor, goal);
12506            });
12507        });
12508
12509        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12510        {
12511            cx.propagate();
12512        }
12513    }
12514
12515    pub fn select_page_down(
12516        &mut self,
12517        _: &SelectPageDown,
12518        window: &mut Window,
12519        cx: &mut Context<Self>,
12520    ) {
12521        let Some(row_count) = self.visible_row_count() else {
12522            return;
12523        };
12524
12525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12526
12527        let text_layout_details = &self.text_layout_details(window);
12528
12529        self.change_selections(Default::default(), window, cx, |s| {
12530            s.move_heads_with(|map, head, goal| {
12531                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12532            })
12533        })
12534    }
12535
12536    pub fn move_page_down(
12537        &mut self,
12538        action: &MovePageDown,
12539        window: &mut Window,
12540        cx: &mut Context<Self>,
12541    ) {
12542        if self.take_rename(true, window, cx).is_some() {
12543            return;
12544        }
12545
12546        if self
12547            .context_menu
12548            .borrow_mut()
12549            .as_mut()
12550            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12551            .unwrap_or(false)
12552        {
12553            return;
12554        }
12555
12556        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12557            cx.propagate();
12558            return;
12559        }
12560
12561        let Some(row_count) = self.visible_row_count() else {
12562            return;
12563        };
12564
12565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12566
12567        let effects = if action.center_cursor {
12568            SelectionEffects::scroll(Autoscroll::center())
12569        } else {
12570            SelectionEffects::default()
12571        };
12572
12573        let text_layout_details = &self.text_layout_details(window);
12574        self.change_selections(effects, window, cx, |s| {
12575            s.move_with(|map, selection| {
12576                if !selection.is_empty() {
12577                    selection.goal = SelectionGoal::None;
12578                }
12579                let (cursor, goal) = movement::down_by_rows(
12580                    map,
12581                    selection.end,
12582                    row_count,
12583                    selection.goal,
12584                    false,
12585                    text_layout_details,
12586                );
12587                selection.collapse_to(cursor, goal);
12588            });
12589        });
12590    }
12591
12592    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12593        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12594        let text_layout_details = &self.text_layout_details(window);
12595        self.change_selections(Default::default(), window, cx, |s| {
12596            s.move_heads_with(|map, head, goal| {
12597                movement::down(map, head, goal, false, text_layout_details)
12598            })
12599        });
12600    }
12601
12602    pub fn context_menu_first(
12603        &mut self,
12604        _: &ContextMenuFirst,
12605        window: &mut Window,
12606        cx: &mut Context<Self>,
12607    ) {
12608        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12609            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12610        }
12611    }
12612
12613    pub fn context_menu_prev(
12614        &mut self,
12615        _: &ContextMenuPrevious,
12616        window: &mut Window,
12617        cx: &mut Context<Self>,
12618    ) {
12619        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12620            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12621        }
12622    }
12623
12624    pub fn context_menu_next(
12625        &mut self,
12626        _: &ContextMenuNext,
12627        window: &mut Window,
12628        cx: &mut Context<Self>,
12629    ) {
12630        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12631            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12632        }
12633    }
12634
12635    pub fn context_menu_last(
12636        &mut self,
12637        _: &ContextMenuLast,
12638        window: &mut Window,
12639        cx: &mut Context<Self>,
12640    ) {
12641        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12642            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12643        }
12644    }
12645
12646    pub fn signature_help_prev(
12647        &mut self,
12648        _: &SignatureHelpPrevious,
12649        _: &mut Window,
12650        cx: &mut Context<Self>,
12651    ) {
12652        if let Some(popover) = self.signature_help_state.popover_mut() {
12653            if popover.current_signature == 0 {
12654                popover.current_signature = popover.signatures.len() - 1;
12655            } else {
12656                popover.current_signature -= 1;
12657            }
12658            cx.notify();
12659        }
12660    }
12661
12662    pub fn signature_help_next(
12663        &mut self,
12664        _: &SignatureHelpNext,
12665        _: &mut Window,
12666        cx: &mut Context<Self>,
12667    ) {
12668        if let Some(popover) = self.signature_help_state.popover_mut() {
12669            if popover.current_signature + 1 == popover.signatures.len() {
12670                popover.current_signature = 0;
12671            } else {
12672                popover.current_signature += 1;
12673            }
12674            cx.notify();
12675        }
12676    }
12677
12678    pub fn move_to_previous_word_start(
12679        &mut self,
12680        _: &MoveToPreviousWordStart,
12681        window: &mut Window,
12682        cx: &mut Context<Self>,
12683    ) {
12684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12685        self.change_selections(Default::default(), window, cx, |s| {
12686            s.move_cursors_with(|map, head, _| {
12687                (
12688                    movement::previous_word_start(map, head),
12689                    SelectionGoal::None,
12690                )
12691            });
12692        })
12693    }
12694
12695    pub fn move_to_previous_subword_start(
12696        &mut self,
12697        _: &MoveToPreviousSubwordStart,
12698        window: &mut Window,
12699        cx: &mut Context<Self>,
12700    ) {
12701        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12702        self.change_selections(Default::default(), window, cx, |s| {
12703            s.move_cursors_with(|map, head, _| {
12704                (
12705                    movement::previous_subword_start(map, head),
12706                    SelectionGoal::None,
12707                )
12708            });
12709        })
12710    }
12711
12712    pub fn select_to_previous_word_start(
12713        &mut self,
12714        _: &SelectToPreviousWordStart,
12715        window: &mut Window,
12716        cx: &mut Context<Self>,
12717    ) {
12718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12719        self.change_selections(Default::default(), window, cx, |s| {
12720            s.move_heads_with(|map, head, _| {
12721                (
12722                    movement::previous_word_start(map, head),
12723                    SelectionGoal::None,
12724                )
12725            });
12726        })
12727    }
12728
12729    pub fn select_to_previous_subword_start(
12730        &mut self,
12731        _: &SelectToPreviousSubwordStart,
12732        window: &mut Window,
12733        cx: &mut Context<Self>,
12734    ) {
12735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12736        self.change_selections(Default::default(), window, cx, |s| {
12737            s.move_heads_with(|map, head, _| {
12738                (
12739                    movement::previous_subword_start(map, head),
12740                    SelectionGoal::None,
12741                )
12742            });
12743        })
12744    }
12745
12746    pub fn delete_to_previous_word_start(
12747        &mut self,
12748        action: &DeleteToPreviousWordStart,
12749        window: &mut Window,
12750        cx: &mut Context<Self>,
12751    ) {
12752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12753        self.transact(window, cx, |this, window, cx| {
12754            this.select_autoclose_pair(window, cx);
12755            this.change_selections(Default::default(), window, cx, |s| {
12756                s.move_with(|map, selection| {
12757                    if selection.is_empty() {
12758                        let cursor = if action.ignore_newlines {
12759                            movement::previous_word_start(map, selection.head())
12760                        } else {
12761                            movement::previous_word_start_or_newline(map, selection.head())
12762                        };
12763                        selection.set_head(cursor, SelectionGoal::None);
12764                    }
12765                });
12766            });
12767            this.insert("", window, cx);
12768        });
12769    }
12770
12771    pub fn delete_to_previous_subword_start(
12772        &mut self,
12773        _: &DeleteToPreviousSubwordStart,
12774        window: &mut Window,
12775        cx: &mut Context<Self>,
12776    ) {
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12778        self.transact(window, cx, |this, window, cx| {
12779            this.select_autoclose_pair(window, cx);
12780            this.change_selections(Default::default(), window, cx, |s| {
12781                s.move_with(|map, selection| {
12782                    if selection.is_empty() {
12783                        let cursor = movement::previous_subword_start(map, selection.head());
12784                        selection.set_head(cursor, SelectionGoal::None);
12785                    }
12786                });
12787            });
12788            this.insert("", window, cx);
12789        });
12790    }
12791
12792    pub fn move_to_next_word_end(
12793        &mut self,
12794        _: &MoveToNextWordEnd,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_cursors_with(|map, head, _| {
12801                (movement::next_word_end(map, head), SelectionGoal::None)
12802            });
12803        })
12804    }
12805
12806    pub fn move_to_next_subword_end(
12807        &mut self,
12808        _: &MoveToNextSubwordEnd,
12809        window: &mut Window,
12810        cx: &mut Context<Self>,
12811    ) {
12812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12813        self.change_selections(Default::default(), window, cx, |s| {
12814            s.move_cursors_with(|map, head, _| {
12815                (movement::next_subword_end(map, head), SelectionGoal::None)
12816            });
12817        })
12818    }
12819
12820    pub fn select_to_next_word_end(
12821        &mut self,
12822        _: &SelectToNextWordEnd,
12823        window: &mut Window,
12824        cx: &mut Context<Self>,
12825    ) {
12826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12827        self.change_selections(Default::default(), window, cx, |s| {
12828            s.move_heads_with(|map, head, _| {
12829                (movement::next_word_end(map, head), SelectionGoal::None)
12830            });
12831        })
12832    }
12833
12834    pub fn select_to_next_subword_end(
12835        &mut self,
12836        _: &SelectToNextSubwordEnd,
12837        window: &mut Window,
12838        cx: &mut Context<Self>,
12839    ) {
12840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12841        self.change_selections(Default::default(), window, cx, |s| {
12842            s.move_heads_with(|map, head, _| {
12843                (movement::next_subword_end(map, head), SelectionGoal::None)
12844            });
12845        })
12846    }
12847
12848    pub fn delete_to_next_word_end(
12849        &mut self,
12850        action: &DeleteToNextWordEnd,
12851        window: &mut Window,
12852        cx: &mut Context<Self>,
12853    ) {
12854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12855        self.transact(window, cx, |this, window, cx| {
12856            this.change_selections(Default::default(), window, cx, |s| {
12857                s.move_with(|map, selection| {
12858                    if selection.is_empty() {
12859                        let cursor = if action.ignore_newlines {
12860                            movement::next_word_end(map, selection.head())
12861                        } else {
12862                            movement::next_word_end_or_newline(map, selection.head())
12863                        };
12864                        selection.set_head(cursor, SelectionGoal::None);
12865                    }
12866                });
12867            });
12868            this.insert("", window, cx);
12869        });
12870    }
12871
12872    pub fn delete_to_next_subword_end(
12873        &mut self,
12874        _: &DeleteToNextSubwordEnd,
12875        window: &mut Window,
12876        cx: &mut Context<Self>,
12877    ) {
12878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12879        self.transact(window, cx, |this, window, cx| {
12880            this.change_selections(Default::default(), window, cx, |s| {
12881                s.move_with(|map, selection| {
12882                    if selection.is_empty() {
12883                        let cursor = movement::next_subword_end(map, selection.head());
12884                        selection.set_head(cursor, SelectionGoal::None);
12885                    }
12886                });
12887            });
12888            this.insert("", window, cx);
12889        });
12890    }
12891
12892    pub fn move_to_beginning_of_line(
12893        &mut self,
12894        action: &MoveToBeginningOfLine,
12895        window: &mut Window,
12896        cx: &mut Context<Self>,
12897    ) {
12898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12899        self.change_selections(Default::default(), window, cx, |s| {
12900            s.move_cursors_with(|map, head, _| {
12901                (
12902                    movement::indented_line_beginning(
12903                        map,
12904                        head,
12905                        action.stop_at_soft_wraps,
12906                        action.stop_at_indent,
12907                    ),
12908                    SelectionGoal::None,
12909                )
12910            });
12911        })
12912    }
12913
12914    pub fn select_to_beginning_of_line(
12915        &mut self,
12916        action: &SelectToBeginningOfLine,
12917        window: &mut Window,
12918        cx: &mut Context<Self>,
12919    ) {
12920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12921        self.change_selections(Default::default(), window, cx, |s| {
12922            s.move_heads_with(|map, head, _| {
12923                (
12924                    movement::indented_line_beginning(
12925                        map,
12926                        head,
12927                        action.stop_at_soft_wraps,
12928                        action.stop_at_indent,
12929                    ),
12930                    SelectionGoal::None,
12931                )
12932            });
12933        });
12934    }
12935
12936    pub fn delete_to_beginning_of_line(
12937        &mut self,
12938        action: &DeleteToBeginningOfLine,
12939        window: &mut Window,
12940        cx: &mut Context<Self>,
12941    ) {
12942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12943        self.transact(window, cx, |this, window, cx| {
12944            this.change_selections(Default::default(), window, cx, |s| {
12945                s.move_with(|_, selection| {
12946                    selection.reversed = true;
12947                });
12948            });
12949
12950            this.select_to_beginning_of_line(
12951                &SelectToBeginningOfLine {
12952                    stop_at_soft_wraps: false,
12953                    stop_at_indent: action.stop_at_indent,
12954                },
12955                window,
12956                cx,
12957            );
12958            this.backspace(&Backspace, window, cx);
12959        });
12960    }
12961
12962    pub fn move_to_end_of_line(
12963        &mut self,
12964        action: &MoveToEndOfLine,
12965        window: &mut Window,
12966        cx: &mut Context<Self>,
12967    ) {
12968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12969        self.change_selections(Default::default(), window, cx, |s| {
12970            s.move_cursors_with(|map, head, _| {
12971                (
12972                    movement::line_end(map, head, action.stop_at_soft_wraps),
12973                    SelectionGoal::None,
12974                )
12975            });
12976        })
12977    }
12978
12979    pub fn select_to_end_of_line(
12980        &mut self,
12981        action: &SelectToEndOfLine,
12982        window: &mut Window,
12983        cx: &mut Context<Self>,
12984    ) {
12985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12986        self.change_selections(Default::default(), window, cx, |s| {
12987            s.move_heads_with(|map, head, _| {
12988                (
12989                    movement::line_end(map, head, action.stop_at_soft_wraps),
12990                    SelectionGoal::None,
12991                )
12992            });
12993        })
12994    }
12995
12996    pub fn delete_to_end_of_line(
12997        &mut self,
12998        _: &DeleteToEndOfLine,
12999        window: &mut Window,
13000        cx: &mut Context<Self>,
13001    ) {
13002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13003        self.transact(window, cx, |this, window, cx| {
13004            this.select_to_end_of_line(
13005                &SelectToEndOfLine {
13006                    stop_at_soft_wraps: false,
13007                },
13008                window,
13009                cx,
13010            );
13011            this.delete(&Delete, window, cx);
13012        });
13013    }
13014
13015    pub fn cut_to_end_of_line(
13016        &mut self,
13017        _: &CutToEndOfLine,
13018        window: &mut Window,
13019        cx: &mut Context<Self>,
13020    ) {
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13022        self.transact(window, cx, |this, window, cx| {
13023            this.select_to_end_of_line(
13024                &SelectToEndOfLine {
13025                    stop_at_soft_wraps: false,
13026                },
13027                window,
13028                cx,
13029            );
13030            this.cut(&Cut, window, cx);
13031        });
13032    }
13033
13034    pub fn move_to_start_of_paragraph(
13035        &mut self,
13036        _: &MoveToStartOfParagraph,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13041            cx.propagate();
13042            return;
13043        }
13044        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13045        self.change_selections(Default::default(), window, cx, |s| {
13046            s.move_with(|map, selection| {
13047                selection.collapse_to(
13048                    movement::start_of_paragraph(map, selection.head(), 1),
13049                    SelectionGoal::None,
13050                )
13051            });
13052        })
13053    }
13054
13055    pub fn move_to_end_of_paragraph(
13056        &mut self,
13057        _: &MoveToEndOfParagraph,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13062            cx.propagate();
13063            return;
13064        }
13065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13066        self.change_selections(Default::default(), window, cx, |s| {
13067            s.move_with(|map, selection| {
13068                selection.collapse_to(
13069                    movement::end_of_paragraph(map, selection.head(), 1),
13070                    SelectionGoal::None,
13071                )
13072            });
13073        })
13074    }
13075
13076    pub fn select_to_start_of_paragraph(
13077        &mut self,
13078        _: &SelectToStartOfParagraph,
13079        window: &mut Window,
13080        cx: &mut Context<Self>,
13081    ) {
13082        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13083            cx.propagate();
13084            return;
13085        }
13086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13087        self.change_selections(Default::default(), window, cx, |s| {
13088            s.move_heads_with(|map, head, _| {
13089                (
13090                    movement::start_of_paragraph(map, head, 1),
13091                    SelectionGoal::None,
13092                )
13093            });
13094        })
13095    }
13096
13097    pub fn select_to_end_of_paragraph(
13098        &mut self,
13099        _: &SelectToEndOfParagraph,
13100        window: &mut Window,
13101        cx: &mut Context<Self>,
13102    ) {
13103        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13104            cx.propagate();
13105            return;
13106        }
13107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13108        self.change_selections(Default::default(), window, cx, |s| {
13109            s.move_heads_with(|map, head, _| {
13110                (
13111                    movement::end_of_paragraph(map, head, 1),
13112                    SelectionGoal::None,
13113                )
13114            });
13115        })
13116    }
13117
13118    pub fn move_to_start_of_excerpt(
13119        &mut self,
13120        _: &MoveToStartOfExcerpt,
13121        window: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13125            cx.propagate();
13126            return;
13127        }
13128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13129        self.change_selections(Default::default(), window, cx, |s| {
13130            s.move_with(|map, selection| {
13131                selection.collapse_to(
13132                    movement::start_of_excerpt(
13133                        map,
13134                        selection.head(),
13135                        workspace::searchable::Direction::Prev,
13136                    ),
13137                    SelectionGoal::None,
13138                )
13139            });
13140        })
13141    }
13142
13143    pub fn move_to_start_of_next_excerpt(
13144        &mut self,
13145        _: &MoveToStartOfNextExcerpt,
13146        window: &mut Window,
13147        cx: &mut Context<Self>,
13148    ) {
13149        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13150            cx.propagate();
13151            return;
13152        }
13153
13154        self.change_selections(Default::default(), window, cx, |s| {
13155            s.move_with(|map, selection| {
13156                selection.collapse_to(
13157                    movement::start_of_excerpt(
13158                        map,
13159                        selection.head(),
13160                        workspace::searchable::Direction::Next,
13161                    ),
13162                    SelectionGoal::None,
13163                )
13164            });
13165        })
13166    }
13167
13168    pub fn move_to_end_of_excerpt(
13169        &mut self,
13170        _: &MoveToEndOfExcerpt,
13171        window: &mut Window,
13172        cx: &mut Context<Self>,
13173    ) {
13174        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13175            cx.propagate();
13176            return;
13177        }
13178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13179        self.change_selections(Default::default(), window, cx, |s| {
13180            s.move_with(|map, selection| {
13181                selection.collapse_to(
13182                    movement::end_of_excerpt(
13183                        map,
13184                        selection.head(),
13185                        workspace::searchable::Direction::Next,
13186                    ),
13187                    SelectionGoal::None,
13188                )
13189            });
13190        })
13191    }
13192
13193    pub fn move_to_end_of_previous_excerpt(
13194        &mut self,
13195        _: &MoveToEndOfPreviousExcerpt,
13196        window: &mut Window,
13197        cx: &mut Context<Self>,
13198    ) {
13199        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13200            cx.propagate();
13201            return;
13202        }
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13204        self.change_selections(Default::default(), window, cx, |s| {
13205            s.move_with(|map, selection| {
13206                selection.collapse_to(
13207                    movement::end_of_excerpt(
13208                        map,
13209                        selection.head(),
13210                        workspace::searchable::Direction::Prev,
13211                    ),
13212                    SelectionGoal::None,
13213                )
13214            });
13215        })
13216    }
13217
13218    pub fn select_to_start_of_excerpt(
13219        &mut self,
13220        _: &SelectToStartOfExcerpt,
13221        window: &mut Window,
13222        cx: &mut Context<Self>,
13223    ) {
13224        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13225            cx.propagate();
13226            return;
13227        }
13228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13229        self.change_selections(Default::default(), window, cx, |s| {
13230            s.move_heads_with(|map, head, _| {
13231                (
13232                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13233                    SelectionGoal::None,
13234                )
13235            });
13236        })
13237    }
13238
13239    pub fn select_to_start_of_next_excerpt(
13240        &mut self,
13241        _: &SelectToStartOfNextExcerpt,
13242        window: &mut Window,
13243        cx: &mut Context<Self>,
13244    ) {
13245        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13246            cx.propagate();
13247            return;
13248        }
13249        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13250        self.change_selections(Default::default(), window, cx, |s| {
13251            s.move_heads_with(|map, head, _| {
13252                (
13253                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13254                    SelectionGoal::None,
13255                )
13256            });
13257        })
13258    }
13259
13260    pub fn select_to_end_of_excerpt(
13261        &mut self,
13262        _: &SelectToEndOfExcerpt,
13263        window: &mut Window,
13264        cx: &mut Context<Self>,
13265    ) {
13266        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13267            cx.propagate();
13268            return;
13269        }
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13271        self.change_selections(Default::default(), window, cx, |s| {
13272            s.move_heads_with(|map, head, _| {
13273                (
13274                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13275                    SelectionGoal::None,
13276                )
13277            });
13278        })
13279    }
13280
13281    pub fn select_to_end_of_previous_excerpt(
13282        &mut self,
13283        _: &SelectToEndOfPreviousExcerpt,
13284        window: &mut Window,
13285        cx: &mut Context<Self>,
13286    ) {
13287        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13288            cx.propagate();
13289            return;
13290        }
13291        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13292        self.change_selections(Default::default(), window, cx, |s| {
13293            s.move_heads_with(|map, head, _| {
13294                (
13295                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13296                    SelectionGoal::None,
13297                )
13298            });
13299        })
13300    }
13301
13302    pub fn move_to_beginning(
13303        &mut self,
13304        _: &MoveToBeginning,
13305        window: &mut Window,
13306        cx: &mut Context<Self>,
13307    ) {
13308        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13309            cx.propagate();
13310            return;
13311        }
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13313        self.change_selections(Default::default(), window, cx, |s| {
13314            s.select_ranges(vec![0..0]);
13315        });
13316    }
13317
13318    pub fn select_to_beginning(
13319        &mut self,
13320        _: &SelectToBeginning,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        let mut selection = self.selections.last::<Point>(cx);
13325        selection.set_head(Point::zero(), SelectionGoal::None);
13326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13327        self.change_selections(Default::default(), window, cx, |s| {
13328            s.select(vec![selection]);
13329        });
13330    }
13331
13332    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13333        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13334            cx.propagate();
13335            return;
13336        }
13337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13338        let cursor = self.buffer.read(cx).read(cx).len();
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.select_ranges(vec![cursor..cursor])
13341        });
13342    }
13343
13344    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13345        self.nav_history = nav_history;
13346    }
13347
13348    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13349        self.nav_history.as_ref()
13350    }
13351
13352    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13353        self.push_to_nav_history(
13354            self.selections.newest_anchor().head(),
13355            None,
13356            false,
13357            true,
13358            cx,
13359        );
13360    }
13361
13362    fn push_to_nav_history(
13363        &mut self,
13364        cursor_anchor: Anchor,
13365        new_position: Option<Point>,
13366        is_deactivate: bool,
13367        always: bool,
13368        cx: &mut Context<Self>,
13369    ) {
13370        if let Some(nav_history) = self.nav_history.as_mut() {
13371            let buffer = self.buffer.read(cx).read(cx);
13372            let cursor_position = cursor_anchor.to_point(&buffer);
13373            let scroll_state = self.scroll_manager.anchor();
13374            let scroll_top_row = scroll_state.top_row(&buffer);
13375            drop(buffer);
13376
13377            if let Some(new_position) = new_position {
13378                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13379                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13380                    return;
13381                }
13382            }
13383
13384            nav_history.push(
13385                Some(NavigationData {
13386                    cursor_anchor,
13387                    cursor_position,
13388                    scroll_anchor: scroll_state,
13389                    scroll_top_row,
13390                }),
13391                cx,
13392            );
13393            cx.emit(EditorEvent::PushedToNavHistory {
13394                anchor: cursor_anchor,
13395                is_deactivate,
13396            })
13397        }
13398    }
13399
13400    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13402        let buffer = self.buffer.read(cx).snapshot(cx);
13403        let mut selection = self.selections.first::<usize>(cx);
13404        selection.set_head(buffer.len(), SelectionGoal::None);
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.select(vec![selection]);
13407        });
13408    }
13409
13410    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13412        let end = self.buffer.read(cx).read(cx).len();
13413        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13414            s.select_ranges(vec![0..end]);
13415        });
13416    }
13417
13418    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13420        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13421        let mut selections = self.selections.all::<Point>(cx);
13422        let max_point = display_map.buffer_snapshot.max_point();
13423        for selection in &mut selections {
13424            let rows = selection.spanned_rows(true, &display_map);
13425            selection.start = Point::new(rows.start.0, 0);
13426            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13427            selection.reversed = false;
13428        }
13429        self.change_selections(Default::default(), window, cx, |s| {
13430            s.select(selections);
13431        });
13432    }
13433
13434    pub fn split_selection_into_lines(
13435        &mut self,
13436        _: &SplitSelectionIntoLines,
13437        window: &mut Window,
13438        cx: &mut Context<Self>,
13439    ) {
13440        let selections = self
13441            .selections
13442            .all::<Point>(cx)
13443            .into_iter()
13444            .map(|selection| selection.start..selection.end)
13445            .collect::<Vec<_>>();
13446        self.unfold_ranges(&selections, true, true, cx);
13447
13448        let mut new_selection_ranges = Vec::new();
13449        {
13450            let buffer = self.buffer.read(cx).read(cx);
13451            for selection in selections {
13452                for row in selection.start.row..selection.end.row {
13453                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13454                    new_selection_ranges.push(cursor..cursor);
13455                }
13456
13457                let is_multiline_selection = selection.start.row != selection.end.row;
13458                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13459                // so this action feels more ergonomic when paired with other selection operations
13460                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13461                if !should_skip_last {
13462                    new_selection_ranges.push(selection.end..selection.end);
13463                }
13464            }
13465        }
13466        self.change_selections(Default::default(), window, cx, |s| {
13467            s.select_ranges(new_selection_ranges);
13468        });
13469    }
13470
13471    pub fn add_selection_above(
13472        &mut self,
13473        _: &AddSelectionAbove,
13474        window: &mut Window,
13475        cx: &mut Context<Self>,
13476    ) {
13477        self.add_selection(true, window, cx);
13478    }
13479
13480    pub fn add_selection_below(
13481        &mut self,
13482        _: &AddSelectionBelow,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        self.add_selection(false, window, cx);
13487    }
13488
13489    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13491
13492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13493        let all_selections = self.selections.all::<Point>(cx);
13494        let text_layout_details = self.text_layout_details(window);
13495
13496        let (mut columnar_selections, new_selections_to_columnarize) = {
13497            if let Some(state) = self.add_selections_state.as_ref() {
13498                let columnar_selection_ids: HashSet<_> = state
13499                    .groups
13500                    .iter()
13501                    .flat_map(|group| group.stack.iter())
13502                    .copied()
13503                    .collect();
13504
13505                all_selections
13506                    .into_iter()
13507                    .partition(|s| columnar_selection_ids.contains(&s.id))
13508            } else {
13509                (Vec::new(), all_selections)
13510            }
13511        };
13512
13513        let mut state = self
13514            .add_selections_state
13515            .take()
13516            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13517
13518        for selection in new_selections_to_columnarize {
13519            let range = selection.display_range(&display_map).sorted();
13520            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13521            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13522            let positions = start_x.min(end_x)..start_x.max(end_x);
13523            let mut stack = Vec::new();
13524            for row in range.start.row().0..=range.end.row().0 {
13525                if let Some(selection) = self.selections.build_columnar_selection(
13526                    &display_map,
13527                    DisplayRow(row),
13528                    &positions,
13529                    selection.reversed,
13530                    &text_layout_details,
13531                ) {
13532                    stack.push(selection.id);
13533                    columnar_selections.push(selection);
13534                }
13535            }
13536            if !stack.is_empty() {
13537                if above {
13538                    stack.reverse();
13539                }
13540                state.groups.push(AddSelectionsGroup { above, stack });
13541            }
13542        }
13543
13544        let mut final_selections = Vec::new();
13545        let end_row = if above {
13546            DisplayRow(0)
13547        } else {
13548            display_map.max_point().row()
13549        };
13550
13551        let mut last_added_item_per_group = HashMap::default();
13552        for group in state.groups.iter_mut() {
13553            if let Some(last_id) = group.stack.last() {
13554                last_added_item_per_group.insert(*last_id, group);
13555            }
13556        }
13557
13558        for selection in columnar_selections {
13559            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13560                if above == group.above {
13561                    let range = selection.display_range(&display_map).sorted();
13562                    debug_assert_eq!(range.start.row(), range.end.row());
13563                    let mut row = range.start.row();
13564                    let positions =
13565                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13566                            px(start)..px(end)
13567                        } else {
13568                            let start_x =
13569                                display_map.x_for_display_point(range.start, &text_layout_details);
13570                            let end_x =
13571                                display_map.x_for_display_point(range.end, &text_layout_details);
13572                            start_x.min(end_x)..start_x.max(end_x)
13573                        };
13574
13575                    let mut maybe_new_selection = None;
13576                    while row != end_row {
13577                        if above {
13578                            row.0 -= 1;
13579                        } else {
13580                            row.0 += 1;
13581                        }
13582                        if let Some(new_selection) = self.selections.build_columnar_selection(
13583                            &display_map,
13584                            row,
13585                            &positions,
13586                            selection.reversed,
13587                            &text_layout_details,
13588                        ) {
13589                            maybe_new_selection = Some(new_selection);
13590                            break;
13591                        }
13592                    }
13593
13594                    if let Some(new_selection) = maybe_new_selection {
13595                        group.stack.push(new_selection.id);
13596                        if above {
13597                            final_selections.push(new_selection);
13598                            final_selections.push(selection);
13599                        } else {
13600                            final_selections.push(selection);
13601                            final_selections.push(new_selection);
13602                        }
13603                    } else {
13604                        final_selections.push(selection);
13605                    }
13606                } else {
13607                    group.stack.pop();
13608                }
13609            } else {
13610                final_selections.push(selection);
13611            }
13612        }
13613
13614        self.change_selections(Default::default(), window, cx, |s| {
13615            s.select(final_selections);
13616        });
13617
13618        let final_selection_ids: HashSet<_> = self
13619            .selections
13620            .all::<Point>(cx)
13621            .iter()
13622            .map(|s| s.id)
13623            .collect();
13624        state.groups.retain_mut(|group| {
13625            // selections might get merged above so we remove invalid items from stacks
13626            group.stack.retain(|id| final_selection_ids.contains(id));
13627
13628            // single selection in stack can be treated as initial state
13629            group.stack.len() > 1
13630        });
13631
13632        if !state.groups.is_empty() {
13633            self.add_selections_state = Some(state);
13634        }
13635    }
13636
13637    fn select_match_ranges(
13638        &mut self,
13639        range: Range<usize>,
13640        reversed: bool,
13641        replace_newest: bool,
13642        auto_scroll: Option<Autoscroll>,
13643        window: &mut Window,
13644        cx: &mut Context<Editor>,
13645    ) {
13646        self.unfold_ranges(
13647            std::slice::from_ref(&range),
13648            false,
13649            auto_scroll.is_some(),
13650            cx,
13651        );
13652        let effects = if let Some(scroll) = auto_scroll {
13653            SelectionEffects::scroll(scroll)
13654        } else {
13655            SelectionEffects::no_scroll()
13656        };
13657        self.change_selections(effects, window, cx, |s| {
13658            if replace_newest {
13659                s.delete(s.newest_anchor().id);
13660            }
13661            if reversed {
13662                s.insert_range(range.end..range.start);
13663            } else {
13664                s.insert_range(range);
13665            }
13666        });
13667    }
13668
13669    pub fn select_next_match_internal(
13670        &mut self,
13671        display_map: &DisplaySnapshot,
13672        replace_newest: bool,
13673        autoscroll: Option<Autoscroll>,
13674        window: &mut Window,
13675        cx: &mut Context<Self>,
13676    ) -> Result<()> {
13677        let buffer = &display_map.buffer_snapshot;
13678        let mut selections = self.selections.all::<usize>(cx);
13679        if let Some(mut select_next_state) = self.select_next_state.take() {
13680            let query = &select_next_state.query;
13681            if !select_next_state.done {
13682                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13683                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13684                let mut next_selected_range = None;
13685
13686                let bytes_after_last_selection =
13687                    buffer.bytes_in_range(last_selection.end..buffer.len());
13688                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13689                let query_matches = query
13690                    .stream_find_iter(bytes_after_last_selection)
13691                    .map(|result| (last_selection.end, result))
13692                    .chain(
13693                        query
13694                            .stream_find_iter(bytes_before_first_selection)
13695                            .map(|result| (0, result)),
13696                    );
13697
13698                for (start_offset, query_match) in query_matches {
13699                    let query_match = query_match.unwrap(); // can only fail due to I/O
13700                    let offset_range =
13701                        start_offset + query_match.start()..start_offset + query_match.end();
13702
13703                    if !select_next_state.wordwise
13704                        || (!buffer.is_inside_word(offset_range.start, false)
13705                            && !buffer.is_inside_word(offset_range.end, false))
13706                    {
13707                        // TODO: This is n^2, because we might check all the selections
13708                        if !selections
13709                            .iter()
13710                            .any(|selection| selection.range().overlaps(&offset_range))
13711                        {
13712                            next_selected_range = Some(offset_range);
13713                            break;
13714                        }
13715                    }
13716                }
13717
13718                if let Some(next_selected_range) = next_selected_range {
13719                    self.select_match_ranges(
13720                        next_selected_range,
13721                        last_selection.reversed,
13722                        replace_newest,
13723                        autoscroll,
13724                        window,
13725                        cx,
13726                    );
13727                } else {
13728                    select_next_state.done = true;
13729                }
13730            }
13731
13732            self.select_next_state = Some(select_next_state);
13733        } else {
13734            let mut only_carets = true;
13735            let mut same_text_selected = true;
13736            let mut selected_text = None;
13737
13738            let mut selections_iter = selections.iter().peekable();
13739            while let Some(selection) = selections_iter.next() {
13740                if selection.start != selection.end {
13741                    only_carets = false;
13742                }
13743
13744                if same_text_selected {
13745                    if selected_text.is_none() {
13746                        selected_text =
13747                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13748                    }
13749
13750                    if let Some(next_selection) = selections_iter.peek() {
13751                        if next_selection.range().len() == selection.range().len() {
13752                            let next_selected_text = buffer
13753                                .text_for_range(next_selection.range())
13754                                .collect::<String>();
13755                            if Some(next_selected_text) != selected_text {
13756                                same_text_selected = false;
13757                                selected_text = None;
13758                            }
13759                        } else {
13760                            same_text_selected = false;
13761                            selected_text = None;
13762                        }
13763                    }
13764                }
13765            }
13766
13767            if only_carets {
13768                for selection in &mut selections {
13769                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13770                    selection.start = word_range.start;
13771                    selection.end = word_range.end;
13772                    selection.goal = SelectionGoal::None;
13773                    selection.reversed = false;
13774                    self.select_match_ranges(
13775                        selection.start..selection.end,
13776                        selection.reversed,
13777                        replace_newest,
13778                        autoscroll,
13779                        window,
13780                        cx,
13781                    );
13782                }
13783
13784                if selections.len() == 1 {
13785                    let selection = selections
13786                        .last()
13787                        .expect("ensured that there's only one selection");
13788                    let query = buffer
13789                        .text_for_range(selection.start..selection.end)
13790                        .collect::<String>();
13791                    let is_empty = query.is_empty();
13792                    let select_state = SelectNextState {
13793                        query: AhoCorasick::new(&[query])?,
13794                        wordwise: true,
13795                        done: is_empty,
13796                    };
13797                    self.select_next_state = Some(select_state);
13798                } else {
13799                    self.select_next_state = None;
13800                }
13801            } else if let Some(selected_text) = selected_text {
13802                self.select_next_state = Some(SelectNextState {
13803                    query: AhoCorasick::new(&[selected_text])?,
13804                    wordwise: false,
13805                    done: false,
13806                });
13807                self.select_next_match_internal(
13808                    display_map,
13809                    replace_newest,
13810                    autoscroll,
13811                    window,
13812                    cx,
13813                )?;
13814            }
13815        }
13816        Ok(())
13817    }
13818
13819    pub fn select_all_matches(
13820        &mut self,
13821        _action: &SelectAllMatches,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) -> Result<()> {
13825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13826
13827        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13828
13829        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13830        let Some(select_next_state) = self.select_next_state.as_mut() else {
13831            return Ok(());
13832        };
13833        if select_next_state.done {
13834            return Ok(());
13835        }
13836
13837        let mut new_selections = Vec::new();
13838
13839        let reversed = self.selections.oldest::<usize>(cx).reversed;
13840        let buffer = &display_map.buffer_snapshot;
13841        let query_matches = select_next_state
13842            .query
13843            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13844
13845        for query_match in query_matches.into_iter() {
13846            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13847            let offset_range = if reversed {
13848                query_match.end()..query_match.start()
13849            } else {
13850                query_match.start()..query_match.end()
13851            };
13852
13853            if !select_next_state.wordwise
13854                || (!buffer.is_inside_word(offset_range.start, false)
13855                    && !buffer.is_inside_word(offset_range.end, false))
13856            {
13857                new_selections.push(offset_range.start..offset_range.end);
13858            }
13859        }
13860
13861        select_next_state.done = true;
13862
13863        if new_selections.is_empty() {
13864            log::error!("bug: new_selections is empty in select_all_matches");
13865            return Ok(());
13866        }
13867
13868        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13869        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13870            selections.select_ranges(new_selections)
13871        });
13872
13873        Ok(())
13874    }
13875
13876    pub fn select_next(
13877        &mut self,
13878        action: &SelectNext,
13879        window: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) -> Result<()> {
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13884        self.select_next_match_internal(
13885            &display_map,
13886            action.replace_newest,
13887            Some(Autoscroll::newest()),
13888            window,
13889            cx,
13890        )?;
13891        Ok(())
13892    }
13893
13894    pub fn select_previous(
13895        &mut self,
13896        action: &SelectPrevious,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) -> Result<()> {
13900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13901        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13902        let buffer = &display_map.buffer_snapshot;
13903        let mut selections = self.selections.all::<usize>(cx);
13904        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13905            let query = &select_prev_state.query;
13906            if !select_prev_state.done {
13907                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13908                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13909                let mut next_selected_range = None;
13910                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13911                let bytes_before_last_selection =
13912                    buffer.reversed_bytes_in_range(0..last_selection.start);
13913                let bytes_after_first_selection =
13914                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13915                let query_matches = query
13916                    .stream_find_iter(bytes_before_last_selection)
13917                    .map(|result| (last_selection.start, result))
13918                    .chain(
13919                        query
13920                            .stream_find_iter(bytes_after_first_selection)
13921                            .map(|result| (buffer.len(), result)),
13922                    );
13923                for (end_offset, query_match) in query_matches {
13924                    let query_match = query_match.unwrap(); // can only fail due to I/O
13925                    let offset_range =
13926                        end_offset - query_match.end()..end_offset - query_match.start();
13927
13928                    if !select_prev_state.wordwise
13929                        || (!buffer.is_inside_word(offset_range.start, false)
13930                            && !buffer.is_inside_word(offset_range.end, false))
13931                    {
13932                        next_selected_range = Some(offset_range);
13933                        break;
13934                    }
13935                }
13936
13937                if let Some(next_selected_range) = next_selected_range {
13938                    self.select_match_ranges(
13939                        next_selected_range,
13940                        last_selection.reversed,
13941                        action.replace_newest,
13942                        Some(Autoscroll::newest()),
13943                        window,
13944                        cx,
13945                    );
13946                } else {
13947                    select_prev_state.done = true;
13948                }
13949            }
13950
13951            self.select_prev_state = Some(select_prev_state);
13952        } else {
13953            let mut only_carets = true;
13954            let mut same_text_selected = true;
13955            let mut selected_text = None;
13956
13957            let mut selections_iter = selections.iter().peekable();
13958            while let Some(selection) = selections_iter.next() {
13959                if selection.start != selection.end {
13960                    only_carets = false;
13961                }
13962
13963                if same_text_selected {
13964                    if selected_text.is_none() {
13965                        selected_text =
13966                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13967                    }
13968
13969                    if let Some(next_selection) = selections_iter.peek() {
13970                        if next_selection.range().len() == selection.range().len() {
13971                            let next_selected_text = buffer
13972                                .text_for_range(next_selection.range())
13973                                .collect::<String>();
13974                            if Some(next_selected_text) != selected_text {
13975                                same_text_selected = false;
13976                                selected_text = None;
13977                            }
13978                        } else {
13979                            same_text_selected = false;
13980                            selected_text = None;
13981                        }
13982                    }
13983                }
13984            }
13985
13986            if only_carets {
13987                for selection in &mut selections {
13988                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13989                    selection.start = word_range.start;
13990                    selection.end = word_range.end;
13991                    selection.goal = SelectionGoal::None;
13992                    selection.reversed = false;
13993                    self.select_match_ranges(
13994                        selection.start..selection.end,
13995                        selection.reversed,
13996                        action.replace_newest,
13997                        Some(Autoscroll::newest()),
13998                        window,
13999                        cx,
14000                    );
14001                }
14002                if selections.len() == 1 {
14003                    let selection = selections
14004                        .last()
14005                        .expect("ensured that there's only one selection");
14006                    let query = buffer
14007                        .text_for_range(selection.start..selection.end)
14008                        .collect::<String>();
14009                    let is_empty = query.is_empty();
14010                    let select_state = SelectNextState {
14011                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14012                        wordwise: true,
14013                        done: is_empty,
14014                    };
14015                    self.select_prev_state = Some(select_state);
14016                } else {
14017                    self.select_prev_state = None;
14018                }
14019            } else if let Some(selected_text) = selected_text {
14020                self.select_prev_state = Some(SelectNextState {
14021                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14022                    wordwise: false,
14023                    done: false,
14024                });
14025                self.select_previous(action, window, cx)?;
14026            }
14027        }
14028        Ok(())
14029    }
14030
14031    pub fn find_next_match(
14032        &mut self,
14033        _: &FindNextMatch,
14034        window: &mut Window,
14035        cx: &mut Context<Self>,
14036    ) -> Result<()> {
14037        let selections = self.selections.disjoint_anchors();
14038        match selections.first() {
14039            Some(first) if selections.len() >= 2 => {
14040                self.change_selections(Default::default(), window, cx, |s| {
14041                    s.select_ranges([first.range()]);
14042                });
14043            }
14044            _ => self.select_next(
14045                &SelectNext {
14046                    replace_newest: true,
14047                },
14048                window,
14049                cx,
14050            )?,
14051        }
14052        Ok(())
14053    }
14054
14055    pub fn find_previous_match(
14056        &mut self,
14057        _: &FindPreviousMatch,
14058        window: &mut Window,
14059        cx: &mut Context<Self>,
14060    ) -> Result<()> {
14061        let selections = self.selections.disjoint_anchors();
14062        match selections.last() {
14063            Some(last) if selections.len() >= 2 => {
14064                self.change_selections(Default::default(), window, cx, |s| {
14065                    s.select_ranges([last.range()]);
14066                });
14067            }
14068            _ => self.select_previous(
14069                &SelectPrevious {
14070                    replace_newest: true,
14071                },
14072                window,
14073                cx,
14074            )?,
14075        }
14076        Ok(())
14077    }
14078
14079    pub fn toggle_comments(
14080        &mut self,
14081        action: &ToggleComments,
14082        window: &mut Window,
14083        cx: &mut Context<Self>,
14084    ) {
14085        if self.read_only(cx) {
14086            return;
14087        }
14088        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14089        let text_layout_details = &self.text_layout_details(window);
14090        self.transact(window, cx, |this, window, cx| {
14091            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14092            let mut edits = Vec::new();
14093            let mut selection_edit_ranges = Vec::new();
14094            let mut last_toggled_row = None;
14095            let snapshot = this.buffer.read(cx).read(cx);
14096            let empty_str: Arc<str> = Arc::default();
14097            let mut suffixes_inserted = Vec::new();
14098            let ignore_indent = action.ignore_indent;
14099
14100            fn comment_prefix_range(
14101                snapshot: &MultiBufferSnapshot,
14102                row: MultiBufferRow,
14103                comment_prefix: &str,
14104                comment_prefix_whitespace: &str,
14105                ignore_indent: bool,
14106            ) -> Range<Point> {
14107                let indent_size = if ignore_indent {
14108                    0
14109                } else {
14110                    snapshot.indent_size_for_line(row).len
14111                };
14112
14113                let start = Point::new(row.0, indent_size);
14114
14115                let mut line_bytes = snapshot
14116                    .bytes_in_range(start..snapshot.max_point())
14117                    .flatten()
14118                    .copied();
14119
14120                // If this line currently begins with the line comment prefix, then record
14121                // the range containing the prefix.
14122                if line_bytes
14123                    .by_ref()
14124                    .take(comment_prefix.len())
14125                    .eq(comment_prefix.bytes())
14126                {
14127                    // Include any whitespace that matches the comment prefix.
14128                    let matching_whitespace_len = line_bytes
14129                        .zip(comment_prefix_whitespace.bytes())
14130                        .take_while(|(a, b)| a == b)
14131                        .count() as u32;
14132                    let end = Point::new(
14133                        start.row,
14134                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14135                    );
14136                    start..end
14137                } else {
14138                    start..start
14139                }
14140            }
14141
14142            fn comment_suffix_range(
14143                snapshot: &MultiBufferSnapshot,
14144                row: MultiBufferRow,
14145                comment_suffix: &str,
14146                comment_suffix_has_leading_space: bool,
14147            ) -> Range<Point> {
14148                let end = Point::new(row.0, snapshot.line_len(row));
14149                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14150
14151                let mut line_end_bytes = snapshot
14152                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14153                    .flatten()
14154                    .copied();
14155
14156                let leading_space_len = if suffix_start_column > 0
14157                    && line_end_bytes.next() == Some(b' ')
14158                    && comment_suffix_has_leading_space
14159                {
14160                    1
14161                } else {
14162                    0
14163                };
14164
14165                // If this line currently begins with the line comment prefix, then record
14166                // the range containing the prefix.
14167                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14168                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14169                    start..end
14170                } else {
14171                    end..end
14172                }
14173            }
14174
14175            // TODO: Handle selections that cross excerpts
14176            for selection in &mut selections {
14177                let start_column = snapshot
14178                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14179                    .len;
14180                let language = if let Some(language) =
14181                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14182                {
14183                    language
14184                } else {
14185                    continue;
14186                };
14187
14188                selection_edit_ranges.clear();
14189
14190                // If multiple selections contain a given row, avoid processing that
14191                // row more than once.
14192                let mut start_row = MultiBufferRow(selection.start.row);
14193                if last_toggled_row == Some(start_row) {
14194                    start_row = start_row.next_row();
14195                }
14196                let end_row =
14197                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14198                        MultiBufferRow(selection.end.row - 1)
14199                    } else {
14200                        MultiBufferRow(selection.end.row)
14201                    };
14202                last_toggled_row = Some(end_row);
14203
14204                if start_row > end_row {
14205                    continue;
14206                }
14207
14208                // If the language has line comments, toggle those.
14209                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14210
14211                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14212                if ignore_indent {
14213                    full_comment_prefixes = full_comment_prefixes
14214                        .into_iter()
14215                        .map(|s| Arc::from(s.trim_end()))
14216                        .collect();
14217                }
14218
14219                if !full_comment_prefixes.is_empty() {
14220                    let first_prefix = full_comment_prefixes
14221                        .first()
14222                        .expect("prefixes is non-empty");
14223                    let prefix_trimmed_lengths = full_comment_prefixes
14224                        .iter()
14225                        .map(|p| p.trim_end_matches(' ').len())
14226                        .collect::<SmallVec<[usize; 4]>>();
14227
14228                    let mut all_selection_lines_are_comments = true;
14229
14230                    for row in start_row.0..=end_row.0 {
14231                        let row = MultiBufferRow(row);
14232                        if start_row < end_row && snapshot.is_line_blank(row) {
14233                            continue;
14234                        }
14235
14236                        let prefix_range = full_comment_prefixes
14237                            .iter()
14238                            .zip(prefix_trimmed_lengths.iter().copied())
14239                            .map(|(prefix, trimmed_prefix_len)| {
14240                                comment_prefix_range(
14241                                    snapshot.deref(),
14242                                    row,
14243                                    &prefix[..trimmed_prefix_len],
14244                                    &prefix[trimmed_prefix_len..],
14245                                    ignore_indent,
14246                                )
14247                            })
14248                            .max_by_key(|range| range.end.column - range.start.column)
14249                            .expect("prefixes is non-empty");
14250
14251                        if prefix_range.is_empty() {
14252                            all_selection_lines_are_comments = false;
14253                        }
14254
14255                        selection_edit_ranges.push(prefix_range);
14256                    }
14257
14258                    if all_selection_lines_are_comments {
14259                        edits.extend(
14260                            selection_edit_ranges
14261                                .iter()
14262                                .cloned()
14263                                .map(|range| (range, empty_str.clone())),
14264                        );
14265                    } else {
14266                        let min_column = selection_edit_ranges
14267                            .iter()
14268                            .map(|range| range.start.column)
14269                            .min()
14270                            .unwrap_or(0);
14271                        edits.extend(selection_edit_ranges.iter().map(|range| {
14272                            let position = Point::new(range.start.row, min_column);
14273                            (position..position, first_prefix.clone())
14274                        }));
14275                    }
14276                } else if let Some((full_comment_prefix, comment_suffix)) =
14277                    language.block_comment_delimiters()
14278                {
14279                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14280                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14281                    let prefix_range = comment_prefix_range(
14282                        snapshot.deref(),
14283                        start_row,
14284                        comment_prefix,
14285                        comment_prefix_whitespace,
14286                        ignore_indent,
14287                    );
14288                    let suffix_range = comment_suffix_range(
14289                        snapshot.deref(),
14290                        end_row,
14291                        comment_suffix.trim_start_matches(' '),
14292                        comment_suffix.starts_with(' '),
14293                    );
14294
14295                    if prefix_range.is_empty() || suffix_range.is_empty() {
14296                        edits.push((
14297                            prefix_range.start..prefix_range.start,
14298                            full_comment_prefix.clone(),
14299                        ));
14300                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14301                        suffixes_inserted.push((end_row, comment_suffix.len()));
14302                    } else {
14303                        edits.push((prefix_range, empty_str.clone()));
14304                        edits.push((suffix_range, empty_str.clone()));
14305                    }
14306                } else {
14307                    continue;
14308                }
14309            }
14310
14311            drop(snapshot);
14312            this.buffer.update(cx, |buffer, cx| {
14313                buffer.edit(edits, None, cx);
14314            });
14315
14316            // Adjust selections so that they end before any comment suffixes that
14317            // were inserted.
14318            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14319            let mut selections = this.selections.all::<Point>(cx);
14320            let snapshot = this.buffer.read(cx).read(cx);
14321            for selection in &mut selections {
14322                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14323                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14324                        Ordering::Less => {
14325                            suffixes_inserted.next();
14326                            continue;
14327                        }
14328                        Ordering::Greater => break,
14329                        Ordering::Equal => {
14330                            if selection.end.column == snapshot.line_len(row) {
14331                                if selection.is_empty() {
14332                                    selection.start.column -= suffix_len as u32;
14333                                }
14334                                selection.end.column -= suffix_len as u32;
14335                            }
14336                            break;
14337                        }
14338                    }
14339                }
14340            }
14341
14342            drop(snapshot);
14343            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14344
14345            let selections = this.selections.all::<Point>(cx);
14346            let selections_on_single_row = selections.windows(2).all(|selections| {
14347                selections[0].start.row == selections[1].start.row
14348                    && selections[0].end.row == selections[1].end.row
14349                    && selections[0].start.row == selections[0].end.row
14350            });
14351            let selections_selecting = selections
14352                .iter()
14353                .any(|selection| selection.start != selection.end);
14354            let advance_downwards = action.advance_downwards
14355                && selections_on_single_row
14356                && !selections_selecting
14357                && !matches!(this.mode, EditorMode::SingleLine { .. });
14358
14359            if advance_downwards {
14360                let snapshot = this.buffer.read(cx).snapshot(cx);
14361
14362                this.change_selections(Default::default(), window, cx, |s| {
14363                    s.move_cursors_with(|display_snapshot, display_point, _| {
14364                        let mut point = display_point.to_point(display_snapshot);
14365                        point.row += 1;
14366                        point = snapshot.clip_point(point, Bias::Left);
14367                        let display_point = point.to_display_point(display_snapshot);
14368                        let goal = SelectionGoal::HorizontalPosition(
14369                            display_snapshot
14370                                .x_for_display_point(display_point, text_layout_details)
14371                                .into(),
14372                        );
14373                        (display_point, goal)
14374                    })
14375                });
14376            }
14377        });
14378    }
14379
14380    pub fn select_enclosing_symbol(
14381        &mut self,
14382        _: &SelectEnclosingSymbol,
14383        window: &mut Window,
14384        cx: &mut Context<Self>,
14385    ) {
14386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14387
14388        let buffer = self.buffer.read(cx).snapshot(cx);
14389        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14390
14391        fn update_selection(
14392            selection: &Selection<usize>,
14393            buffer_snap: &MultiBufferSnapshot,
14394        ) -> Option<Selection<usize>> {
14395            let cursor = selection.head();
14396            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14397            for symbol in symbols.iter().rev() {
14398                let start = symbol.range.start.to_offset(buffer_snap);
14399                let end = symbol.range.end.to_offset(buffer_snap);
14400                let new_range = start..end;
14401                if start < selection.start || end > selection.end {
14402                    return Some(Selection {
14403                        id: selection.id,
14404                        start: new_range.start,
14405                        end: new_range.end,
14406                        goal: SelectionGoal::None,
14407                        reversed: selection.reversed,
14408                    });
14409                }
14410            }
14411            None
14412        }
14413
14414        let mut selected_larger_symbol = false;
14415        let new_selections = old_selections
14416            .iter()
14417            .map(|selection| match update_selection(selection, &buffer) {
14418                Some(new_selection) => {
14419                    if new_selection.range() != selection.range() {
14420                        selected_larger_symbol = true;
14421                    }
14422                    new_selection
14423                }
14424                None => selection.clone(),
14425            })
14426            .collect::<Vec<_>>();
14427
14428        if selected_larger_symbol {
14429            self.change_selections(Default::default(), window, cx, |s| {
14430                s.select(new_selections);
14431            });
14432        }
14433    }
14434
14435    pub fn select_larger_syntax_node(
14436        &mut self,
14437        _: &SelectLargerSyntaxNode,
14438        window: &mut Window,
14439        cx: &mut Context<Self>,
14440    ) {
14441        let Some(visible_row_count) = self.visible_row_count() else {
14442            return;
14443        };
14444        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14445        if old_selections.is_empty() {
14446            return;
14447        }
14448
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450
14451        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14452        let buffer = self.buffer.read(cx).snapshot(cx);
14453
14454        let mut selected_larger_node = false;
14455        let mut new_selections = old_selections
14456            .iter()
14457            .map(|selection| {
14458                let old_range = selection.start..selection.end;
14459
14460                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14461                    // manually select word at selection
14462                    if ["string_content", "inline"].contains(&node.kind()) {
14463                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14464                        // ignore if word is already selected
14465                        if !word_range.is_empty() && old_range != word_range {
14466                            let (last_word_range, _) =
14467                                buffer.surrounding_word(old_range.end, false);
14468                            // only select word if start and end point belongs to same word
14469                            if word_range == last_word_range {
14470                                selected_larger_node = true;
14471                                return Selection {
14472                                    id: selection.id,
14473                                    start: word_range.start,
14474                                    end: word_range.end,
14475                                    goal: SelectionGoal::None,
14476                                    reversed: selection.reversed,
14477                                };
14478                            }
14479                        }
14480                    }
14481                }
14482
14483                let mut new_range = old_range.clone();
14484                while let Some((_node, containing_range)) =
14485                    buffer.syntax_ancestor(new_range.clone())
14486                {
14487                    new_range = match containing_range {
14488                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14489                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14490                    };
14491                    if !display_map.intersects_fold(new_range.start)
14492                        && !display_map.intersects_fold(new_range.end)
14493                    {
14494                        break;
14495                    }
14496                }
14497
14498                selected_larger_node |= new_range != old_range;
14499                Selection {
14500                    id: selection.id,
14501                    start: new_range.start,
14502                    end: new_range.end,
14503                    goal: SelectionGoal::None,
14504                    reversed: selection.reversed,
14505                }
14506            })
14507            .collect::<Vec<_>>();
14508
14509        if !selected_larger_node {
14510            return; // don't put this call in the history
14511        }
14512
14513        // scroll based on transformation done to the last selection created by the user
14514        let (last_old, last_new) = old_selections
14515            .last()
14516            .zip(new_selections.last().cloned())
14517            .expect("old_selections isn't empty");
14518
14519        // revert selection
14520        let is_selection_reversed = {
14521            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14522            new_selections.last_mut().expect("checked above").reversed =
14523                should_newest_selection_be_reversed;
14524            should_newest_selection_be_reversed
14525        };
14526
14527        if selected_larger_node {
14528            self.select_syntax_node_history.disable_clearing = true;
14529            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14530                s.select(new_selections.clone());
14531            });
14532            self.select_syntax_node_history.disable_clearing = false;
14533        }
14534
14535        let start_row = last_new.start.to_display_point(&display_map).row().0;
14536        let end_row = last_new.end.to_display_point(&display_map).row().0;
14537        let selection_height = end_row - start_row + 1;
14538        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14539
14540        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14541        let scroll_behavior = if fits_on_the_screen {
14542            self.request_autoscroll(Autoscroll::fit(), cx);
14543            SelectSyntaxNodeScrollBehavior::FitSelection
14544        } else if is_selection_reversed {
14545            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14546            SelectSyntaxNodeScrollBehavior::CursorTop
14547        } else {
14548            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14549            SelectSyntaxNodeScrollBehavior::CursorBottom
14550        };
14551
14552        self.select_syntax_node_history.push((
14553            old_selections,
14554            scroll_behavior,
14555            is_selection_reversed,
14556        ));
14557    }
14558
14559    pub fn select_smaller_syntax_node(
14560        &mut self,
14561        _: &SelectSmallerSyntaxNode,
14562        window: &mut Window,
14563        cx: &mut Context<Self>,
14564    ) {
14565        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14566
14567        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14568            self.select_syntax_node_history.pop()
14569        {
14570            if let Some(selection) = selections.last_mut() {
14571                selection.reversed = is_selection_reversed;
14572            }
14573
14574            self.select_syntax_node_history.disable_clearing = true;
14575            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14576                s.select(selections.to_vec());
14577            });
14578            self.select_syntax_node_history.disable_clearing = false;
14579
14580            match scroll_behavior {
14581                SelectSyntaxNodeScrollBehavior::CursorTop => {
14582                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14583                }
14584                SelectSyntaxNodeScrollBehavior::FitSelection => {
14585                    self.request_autoscroll(Autoscroll::fit(), cx);
14586                }
14587                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14588                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14589                }
14590            }
14591        }
14592    }
14593
14594    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14595        if !EditorSettings::get_global(cx).gutter.runnables {
14596            self.clear_tasks();
14597            return Task::ready(());
14598        }
14599        let project = self.project.as_ref().map(Entity::downgrade);
14600        let task_sources = self.lsp_task_sources(cx);
14601        let multi_buffer = self.buffer.downgrade();
14602        cx.spawn_in(window, async move |editor, cx| {
14603            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14604            let Some(project) = project.and_then(|p| p.upgrade()) else {
14605                return;
14606            };
14607            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14608                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14609            }) else {
14610                return;
14611            };
14612
14613            let hide_runnables = project
14614                .update(cx, |project, cx| {
14615                    // Do not display any test indicators in non-dev server remote projects.
14616                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14617                })
14618                .unwrap_or(true);
14619            if hide_runnables {
14620                return;
14621            }
14622            let new_rows =
14623                cx.background_spawn({
14624                    let snapshot = display_snapshot.clone();
14625                    async move {
14626                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14627                    }
14628                })
14629                    .await;
14630            let Ok(lsp_tasks) =
14631                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14632            else {
14633                return;
14634            };
14635            let lsp_tasks = lsp_tasks.await;
14636
14637            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14638                lsp_tasks
14639                    .into_iter()
14640                    .flat_map(|(kind, tasks)| {
14641                        tasks.into_iter().filter_map(move |(location, task)| {
14642                            Some((kind.clone(), location?, task))
14643                        })
14644                    })
14645                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14646                        let buffer = location.target.buffer;
14647                        let buffer_snapshot = buffer.read(cx).snapshot();
14648                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14649                            |(excerpt_id, snapshot, _)| {
14650                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14651                                    display_snapshot
14652                                        .buffer_snapshot
14653                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14654                                } else {
14655                                    None
14656                                }
14657                            },
14658                        );
14659                        if let Some(offset) = offset {
14660                            let task_buffer_range =
14661                                location.target.range.to_point(&buffer_snapshot);
14662                            let context_buffer_range =
14663                                task_buffer_range.to_offset(&buffer_snapshot);
14664                            let context_range = BufferOffset(context_buffer_range.start)
14665                                ..BufferOffset(context_buffer_range.end);
14666
14667                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14668                                .or_insert_with(|| RunnableTasks {
14669                                    templates: Vec::new(),
14670                                    offset,
14671                                    column: task_buffer_range.start.column,
14672                                    extra_variables: HashMap::default(),
14673                                    context_range,
14674                                })
14675                                .templates
14676                                .push((kind, task.original_task().clone()));
14677                        }
14678
14679                        acc
14680                    })
14681            }) else {
14682                return;
14683            };
14684
14685            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14686                buffer.language_settings(cx).tasks.prefer_lsp
14687            }) else {
14688                return;
14689            };
14690
14691            let rows = Self::runnable_rows(
14692                project,
14693                display_snapshot,
14694                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14695                new_rows,
14696                cx.clone(),
14697            )
14698            .await;
14699            editor
14700                .update(cx, |editor, _| {
14701                    editor.clear_tasks();
14702                    for (key, mut value) in rows {
14703                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14704                            value.templates.extend(lsp_tasks.templates);
14705                        }
14706
14707                        editor.insert_tasks(key, value);
14708                    }
14709                    for (key, value) in lsp_tasks_by_rows {
14710                        editor.insert_tasks(key, value);
14711                    }
14712                })
14713                .ok();
14714        })
14715    }
14716    fn fetch_runnable_ranges(
14717        snapshot: &DisplaySnapshot,
14718        range: Range<Anchor>,
14719    ) -> Vec<language::RunnableRange> {
14720        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14721    }
14722
14723    fn runnable_rows(
14724        project: Entity<Project>,
14725        snapshot: DisplaySnapshot,
14726        prefer_lsp: bool,
14727        runnable_ranges: Vec<RunnableRange>,
14728        cx: AsyncWindowContext,
14729    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14730        cx.spawn(async move |cx| {
14731            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14732            for mut runnable in runnable_ranges {
14733                let Some(tasks) = cx
14734                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14735                    .ok()
14736                else {
14737                    continue;
14738                };
14739                let mut tasks = tasks.await;
14740
14741                if prefer_lsp {
14742                    tasks.retain(|(task_kind, _)| {
14743                        !matches!(task_kind, TaskSourceKind::Language { .. })
14744                    });
14745                }
14746                if tasks.is_empty() {
14747                    continue;
14748                }
14749
14750                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14751                let Some(row) = snapshot
14752                    .buffer_snapshot
14753                    .buffer_line_for_row(MultiBufferRow(point.row))
14754                    .map(|(_, range)| range.start.row)
14755                else {
14756                    continue;
14757                };
14758
14759                let context_range =
14760                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14761                runnable_rows.push((
14762                    (runnable.buffer_id, row),
14763                    RunnableTasks {
14764                        templates: tasks,
14765                        offset: snapshot
14766                            .buffer_snapshot
14767                            .anchor_before(runnable.run_range.start),
14768                        context_range,
14769                        column: point.column,
14770                        extra_variables: runnable.extra_captures,
14771                    },
14772                ));
14773            }
14774            runnable_rows
14775        })
14776    }
14777
14778    fn templates_with_tags(
14779        project: &Entity<Project>,
14780        runnable: &mut Runnable,
14781        cx: &mut App,
14782    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14783        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14784            let (worktree_id, file) = project
14785                .buffer_for_id(runnable.buffer, cx)
14786                .and_then(|buffer| buffer.read(cx).file())
14787                .map(|file| (file.worktree_id(cx), file.clone()))
14788                .unzip();
14789
14790            (
14791                project.task_store().read(cx).task_inventory().cloned(),
14792                worktree_id,
14793                file,
14794            )
14795        });
14796
14797        let tags = mem::take(&mut runnable.tags);
14798        let language = runnable.language.clone();
14799        cx.spawn(async move |cx| {
14800            let mut templates_with_tags = Vec::new();
14801            if let Some(inventory) = inventory {
14802                for RunnableTag(tag) in tags {
14803                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14804                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14805                    }) else {
14806                        return templates_with_tags;
14807                    };
14808                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14809                        move |(_, template)| {
14810                            template.tags.iter().any(|source_tag| source_tag == &tag)
14811                        },
14812                    ));
14813                }
14814            }
14815            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14816
14817            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14818                // Strongest source wins; if we have worktree tag binding, prefer that to
14819                // global and language bindings;
14820                // if we have a global binding, prefer that to language binding.
14821                let first_mismatch = templates_with_tags
14822                    .iter()
14823                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14824                if let Some(index) = first_mismatch {
14825                    templates_with_tags.truncate(index);
14826                }
14827            }
14828
14829            templates_with_tags
14830        })
14831    }
14832
14833    pub fn move_to_enclosing_bracket(
14834        &mut self,
14835        _: &MoveToEnclosingBracket,
14836        window: &mut Window,
14837        cx: &mut Context<Self>,
14838    ) {
14839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14840        self.change_selections(Default::default(), window, cx, |s| {
14841            s.move_offsets_with(|snapshot, selection| {
14842                let Some(enclosing_bracket_ranges) =
14843                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14844                else {
14845                    return;
14846                };
14847
14848                let mut best_length = usize::MAX;
14849                let mut best_inside = false;
14850                let mut best_in_bracket_range = false;
14851                let mut best_destination = None;
14852                for (open, close) in enclosing_bracket_ranges {
14853                    let close = close.to_inclusive();
14854                    let length = close.end() - open.start;
14855                    let inside = selection.start >= open.end && selection.end <= *close.start();
14856                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14857                        || close.contains(&selection.head());
14858
14859                    // If best is next to a bracket and current isn't, skip
14860                    if !in_bracket_range && best_in_bracket_range {
14861                        continue;
14862                    }
14863
14864                    // Prefer smaller lengths unless best is inside and current isn't
14865                    if length > best_length && (best_inside || !inside) {
14866                        continue;
14867                    }
14868
14869                    best_length = length;
14870                    best_inside = inside;
14871                    best_in_bracket_range = in_bracket_range;
14872                    best_destination = Some(
14873                        if close.contains(&selection.start) && close.contains(&selection.end) {
14874                            if inside { open.end } else { open.start }
14875                        } else if inside {
14876                            *close.start()
14877                        } else {
14878                            *close.end()
14879                        },
14880                    );
14881                }
14882
14883                if let Some(destination) = best_destination {
14884                    selection.collapse_to(destination, SelectionGoal::None);
14885                }
14886            })
14887        });
14888    }
14889
14890    pub fn undo_selection(
14891        &mut self,
14892        _: &UndoSelection,
14893        window: &mut Window,
14894        cx: &mut Context<Self>,
14895    ) {
14896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14897        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14898            self.selection_history.mode = SelectionHistoryMode::Undoing;
14899            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14900                this.end_selection(window, cx);
14901                this.change_selections(
14902                    SelectionEffects::scroll(Autoscroll::newest()),
14903                    window,
14904                    cx,
14905                    |s| s.select_anchors(entry.selections.to_vec()),
14906                );
14907            });
14908            self.selection_history.mode = SelectionHistoryMode::Normal;
14909
14910            self.select_next_state = entry.select_next_state;
14911            self.select_prev_state = entry.select_prev_state;
14912            self.add_selections_state = entry.add_selections_state;
14913        }
14914    }
14915
14916    pub fn redo_selection(
14917        &mut self,
14918        _: &RedoSelection,
14919        window: &mut Window,
14920        cx: &mut Context<Self>,
14921    ) {
14922        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14923        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14924            self.selection_history.mode = SelectionHistoryMode::Redoing;
14925            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14926                this.end_selection(window, cx);
14927                this.change_selections(
14928                    SelectionEffects::scroll(Autoscroll::newest()),
14929                    window,
14930                    cx,
14931                    |s| s.select_anchors(entry.selections.to_vec()),
14932                );
14933            });
14934            self.selection_history.mode = SelectionHistoryMode::Normal;
14935
14936            self.select_next_state = entry.select_next_state;
14937            self.select_prev_state = entry.select_prev_state;
14938            self.add_selections_state = entry.add_selections_state;
14939        }
14940    }
14941
14942    pub fn expand_excerpts(
14943        &mut self,
14944        action: &ExpandExcerpts,
14945        _: &mut Window,
14946        cx: &mut Context<Self>,
14947    ) {
14948        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14949    }
14950
14951    pub fn expand_excerpts_down(
14952        &mut self,
14953        action: &ExpandExcerptsDown,
14954        _: &mut Window,
14955        cx: &mut Context<Self>,
14956    ) {
14957        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14958    }
14959
14960    pub fn expand_excerpts_up(
14961        &mut self,
14962        action: &ExpandExcerptsUp,
14963        _: &mut Window,
14964        cx: &mut Context<Self>,
14965    ) {
14966        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14967    }
14968
14969    pub fn expand_excerpts_for_direction(
14970        &mut self,
14971        lines: u32,
14972        direction: ExpandExcerptDirection,
14973
14974        cx: &mut Context<Self>,
14975    ) {
14976        let selections = self.selections.disjoint_anchors();
14977
14978        let lines = if lines == 0 {
14979            EditorSettings::get_global(cx).expand_excerpt_lines
14980        } else {
14981            lines
14982        };
14983
14984        self.buffer.update(cx, |buffer, cx| {
14985            let snapshot = buffer.snapshot(cx);
14986            let mut excerpt_ids = selections
14987                .iter()
14988                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14989                .collect::<Vec<_>>();
14990            excerpt_ids.sort();
14991            excerpt_ids.dedup();
14992            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14993        })
14994    }
14995
14996    pub fn expand_excerpt(
14997        &mut self,
14998        excerpt: ExcerptId,
14999        direction: ExpandExcerptDirection,
15000        window: &mut Window,
15001        cx: &mut Context<Self>,
15002    ) {
15003        let current_scroll_position = self.scroll_position(cx);
15004        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15005        let mut should_scroll_up = false;
15006
15007        if direction == ExpandExcerptDirection::Down {
15008            let multi_buffer = self.buffer.read(cx);
15009            let snapshot = multi_buffer.snapshot(cx);
15010            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15011                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15012                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15013                        let buffer_snapshot = buffer.read(cx).snapshot();
15014                        let excerpt_end_row =
15015                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15016                        let last_row = buffer_snapshot.max_point().row;
15017                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15018                        should_scroll_up = lines_below >= lines_to_expand;
15019                    }
15020                }
15021            }
15022        }
15023
15024        self.buffer.update(cx, |buffer, cx| {
15025            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15026        });
15027
15028        if should_scroll_up {
15029            let new_scroll_position =
15030                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15031            self.set_scroll_position(new_scroll_position, window, cx);
15032        }
15033    }
15034
15035    pub fn go_to_singleton_buffer_point(
15036        &mut self,
15037        point: Point,
15038        window: &mut Window,
15039        cx: &mut Context<Self>,
15040    ) {
15041        self.go_to_singleton_buffer_range(point..point, window, cx);
15042    }
15043
15044    pub fn go_to_singleton_buffer_range(
15045        &mut self,
15046        range: Range<Point>,
15047        window: &mut Window,
15048        cx: &mut Context<Self>,
15049    ) {
15050        let multibuffer = self.buffer().read(cx);
15051        let Some(buffer) = multibuffer.as_singleton() else {
15052            return;
15053        };
15054        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15055            return;
15056        };
15057        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15058            return;
15059        };
15060        self.change_selections(
15061            SelectionEffects::default().nav_history(true),
15062            window,
15063            cx,
15064            |s| s.select_anchor_ranges([start..end]),
15065        );
15066    }
15067
15068    pub fn go_to_diagnostic(
15069        &mut self,
15070        action: &GoToDiagnostic,
15071        window: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        if !self.diagnostics_enabled() {
15075            return;
15076        }
15077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15078        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15079    }
15080
15081    pub fn go_to_prev_diagnostic(
15082        &mut self,
15083        action: &GoToPreviousDiagnostic,
15084        window: &mut Window,
15085        cx: &mut Context<Self>,
15086    ) {
15087        if !self.diagnostics_enabled() {
15088            return;
15089        }
15090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15091        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15092    }
15093
15094    pub fn go_to_diagnostic_impl(
15095        &mut self,
15096        direction: Direction,
15097        severity: GoToDiagnosticSeverityFilter,
15098        window: &mut Window,
15099        cx: &mut Context<Self>,
15100    ) {
15101        let buffer = self.buffer.read(cx).snapshot(cx);
15102        let selection = self.selections.newest::<usize>(cx);
15103
15104        let mut active_group_id = None;
15105        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15106            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15107                active_group_id = Some(active_group.group_id);
15108            }
15109        }
15110
15111        fn filtered(
15112            snapshot: EditorSnapshot,
15113            severity: GoToDiagnosticSeverityFilter,
15114            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15115        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15116            diagnostics
15117                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15118                .filter(|entry| entry.range.start != entry.range.end)
15119                .filter(|entry| !entry.diagnostic.is_unnecessary)
15120                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15121        }
15122
15123        let snapshot = self.snapshot(window, cx);
15124        let before = filtered(
15125            snapshot.clone(),
15126            severity,
15127            buffer
15128                .diagnostics_in_range(0..selection.start)
15129                .filter(|entry| entry.range.start <= selection.start),
15130        );
15131        let after = filtered(
15132            snapshot,
15133            severity,
15134            buffer
15135                .diagnostics_in_range(selection.start..buffer.len())
15136                .filter(|entry| entry.range.start >= selection.start),
15137        );
15138
15139        let mut found: Option<DiagnosticEntry<usize>> = None;
15140        if direction == Direction::Prev {
15141            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15142            {
15143                for diagnostic in prev_diagnostics.into_iter().rev() {
15144                    if diagnostic.range.start != selection.start
15145                        || active_group_id
15146                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15147                    {
15148                        found = Some(diagnostic);
15149                        break 'outer;
15150                    }
15151                }
15152            }
15153        } else {
15154            for diagnostic in after.chain(before) {
15155                if diagnostic.range.start != selection.start
15156                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15157                {
15158                    found = Some(diagnostic);
15159                    break;
15160                }
15161            }
15162        }
15163        let Some(next_diagnostic) = found else {
15164            return;
15165        };
15166
15167        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15168            return;
15169        };
15170        self.change_selections(Default::default(), window, cx, |s| {
15171            s.select_ranges(vec![
15172                next_diagnostic.range.start..next_diagnostic.range.start,
15173            ])
15174        });
15175        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15176        self.refresh_inline_completion(false, true, window, cx);
15177    }
15178
15179    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15181        let snapshot = self.snapshot(window, cx);
15182        let selection = self.selections.newest::<Point>(cx);
15183        self.go_to_hunk_before_or_after_position(
15184            &snapshot,
15185            selection.head(),
15186            Direction::Next,
15187            window,
15188            cx,
15189        );
15190    }
15191
15192    pub fn go_to_hunk_before_or_after_position(
15193        &mut self,
15194        snapshot: &EditorSnapshot,
15195        position: Point,
15196        direction: Direction,
15197        window: &mut Window,
15198        cx: &mut Context<Editor>,
15199    ) {
15200        let row = if direction == Direction::Next {
15201            self.hunk_after_position(snapshot, position)
15202                .map(|hunk| hunk.row_range.start)
15203        } else {
15204            self.hunk_before_position(snapshot, position)
15205        };
15206
15207        if let Some(row) = row {
15208            let destination = Point::new(row.0, 0);
15209            let autoscroll = Autoscroll::center();
15210
15211            self.unfold_ranges(&[destination..destination], false, false, cx);
15212            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15213                s.select_ranges([destination..destination]);
15214            });
15215        }
15216    }
15217
15218    fn hunk_after_position(
15219        &mut self,
15220        snapshot: &EditorSnapshot,
15221        position: Point,
15222    ) -> Option<MultiBufferDiffHunk> {
15223        snapshot
15224            .buffer_snapshot
15225            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15226            .find(|hunk| hunk.row_range.start.0 > position.row)
15227            .or_else(|| {
15228                snapshot
15229                    .buffer_snapshot
15230                    .diff_hunks_in_range(Point::zero()..position)
15231                    .find(|hunk| hunk.row_range.end.0 < position.row)
15232            })
15233    }
15234
15235    fn go_to_prev_hunk(
15236        &mut self,
15237        _: &GoToPreviousHunk,
15238        window: &mut Window,
15239        cx: &mut Context<Self>,
15240    ) {
15241        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15242        let snapshot = self.snapshot(window, cx);
15243        let selection = self.selections.newest::<Point>(cx);
15244        self.go_to_hunk_before_or_after_position(
15245            &snapshot,
15246            selection.head(),
15247            Direction::Prev,
15248            window,
15249            cx,
15250        );
15251    }
15252
15253    fn hunk_before_position(
15254        &mut self,
15255        snapshot: &EditorSnapshot,
15256        position: Point,
15257    ) -> Option<MultiBufferRow> {
15258        snapshot
15259            .buffer_snapshot
15260            .diff_hunk_before(position)
15261            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15262    }
15263
15264    fn go_to_next_change(
15265        &mut self,
15266        _: &GoToNextChange,
15267        window: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) {
15270        if let Some(selections) = self
15271            .change_list
15272            .next_change(1, Direction::Next)
15273            .map(|s| s.to_vec())
15274        {
15275            self.change_selections(Default::default(), window, cx, |s| {
15276                let map = s.display_map();
15277                s.select_display_ranges(selections.iter().map(|a| {
15278                    let point = a.to_display_point(&map);
15279                    point..point
15280                }))
15281            })
15282        }
15283    }
15284
15285    fn go_to_previous_change(
15286        &mut self,
15287        _: &GoToPreviousChange,
15288        window: &mut Window,
15289        cx: &mut Context<Self>,
15290    ) {
15291        if let Some(selections) = self
15292            .change_list
15293            .next_change(1, Direction::Prev)
15294            .map(|s| s.to_vec())
15295        {
15296            self.change_selections(Default::default(), window, cx, |s| {
15297                let map = s.display_map();
15298                s.select_display_ranges(selections.iter().map(|a| {
15299                    let point = a.to_display_point(&map);
15300                    point..point
15301                }))
15302            })
15303        }
15304    }
15305
15306    fn go_to_line<T: 'static>(
15307        &mut self,
15308        position: Anchor,
15309        highlight_color: Option<Hsla>,
15310        window: &mut Window,
15311        cx: &mut Context<Self>,
15312    ) {
15313        let snapshot = self.snapshot(window, cx).display_snapshot;
15314        let position = position.to_point(&snapshot.buffer_snapshot);
15315        let start = snapshot
15316            .buffer_snapshot
15317            .clip_point(Point::new(position.row, 0), Bias::Left);
15318        let end = start + Point::new(1, 0);
15319        let start = snapshot.buffer_snapshot.anchor_before(start);
15320        let end = snapshot.buffer_snapshot.anchor_before(end);
15321
15322        self.highlight_rows::<T>(
15323            start..end,
15324            highlight_color
15325                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15326            Default::default(),
15327            cx,
15328        );
15329
15330        if self.buffer.read(cx).is_singleton() {
15331            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15332        }
15333    }
15334
15335    pub fn go_to_definition(
15336        &mut self,
15337        _: &GoToDefinition,
15338        window: &mut Window,
15339        cx: &mut Context<Self>,
15340    ) -> Task<Result<Navigated>> {
15341        let definition =
15342            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15343        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15344        cx.spawn_in(window, async move |editor, cx| {
15345            if definition.await? == Navigated::Yes {
15346                return Ok(Navigated::Yes);
15347            }
15348            match fallback_strategy {
15349                GoToDefinitionFallback::None => Ok(Navigated::No),
15350                GoToDefinitionFallback::FindAllReferences => {
15351                    match editor.update_in(cx, |editor, window, cx| {
15352                        editor.find_all_references(&FindAllReferences, window, cx)
15353                    })? {
15354                        Some(references) => references.await,
15355                        None => Ok(Navigated::No),
15356                    }
15357                }
15358            }
15359        })
15360    }
15361
15362    pub fn go_to_declaration(
15363        &mut self,
15364        _: &GoToDeclaration,
15365        window: &mut Window,
15366        cx: &mut Context<Self>,
15367    ) -> Task<Result<Navigated>> {
15368        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15369    }
15370
15371    pub fn go_to_declaration_split(
15372        &mut self,
15373        _: &GoToDeclaration,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) -> Task<Result<Navigated>> {
15377        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15378    }
15379
15380    pub fn go_to_implementation(
15381        &mut self,
15382        _: &GoToImplementation,
15383        window: &mut Window,
15384        cx: &mut Context<Self>,
15385    ) -> Task<Result<Navigated>> {
15386        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15387    }
15388
15389    pub fn go_to_implementation_split(
15390        &mut self,
15391        _: &GoToImplementationSplit,
15392        window: &mut Window,
15393        cx: &mut Context<Self>,
15394    ) -> Task<Result<Navigated>> {
15395        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15396    }
15397
15398    pub fn go_to_type_definition(
15399        &mut self,
15400        _: &GoToTypeDefinition,
15401        window: &mut Window,
15402        cx: &mut Context<Self>,
15403    ) -> Task<Result<Navigated>> {
15404        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15405    }
15406
15407    pub fn go_to_definition_split(
15408        &mut self,
15409        _: &GoToDefinitionSplit,
15410        window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) -> Task<Result<Navigated>> {
15413        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15414    }
15415
15416    pub fn go_to_type_definition_split(
15417        &mut self,
15418        _: &GoToTypeDefinitionSplit,
15419        window: &mut Window,
15420        cx: &mut Context<Self>,
15421    ) -> Task<Result<Navigated>> {
15422        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15423    }
15424
15425    fn go_to_definition_of_kind(
15426        &mut self,
15427        kind: GotoDefinitionKind,
15428        split: bool,
15429        window: &mut Window,
15430        cx: &mut Context<Self>,
15431    ) -> Task<Result<Navigated>> {
15432        let Some(provider) = self.semantics_provider.clone() else {
15433            return Task::ready(Ok(Navigated::No));
15434        };
15435        let head = self.selections.newest::<usize>(cx).head();
15436        let buffer = self.buffer.read(cx);
15437        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15438            text_anchor
15439        } else {
15440            return Task::ready(Ok(Navigated::No));
15441        };
15442
15443        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15444            return Task::ready(Ok(Navigated::No));
15445        };
15446
15447        cx.spawn_in(window, async move |editor, cx| {
15448            let definitions = definitions.await?;
15449            let navigated = editor
15450                .update_in(cx, |editor, window, cx| {
15451                    editor.navigate_to_hover_links(
15452                        Some(kind),
15453                        definitions
15454                            .into_iter()
15455                            .filter(|location| {
15456                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15457                            })
15458                            .map(HoverLink::Text)
15459                            .collect::<Vec<_>>(),
15460                        split,
15461                        window,
15462                        cx,
15463                    )
15464                })?
15465                .await?;
15466            anyhow::Ok(navigated)
15467        })
15468    }
15469
15470    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15471        let selection = self.selections.newest_anchor();
15472        let head = selection.head();
15473        let tail = selection.tail();
15474
15475        let Some((buffer, start_position)) =
15476            self.buffer.read(cx).text_anchor_for_position(head, cx)
15477        else {
15478            return;
15479        };
15480
15481        let end_position = if head != tail {
15482            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15483                return;
15484            };
15485            Some(pos)
15486        } else {
15487            None
15488        };
15489
15490        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15491            let url = if let Some(end_pos) = end_position {
15492                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15493            } else {
15494                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15495            };
15496
15497            if let Some(url) = url {
15498                editor.update(cx, |_, cx| {
15499                    cx.open_url(&url);
15500                })
15501            } else {
15502                Ok(())
15503            }
15504        });
15505
15506        url_finder.detach();
15507    }
15508
15509    pub fn open_selected_filename(
15510        &mut self,
15511        _: &OpenSelectedFilename,
15512        window: &mut Window,
15513        cx: &mut Context<Self>,
15514    ) {
15515        let Some(workspace) = self.workspace() else {
15516            return;
15517        };
15518
15519        let position = self.selections.newest_anchor().head();
15520
15521        let Some((buffer, buffer_position)) =
15522            self.buffer.read(cx).text_anchor_for_position(position, cx)
15523        else {
15524            return;
15525        };
15526
15527        let project = self.project.clone();
15528
15529        cx.spawn_in(window, async move |_, cx| {
15530            let result = find_file(&buffer, project, buffer_position, cx).await;
15531
15532            if let Some((_, path)) = result {
15533                workspace
15534                    .update_in(cx, |workspace, window, cx| {
15535                        workspace.open_resolved_path(path, window, cx)
15536                    })?
15537                    .await?;
15538            }
15539            anyhow::Ok(())
15540        })
15541        .detach();
15542    }
15543
15544    pub(crate) fn navigate_to_hover_links(
15545        &mut self,
15546        kind: Option<GotoDefinitionKind>,
15547        mut definitions: Vec<HoverLink>,
15548        split: bool,
15549        window: &mut Window,
15550        cx: &mut Context<Editor>,
15551    ) -> Task<Result<Navigated>> {
15552        // If there is one definition, just open it directly
15553        if definitions.len() == 1 {
15554            let definition = definitions.pop().unwrap();
15555
15556            enum TargetTaskResult {
15557                Location(Option<Location>),
15558                AlreadyNavigated,
15559            }
15560
15561            let target_task = match definition {
15562                HoverLink::Text(link) => {
15563                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15564                }
15565                HoverLink::InlayHint(lsp_location, server_id) => {
15566                    let computation =
15567                        self.compute_target_location(lsp_location, server_id, window, cx);
15568                    cx.background_spawn(async move {
15569                        let location = computation.await?;
15570                        Ok(TargetTaskResult::Location(location))
15571                    })
15572                }
15573                HoverLink::Url(url) => {
15574                    cx.open_url(&url);
15575                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15576                }
15577                HoverLink::File(path) => {
15578                    if let Some(workspace) = self.workspace() {
15579                        cx.spawn_in(window, async move |_, cx| {
15580                            workspace
15581                                .update_in(cx, |workspace, window, cx| {
15582                                    workspace.open_resolved_path(path, window, cx)
15583                                })?
15584                                .await
15585                                .map(|_| TargetTaskResult::AlreadyNavigated)
15586                        })
15587                    } else {
15588                        Task::ready(Ok(TargetTaskResult::Location(None)))
15589                    }
15590                }
15591            };
15592            cx.spawn_in(window, async move |editor, cx| {
15593                let target = match target_task.await.context("target resolution task")? {
15594                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15595                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15596                    TargetTaskResult::Location(Some(target)) => target,
15597                };
15598
15599                editor.update_in(cx, |editor, window, cx| {
15600                    let Some(workspace) = editor.workspace() else {
15601                        return Navigated::No;
15602                    };
15603                    let pane = workspace.read(cx).active_pane().clone();
15604
15605                    let range = target.range.to_point(target.buffer.read(cx));
15606                    let range = editor.range_for_match(&range);
15607                    let range = collapse_multiline_range(range);
15608
15609                    if !split
15610                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15611                    {
15612                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15613                    } else {
15614                        window.defer(cx, move |window, cx| {
15615                            let target_editor: Entity<Self> =
15616                                workspace.update(cx, |workspace, cx| {
15617                                    let pane = if split {
15618                                        workspace.adjacent_pane(window, cx)
15619                                    } else {
15620                                        workspace.active_pane().clone()
15621                                    };
15622
15623                                    workspace.open_project_item(
15624                                        pane,
15625                                        target.buffer.clone(),
15626                                        true,
15627                                        true,
15628                                        window,
15629                                        cx,
15630                                    )
15631                                });
15632                            target_editor.update(cx, |target_editor, cx| {
15633                                // When selecting a definition in a different buffer, disable the nav history
15634                                // to avoid creating a history entry at the previous cursor location.
15635                                pane.update(cx, |pane, _| pane.disable_history());
15636                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15637                                pane.update(cx, |pane, _| pane.enable_history());
15638                            });
15639                        });
15640                    }
15641                    Navigated::Yes
15642                })
15643            })
15644        } else if !definitions.is_empty() {
15645            cx.spawn_in(window, async move |editor, cx| {
15646                let (title, location_tasks, workspace) = editor
15647                    .update_in(cx, |editor, window, cx| {
15648                        let tab_kind = match kind {
15649                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15650                            _ => "Definitions",
15651                        };
15652                        let title = definitions
15653                            .iter()
15654                            .find_map(|definition| match definition {
15655                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15656                                    let buffer = origin.buffer.read(cx);
15657                                    format!(
15658                                        "{} for {}",
15659                                        tab_kind,
15660                                        buffer
15661                                            .text_for_range(origin.range.clone())
15662                                            .collect::<String>()
15663                                    )
15664                                }),
15665                                HoverLink::InlayHint(_, _) => None,
15666                                HoverLink::Url(_) => None,
15667                                HoverLink::File(_) => None,
15668                            })
15669                            .unwrap_or(tab_kind.to_string());
15670                        let location_tasks = definitions
15671                            .into_iter()
15672                            .map(|definition| match definition {
15673                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15674                                HoverLink::InlayHint(lsp_location, server_id) => editor
15675                                    .compute_target_location(lsp_location, server_id, window, cx),
15676                                HoverLink::Url(_) => Task::ready(Ok(None)),
15677                                HoverLink::File(_) => Task::ready(Ok(None)),
15678                            })
15679                            .collect::<Vec<_>>();
15680                        (title, location_tasks, editor.workspace().clone())
15681                    })
15682                    .context("location tasks preparation")?;
15683
15684                let locations: Vec<Location> = future::join_all(location_tasks)
15685                    .await
15686                    .into_iter()
15687                    .filter_map(|location| location.transpose())
15688                    .collect::<Result<_>>()
15689                    .context("location tasks")?;
15690
15691                if locations.is_empty() {
15692                    return Ok(Navigated::No);
15693                }
15694
15695                let Some(workspace) = workspace else {
15696                    return Ok(Navigated::No);
15697                };
15698
15699                let opened = workspace
15700                    .update_in(cx, |workspace, window, cx| {
15701                        Self::open_locations_in_multibuffer(
15702                            workspace,
15703                            locations,
15704                            title,
15705                            split,
15706                            MultibufferSelectionMode::First,
15707                            window,
15708                            cx,
15709                        )
15710                    })
15711                    .ok();
15712
15713                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15714            })
15715        } else {
15716            Task::ready(Ok(Navigated::No))
15717        }
15718    }
15719
15720    fn compute_target_location(
15721        &self,
15722        lsp_location: lsp::Location,
15723        server_id: LanguageServerId,
15724        window: &mut Window,
15725        cx: &mut Context<Self>,
15726    ) -> Task<anyhow::Result<Option<Location>>> {
15727        let Some(project) = self.project.clone() else {
15728            return Task::ready(Ok(None));
15729        };
15730
15731        cx.spawn_in(window, async move |editor, cx| {
15732            let location_task = editor.update(cx, |_, cx| {
15733                project.update(cx, |project, cx| {
15734                    let language_server_name = project
15735                        .language_server_statuses(cx)
15736                        .find(|(id, _)| server_id == *id)
15737                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15738                    language_server_name.map(|language_server_name| {
15739                        project.open_local_buffer_via_lsp(
15740                            lsp_location.uri.clone(),
15741                            server_id,
15742                            language_server_name,
15743                            cx,
15744                        )
15745                    })
15746                })
15747            })?;
15748            let location = match location_task {
15749                Some(task) => Some({
15750                    let target_buffer_handle = task.await.context("open local buffer")?;
15751                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15752                        let target_start = target_buffer
15753                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15754                        let target_end = target_buffer
15755                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15756                        target_buffer.anchor_after(target_start)
15757                            ..target_buffer.anchor_before(target_end)
15758                    })?;
15759                    Location {
15760                        buffer: target_buffer_handle,
15761                        range,
15762                    }
15763                }),
15764                None => None,
15765            };
15766            Ok(location)
15767        })
15768    }
15769
15770    pub fn find_all_references(
15771        &mut self,
15772        _: &FindAllReferences,
15773        window: &mut Window,
15774        cx: &mut Context<Self>,
15775    ) -> Option<Task<Result<Navigated>>> {
15776        let selection = self.selections.newest::<usize>(cx);
15777        let multi_buffer = self.buffer.read(cx);
15778        let head = selection.head();
15779
15780        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15781        let head_anchor = multi_buffer_snapshot.anchor_at(
15782            head,
15783            if head < selection.tail() {
15784                Bias::Right
15785            } else {
15786                Bias::Left
15787            },
15788        );
15789
15790        match self
15791            .find_all_references_task_sources
15792            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15793        {
15794            Ok(_) => {
15795                log::info!(
15796                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15797                );
15798                return None;
15799            }
15800            Err(i) => {
15801                self.find_all_references_task_sources.insert(i, head_anchor);
15802            }
15803        }
15804
15805        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15806        let workspace = self.workspace()?;
15807        let project = workspace.read(cx).project().clone();
15808        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15809        Some(cx.spawn_in(window, async move |editor, cx| {
15810            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15811                if let Ok(i) = editor
15812                    .find_all_references_task_sources
15813                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15814                {
15815                    editor.find_all_references_task_sources.remove(i);
15816                }
15817            });
15818
15819            let locations = references.await?;
15820            if locations.is_empty() {
15821                return anyhow::Ok(Navigated::No);
15822            }
15823
15824            workspace.update_in(cx, |workspace, window, cx| {
15825                let title = locations
15826                    .first()
15827                    .as_ref()
15828                    .map(|location| {
15829                        let buffer = location.buffer.read(cx);
15830                        format!(
15831                            "References to `{}`",
15832                            buffer
15833                                .text_for_range(location.range.clone())
15834                                .collect::<String>()
15835                        )
15836                    })
15837                    .unwrap();
15838                Self::open_locations_in_multibuffer(
15839                    workspace,
15840                    locations,
15841                    title,
15842                    false,
15843                    MultibufferSelectionMode::First,
15844                    window,
15845                    cx,
15846                );
15847                Navigated::Yes
15848            })
15849        }))
15850    }
15851
15852    /// Opens a multibuffer with the given project locations in it
15853    pub fn open_locations_in_multibuffer(
15854        workspace: &mut Workspace,
15855        mut locations: Vec<Location>,
15856        title: String,
15857        split: bool,
15858        multibuffer_selection_mode: MultibufferSelectionMode,
15859        window: &mut Window,
15860        cx: &mut Context<Workspace>,
15861    ) {
15862        if locations.is_empty() {
15863            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15864            return;
15865        }
15866
15867        // If there are multiple definitions, open them in a multibuffer
15868        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15869        let mut locations = locations.into_iter().peekable();
15870        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15871        let capability = workspace.project().read(cx).capability();
15872
15873        let excerpt_buffer = cx.new(|cx| {
15874            let mut multibuffer = MultiBuffer::new(capability);
15875            while let Some(location) = locations.next() {
15876                let buffer = location.buffer.read(cx);
15877                let mut ranges_for_buffer = Vec::new();
15878                let range = location.range.to_point(buffer);
15879                ranges_for_buffer.push(range.clone());
15880
15881                while let Some(next_location) = locations.peek() {
15882                    if next_location.buffer == location.buffer {
15883                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15884                        locations.next();
15885                    } else {
15886                        break;
15887                    }
15888                }
15889
15890                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15891                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15892                    PathKey::for_buffer(&location.buffer, cx),
15893                    location.buffer.clone(),
15894                    ranges_for_buffer,
15895                    DEFAULT_MULTIBUFFER_CONTEXT,
15896                    cx,
15897                );
15898                ranges.extend(new_ranges)
15899            }
15900
15901            multibuffer.with_title(title)
15902        });
15903
15904        let editor = cx.new(|cx| {
15905            Editor::for_multibuffer(
15906                excerpt_buffer,
15907                Some(workspace.project().clone()),
15908                window,
15909                cx,
15910            )
15911        });
15912        editor.update(cx, |editor, cx| {
15913            match multibuffer_selection_mode {
15914                MultibufferSelectionMode::First => {
15915                    if let Some(first_range) = ranges.first() {
15916                        editor.change_selections(
15917                            SelectionEffects::no_scroll(),
15918                            window,
15919                            cx,
15920                            |selections| {
15921                                selections.clear_disjoint();
15922                                selections
15923                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
15924                            },
15925                        );
15926                    }
15927                    editor.highlight_background::<Self>(
15928                        &ranges,
15929                        |theme| theme.colors().editor_highlighted_line_background,
15930                        cx,
15931                    );
15932                }
15933                MultibufferSelectionMode::All => {
15934                    editor.change_selections(
15935                        SelectionEffects::no_scroll(),
15936                        window,
15937                        cx,
15938                        |selections| {
15939                            selections.clear_disjoint();
15940                            selections.select_anchor_ranges(ranges);
15941                        },
15942                    );
15943                }
15944            }
15945            editor.register_buffers_with_language_servers(cx);
15946        });
15947
15948        let item = Box::new(editor);
15949        let item_id = item.item_id();
15950
15951        if split {
15952            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15953        } else {
15954            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15955                let (preview_item_id, preview_item_idx) =
15956                    workspace.active_pane().read_with(cx, |pane, _| {
15957                        (pane.preview_item_id(), pane.preview_item_idx())
15958                    });
15959
15960                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15961
15962                if let Some(preview_item_id) = preview_item_id {
15963                    workspace.active_pane().update(cx, |pane, cx| {
15964                        pane.remove_item(preview_item_id, false, false, window, cx);
15965                    });
15966                }
15967            } else {
15968                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15969            }
15970        }
15971        workspace.active_pane().update(cx, |pane, cx| {
15972            pane.set_preview_item_id(Some(item_id), cx);
15973        });
15974    }
15975
15976    pub fn rename(
15977        &mut self,
15978        _: &Rename,
15979        window: &mut Window,
15980        cx: &mut Context<Self>,
15981    ) -> Option<Task<Result<()>>> {
15982        use language::ToOffset as _;
15983
15984        let provider = self.semantics_provider.clone()?;
15985        let selection = self.selections.newest_anchor().clone();
15986        let (cursor_buffer, cursor_buffer_position) = self
15987            .buffer
15988            .read(cx)
15989            .text_anchor_for_position(selection.head(), cx)?;
15990        let (tail_buffer, cursor_buffer_position_end) = self
15991            .buffer
15992            .read(cx)
15993            .text_anchor_for_position(selection.tail(), cx)?;
15994        if tail_buffer != cursor_buffer {
15995            return None;
15996        }
15997
15998        let snapshot = cursor_buffer.read(cx).snapshot();
15999        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16000        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16001        let prepare_rename = provider
16002            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16003            .unwrap_or_else(|| Task::ready(Ok(None)));
16004        drop(snapshot);
16005
16006        Some(cx.spawn_in(window, async move |this, cx| {
16007            let rename_range = if let Some(range) = prepare_rename.await? {
16008                Some(range)
16009            } else {
16010                this.update(cx, |this, cx| {
16011                    let buffer = this.buffer.read(cx).snapshot(cx);
16012                    let mut buffer_highlights = this
16013                        .document_highlights_for_position(selection.head(), &buffer)
16014                        .filter(|highlight| {
16015                            highlight.start.excerpt_id == selection.head().excerpt_id
16016                                && highlight.end.excerpt_id == selection.head().excerpt_id
16017                        });
16018                    buffer_highlights
16019                        .next()
16020                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16021                })?
16022            };
16023            if let Some(rename_range) = rename_range {
16024                this.update_in(cx, |this, window, cx| {
16025                    let snapshot = cursor_buffer.read(cx).snapshot();
16026                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16027                    let cursor_offset_in_rename_range =
16028                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16029                    let cursor_offset_in_rename_range_end =
16030                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16031
16032                    this.take_rename(false, window, cx);
16033                    let buffer = this.buffer.read(cx).read(cx);
16034                    let cursor_offset = selection.head().to_offset(&buffer);
16035                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16036                    let rename_end = rename_start + rename_buffer_range.len();
16037                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16038                    let mut old_highlight_id = None;
16039                    let old_name: Arc<str> = buffer
16040                        .chunks(rename_start..rename_end, true)
16041                        .map(|chunk| {
16042                            if old_highlight_id.is_none() {
16043                                old_highlight_id = chunk.syntax_highlight_id;
16044                            }
16045                            chunk.text
16046                        })
16047                        .collect::<String>()
16048                        .into();
16049
16050                    drop(buffer);
16051
16052                    // Position the selection in the rename editor so that it matches the current selection.
16053                    this.show_local_selections = false;
16054                    let rename_editor = cx.new(|cx| {
16055                        let mut editor = Editor::single_line(window, cx);
16056                        editor.buffer.update(cx, |buffer, cx| {
16057                            buffer.edit([(0..0, old_name.clone())], None, cx)
16058                        });
16059                        let rename_selection_range = match cursor_offset_in_rename_range
16060                            .cmp(&cursor_offset_in_rename_range_end)
16061                        {
16062                            Ordering::Equal => {
16063                                editor.select_all(&SelectAll, window, cx);
16064                                return editor;
16065                            }
16066                            Ordering::Less => {
16067                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16068                            }
16069                            Ordering::Greater => {
16070                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16071                            }
16072                        };
16073                        if rename_selection_range.end > old_name.len() {
16074                            editor.select_all(&SelectAll, window, cx);
16075                        } else {
16076                            editor.change_selections(Default::default(), window, cx, |s| {
16077                                s.select_ranges([rename_selection_range]);
16078                            });
16079                        }
16080                        editor
16081                    });
16082                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16083                        if e == &EditorEvent::Focused {
16084                            cx.emit(EditorEvent::FocusedIn)
16085                        }
16086                    })
16087                    .detach();
16088
16089                    let write_highlights =
16090                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16091                    let read_highlights =
16092                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16093                    let ranges = write_highlights
16094                        .iter()
16095                        .flat_map(|(_, ranges)| ranges.iter())
16096                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16097                        .cloned()
16098                        .collect();
16099
16100                    this.highlight_text::<Rename>(
16101                        ranges,
16102                        HighlightStyle {
16103                            fade_out: Some(0.6),
16104                            ..Default::default()
16105                        },
16106                        cx,
16107                    );
16108                    let rename_focus_handle = rename_editor.focus_handle(cx);
16109                    window.focus(&rename_focus_handle);
16110                    let block_id = this.insert_blocks(
16111                        [BlockProperties {
16112                            style: BlockStyle::Flex,
16113                            placement: BlockPlacement::Below(range.start),
16114                            height: Some(1),
16115                            render: Arc::new({
16116                                let rename_editor = rename_editor.clone();
16117                                move |cx: &mut BlockContext| {
16118                                    let mut text_style = cx.editor_style.text.clone();
16119                                    if let Some(highlight_style) = old_highlight_id
16120                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16121                                    {
16122                                        text_style = text_style.highlight(highlight_style);
16123                                    }
16124                                    div()
16125                                        .block_mouse_except_scroll()
16126                                        .pl(cx.anchor_x)
16127                                        .child(EditorElement::new(
16128                                            &rename_editor,
16129                                            EditorStyle {
16130                                                background: cx.theme().system().transparent,
16131                                                local_player: cx.editor_style.local_player,
16132                                                text: text_style,
16133                                                scrollbar_width: cx.editor_style.scrollbar_width,
16134                                                syntax: cx.editor_style.syntax.clone(),
16135                                                status: cx.editor_style.status.clone(),
16136                                                inlay_hints_style: HighlightStyle {
16137                                                    font_weight: Some(FontWeight::BOLD),
16138                                                    ..make_inlay_hints_style(cx.app)
16139                                                },
16140                                                inline_completion_styles: make_suggestion_styles(
16141                                                    cx.app,
16142                                                ),
16143                                                ..EditorStyle::default()
16144                                            },
16145                                        ))
16146                                        .into_any_element()
16147                                }
16148                            }),
16149                            priority: 0,
16150                        }],
16151                        Some(Autoscroll::fit()),
16152                        cx,
16153                    )[0];
16154                    this.pending_rename = Some(RenameState {
16155                        range,
16156                        old_name,
16157                        editor: rename_editor,
16158                        block_id,
16159                    });
16160                })?;
16161            }
16162
16163            Ok(())
16164        }))
16165    }
16166
16167    pub fn confirm_rename(
16168        &mut self,
16169        _: &ConfirmRename,
16170        window: &mut Window,
16171        cx: &mut Context<Self>,
16172    ) -> Option<Task<Result<()>>> {
16173        let rename = self.take_rename(false, window, cx)?;
16174        let workspace = self.workspace()?.downgrade();
16175        let (buffer, start) = self
16176            .buffer
16177            .read(cx)
16178            .text_anchor_for_position(rename.range.start, cx)?;
16179        let (end_buffer, _) = self
16180            .buffer
16181            .read(cx)
16182            .text_anchor_for_position(rename.range.end, cx)?;
16183        if buffer != end_buffer {
16184            return None;
16185        }
16186
16187        let old_name = rename.old_name;
16188        let new_name = rename.editor.read(cx).text(cx);
16189
16190        let rename = self.semantics_provider.as_ref()?.perform_rename(
16191            &buffer,
16192            start,
16193            new_name.clone(),
16194            cx,
16195        )?;
16196
16197        Some(cx.spawn_in(window, async move |editor, cx| {
16198            let project_transaction = rename.await?;
16199            Self::open_project_transaction(
16200                &editor,
16201                workspace,
16202                project_transaction,
16203                format!("Rename: {}{}", old_name, new_name),
16204                cx,
16205            )
16206            .await?;
16207
16208            editor.update(cx, |editor, cx| {
16209                editor.refresh_document_highlights(cx);
16210            })?;
16211            Ok(())
16212        }))
16213    }
16214
16215    fn take_rename(
16216        &mut self,
16217        moving_cursor: bool,
16218        window: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) -> Option<RenameState> {
16221        let rename = self.pending_rename.take()?;
16222        if rename.editor.focus_handle(cx).is_focused(window) {
16223            window.focus(&self.focus_handle);
16224        }
16225
16226        self.remove_blocks(
16227            [rename.block_id].into_iter().collect(),
16228            Some(Autoscroll::fit()),
16229            cx,
16230        );
16231        self.clear_highlights::<Rename>(cx);
16232        self.show_local_selections = true;
16233
16234        if moving_cursor {
16235            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16236                editor.selections.newest::<usize>(cx).head()
16237            });
16238
16239            // Update the selection to match the position of the selection inside
16240            // the rename editor.
16241            let snapshot = self.buffer.read(cx).read(cx);
16242            let rename_range = rename.range.to_offset(&snapshot);
16243            let cursor_in_editor = snapshot
16244                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16245                .min(rename_range.end);
16246            drop(snapshot);
16247
16248            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16249                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16250            });
16251        } else {
16252            self.refresh_document_highlights(cx);
16253        }
16254
16255        Some(rename)
16256    }
16257
16258    pub fn pending_rename(&self) -> Option<&RenameState> {
16259        self.pending_rename.as_ref()
16260    }
16261
16262    fn format(
16263        &mut self,
16264        _: &Format,
16265        window: &mut Window,
16266        cx: &mut Context<Self>,
16267    ) -> Option<Task<Result<()>>> {
16268        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16269
16270        let project = match &self.project {
16271            Some(project) => project.clone(),
16272            None => return None,
16273        };
16274
16275        Some(self.perform_format(
16276            project,
16277            FormatTrigger::Manual,
16278            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16279            window,
16280            cx,
16281        ))
16282    }
16283
16284    fn format_selections(
16285        &mut self,
16286        _: &FormatSelections,
16287        window: &mut Window,
16288        cx: &mut Context<Self>,
16289    ) -> Option<Task<Result<()>>> {
16290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16291
16292        let project = match &self.project {
16293            Some(project) => project.clone(),
16294            None => return None,
16295        };
16296
16297        let ranges = self
16298            .selections
16299            .all_adjusted(cx)
16300            .into_iter()
16301            .map(|selection| selection.range())
16302            .collect_vec();
16303
16304        Some(self.perform_format(
16305            project,
16306            FormatTrigger::Manual,
16307            FormatTarget::Ranges(ranges),
16308            window,
16309            cx,
16310        ))
16311    }
16312
16313    fn perform_format(
16314        &mut self,
16315        project: Entity<Project>,
16316        trigger: FormatTrigger,
16317        target: FormatTarget,
16318        window: &mut Window,
16319        cx: &mut Context<Self>,
16320    ) -> Task<Result<()>> {
16321        let buffer = self.buffer.clone();
16322        let (buffers, target) = match target {
16323            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16324            FormatTarget::Ranges(selection_ranges) => {
16325                let multi_buffer = buffer.read(cx);
16326                let snapshot = multi_buffer.read(cx);
16327                let mut buffers = HashSet::default();
16328                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16329                    BTreeMap::new();
16330                for selection_range in selection_ranges {
16331                    for (buffer, buffer_range, _) in
16332                        snapshot.range_to_buffer_ranges(selection_range)
16333                    {
16334                        let buffer_id = buffer.remote_id();
16335                        let start = buffer.anchor_before(buffer_range.start);
16336                        let end = buffer.anchor_after(buffer_range.end);
16337                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16338                        buffer_id_to_ranges
16339                            .entry(buffer_id)
16340                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16341                            .or_insert_with(|| vec![start..end]);
16342                    }
16343                }
16344                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16345            }
16346        };
16347
16348        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16349        let selections_prev = transaction_id_prev
16350            .and_then(|transaction_id_prev| {
16351                // default to selections as they were after the last edit, if we have them,
16352                // instead of how they are now.
16353                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16354                // will take you back to where you made the last edit, instead of staying where you scrolled
16355                self.selection_history
16356                    .transaction(transaction_id_prev)
16357                    .map(|t| t.0.clone())
16358            })
16359            .unwrap_or_else(|| {
16360                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16361                self.selections.disjoint_anchors()
16362            });
16363
16364        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16365        let format = project.update(cx, |project, cx| {
16366            project.format(buffers, target, true, trigger, cx)
16367        });
16368
16369        cx.spawn_in(window, async move |editor, cx| {
16370            let transaction = futures::select_biased! {
16371                transaction = format.log_err().fuse() => transaction,
16372                () = timeout => {
16373                    log::warn!("timed out waiting for formatting");
16374                    None
16375                }
16376            };
16377
16378            buffer
16379                .update(cx, |buffer, cx| {
16380                    if let Some(transaction) = transaction {
16381                        if !buffer.is_singleton() {
16382                            buffer.push_transaction(&transaction.0, cx);
16383                        }
16384                    }
16385                    cx.notify();
16386                })
16387                .ok();
16388
16389            if let Some(transaction_id_now) =
16390                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16391            {
16392                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16393                if has_new_transaction {
16394                    _ = editor.update(cx, |editor, _| {
16395                        editor
16396                            .selection_history
16397                            .insert_transaction(transaction_id_now, selections_prev);
16398                    });
16399                }
16400            }
16401
16402            Ok(())
16403        })
16404    }
16405
16406    fn organize_imports(
16407        &mut self,
16408        _: &OrganizeImports,
16409        window: &mut Window,
16410        cx: &mut Context<Self>,
16411    ) -> Option<Task<Result<()>>> {
16412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16413        let project = match &self.project {
16414            Some(project) => project.clone(),
16415            None => return None,
16416        };
16417        Some(self.perform_code_action_kind(
16418            project,
16419            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16420            window,
16421            cx,
16422        ))
16423    }
16424
16425    fn perform_code_action_kind(
16426        &mut self,
16427        project: Entity<Project>,
16428        kind: CodeActionKind,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) -> Task<Result<()>> {
16432        let buffer = self.buffer.clone();
16433        let buffers = buffer.read(cx).all_buffers();
16434        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16435        let apply_action = project.update(cx, |project, cx| {
16436            project.apply_code_action_kind(buffers, kind, true, cx)
16437        });
16438        cx.spawn_in(window, async move |_, cx| {
16439            let transaction = futures::select_biased! {
16440                () = timeout => {
16441                    log::warn!("timed out waiting for executing code action");
16442                    None
16443                }
16444                transaction = apply_action.log_err().fuse() => transaction,
16445            };
16446            buffer
16447                .update(cx, |buffer, cx| {
16448                    // check if we need this
16449                    if let Some(transaction) = transaction {
16450                        if !buffer.is_singleton() {
16451                            buffer.push_transaction(&transaction.0, cx);
16452                        }
16453                    }
16454                    cx.notify();
16455                })
16456                .ok();
16457            Ok(())
16458        })
16459    }
16460
16461    pub fn restart_language_server(
16462        &mut self,
16463        _: &RestartLanguageServer,
16464        _: &mut Window,
16465        cx: &mut Context<Self>,
16466    ) {
16467        if let Some(project) = self.project.clone() {
16468            self.buffer.update(cx, |multi_buffer, cx| {
16469                project.update(cx, |project, cx| {
16470                    project.restart_language_servers_for_buffers(
16471                        multi_buffer.all_buffers().into_iter().collect(),
16472                        HashSet::default(),
16473                        cx,
16474                    );
16475                });
16476            })
16477        }
16478    }
16479
16480    pub fn stop_language_server(
16481        &mut self,
16482        _: &StopLanguageServer,
16483        _: &mut Window,
16484        cx: &mut Context<Self>,
16485    ) {
16486        if let Some(project) = self.project.clone() {
16487            self.buffer.update(cx, |multi_buffer, cx| {
16488                project.update(cx, |project, cx| {
16489                    project.stop_language_servers_for_buffers(
16490                        multi_buffer.all_buffers().into_iter().collect(),
16491                        HashSet::default(),
16492                        cx,
16493                    );
16494                    cx.emit(project::Event::RefreshInlayHints);
16495                });
16496            });
16497        }
16498    }
16499
16500    fn cancel_language_server_work(
16501        workspace: &mut Workspace,
16502        _: &actions::CancelLanguageServerWork,
16503        _: &mut Window,
16504        cx: &mut Context<Workspace>,
16505    ) {
16506        let project = workspace.project();
16507        let buffers = workspace
16508            .active_item(cx)
16509            .and_then(|item| item.act_as::<Editor>(cx))
16510            .map_or(HashSet::default(), |editor| {
16511                editor.read(cx).buffer.read(cx).all_buffers()
16512            });
16513        project.update(cx, |project, cx| {
16514            project.cancel_language_server_work_for_buffers(buffers, cx);
16515        });
16516    }
16517
16518    fn show_character_palette(
16519        &mut self,
16520        _: &ShowCharacterPalette,
16521        window: &mut Window,
16522        _: &mut Context<Self>,
16523    ) {
16524        window.show_character_palette();
16525    }
16526
16527    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16528        if !self.diagnostics_enabled() {
16529            return;
16530        }
16531
16532        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16533            let buffer = self.buffer.read(cx).snapshot(cx);
16534            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16535            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16536            let is_valid = buffer
16537                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16538                .any(|entry| {
16539                    entry.diagnostic.is_primary
16540                        && !entry.range.is_empty()
16541                        && entry.range.start == primary_range_start
16542                        && entry.diagnostic.message == active_diagnostics.active_message
16543                });
16544
16545            if !is_valid {
16546                self.dismiss_diagnostics(cx);
16547            }
16548        }
16549    }
16550
16551    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16552        match &self.active_diagnostics {
16553            ActiveDiagnostic::Group(group) => Some(group),
16554            _ => None,
16555        }
16556    }
16557
16558    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16559        if !self.diagnostics_enabled() {
16560            return;
16561        }
16562        self.dismiss_diagnostics(cx);
16563        self.active_diagnostics = ActiveDiagnostic::All;
16564    }
16565
16566    fn activate_diagnostics(
16567        &mut self,
16568        buffer_id: BufferId,
16569        diagnostic: DiagnosticEntry<usize>,
16570        window: &mut Window,
16571        cx: &mut Context<Self>,
16572    ) {
16573        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16574            return;
16575        }
16576        self.dismiss_diagnostics(cx);
16577        let snapshot = self.snapshot(window, cx);
16578        let buffer = self.buffer.read(cx).snapshot(cx);
16579        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16580            return;
16581        };
16582
16583        let diagnostic_group = buffer
16584            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16585            .collect::<Vec<_>>();
16586
16587        let blocks =
16588            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16589
16590        let blocks = self.display_map.update(cx, |display_map, cx| {
16591            display_map.insert_blocks(blocks, cx).into_iter().collect()
16592        });
16593        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16594            active_range: buffer.anchor_before(diagnostic.range.start)
16595                ..buffer.anchor_after(diagnostic.range.end),
16596            active_message: diagnostic.diagnostic.message.clone(),
16597            group_id: diagnostic.diagnostic.group_id,
16598            blocks,
16599        });
16600        cx.notify();
16601    }
16602
16603    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16604        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16605            return;
16606        };
16607
16608        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16609        if let ActiveDiagnostic::Group(group) = prev {
16610            self.display_map.update(cx, |display_map, cx| {
16611                display_map.remove_blocks(group.blocks, cx);
16612            });
16613            cx.notify();
16614        }
16615    }
16616
16617    /// Disable inline diagnostics rendering for this editor.
16618    pub fn disable_inline_diagnostics(&mut self) {
16619        self.inline_diagnostics_enabled = false;
16620        self.inline_diagnostics_update = Task::ready(());
16621        self.inline_diagnostics.clear();
16622    }
16623
16624    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16625        self.diagnostics_enabled = false;
16626        self.dismiss_diagnostics(cx);
16627        self.inline_diagnostics_update = Task::ready(());
16628        self.inline_diagnostics.clear();
16629    }
16630
16631    pub fn diagnostics_enabled(&self) -> bool {
16632        self.diagnostics_enabled && self.mode.is_full()
16633    }
16634
16635    pub fn inline_diagnostics_enabled(&self) -> bool {
16636        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16637    }
16638
16639    pub fn show_inline_diagnostics(&self) -> bool {
16640        self.show_inline_diagnostics
16641    }
16642
16643    pub fn toggle_inline_diagnostics(
16644        &mut self,
16645        _: &ToggleInlineDiagnostics,
16646        window: &mut Window,
16647        cx: &mut Context<Editor>,
16648    ) {
16649        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16650        self.refresh_inline_diagnostics(false, window, cx);
16651    }
16652
16653    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16654        self.diagnostics_max_severity = severity;
16655        self.display_map.update(cx, |display_map, _| {
16656            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16657        });
16658    }
16659
16660    pub fn toggle_diagnostics(
16661        &mut self,
16662        _: &ToggleDiagnostics,
16663        window: &mut Window,
16664        cx: &mut Context<Editor>,
16665    ) {
16666        if !self.diagnostics_enabled() {
16667            return;
16668        }
16669
16670        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16671            EditorSettings::get_global(cx)
16672                .diagnostics_max_severity
16673                .filter(|severity| severity != &DiagnosticSeverity::Off)
16674                .unwrap_or(DiagnosticSeverity::Hint)
16675        } else {
16676            DiagnosticSeverity::Off
16677        };
16678        self.set_max_diagnostics_severity(new_severity, cx);
16679        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16680            self.active_diagnostics = ActiveDiagnostic::None;
16681            self.inline_diagnostics_update = Task::ready(());
16682            self.inline_diagnostics.clear();
16683        } else {
16684            self.refresh_inline_diagnostics(false, window, cx);
16685        }
16686
16687        cx.notify();
16688    }
16689
16690    pub fn toggle_minimap(
16691        &mut self,
16692        _: &ToggleMinimap,
16693        window: &mut Window,
16694        cx: &mut Context<Editor>,
16695    ) {
16696        if self.supports_minimap(cx) {
16697            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16698        }
16699    }
16700
16701    fn refresh_inline_diagnostics(
16702        &mut self,
16703        debounce: bool,
16704        window: &mut Window,
16705        cx: &mut Context<Self>,
16706    ) {
16707        let max_severity = ProjectSettings::get_global(cx)
16708            .diagnostics
16709            .inline
16710            .max_severity
16711            .unwrap_or(self.diagnostics_max_severity);
16712
16713        if !self.inline_diagnostics_enabled()
16714            || !self.show_inline_diagnostics
16715            || max_severity == DiagnosticSeverity::Off
16716        {
16717            self.inline_diagnostics_update = Task::ready(());
16718            self.inline_diagnostics.clear();
16719            return;
16720        }
16721
16722        let debounce_ms = ProjectSettings::get_global(cx)
16723            .diagnostics
16724            .inline
16725            .update_debounce_ms;
16726        let debounce = if debounce && debounce_ms > 0 {
16727            Some(Duration::from_millis(debounce_ms))
16728        } else {
16729            None
16730        };
16731        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16732            if let Some(debounce) = debounce {
16733                cx.background_executor().timer(debounce).await;
16734            }
16735            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16736                editor
16737                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16738                    .ok()
16739            }) else {
16740                return;
16741            };
16742
16743            let new_inline_diagnostics = cx
16744                .background_spawn(async move {
16745                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16746                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16747                        let message = diagnostic_entry
16748                            .diagnostic
16749                            .message
16750                            .split_once('\n')
16751                            .map(|(line, _)| line)
16752                            .map(SharedString::new)
16753                            .unwrap_or_else(|| {
16754                                SharedString::from(diagnostic_entry.diagnostic.message)
16755                            });
16756                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16757                        let (Ok(i) | Err(i)) = inline_diagnostics
16758                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16759                        inline_diagnostics.insert(
16760                            i,
16761                            (
16762                                start_anchor,
16763                                InlineDiagnostic {
16764                                    message,
16765                                    group_id: diagnostic_entry.diagnostic.group_id,
16766                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16767                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16768                                    severity: diagnostic_entry.diagnostic.severity,
16769                                },
16770                            ),
16771                        );
16772                    }
16773                    inline_diagnostics
16774                })
16775                .await;
16776
16777            editor
16778                .update(cx, |editor, cx| {
16779                    editor.inline_diagnostics = new_inline_diagnostics;
16780                    cx.notify();
16781                })
16782                .ok();
16783        });
16784    }
16785
16786    fn pull_diagnostics(
16787        &mut self,
16788        buffer_id: Option<BufferId>,
16789        window: &Window,
16790        cx: &mut Context<Self>,
16791    ) -> Option<()> {
16792        if !self.mode().is_full() {
16793            return None;
16794        }
16795        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16796            .diagnostics
16797            .lsp_pull_diagnostics;
16798        if !pull_diagnostics_settings.enabled {
16799            return None;
16800        }
16801        let project = self.project.as_ref()?.downgrade();
16802        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16803        let mut buffers = self.buffer.read(cx).all_buffers();
16804        if let Some(buffer_id) = buffer_id {
16805            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16806        }
16807
16808        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16809            cx.background_executor().timer(debounce).await;
16810
16811            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16812                buffers
16813                    .into_iter()
16814                    .filter_map(|buffer| {
16815                        project
16816                            .update(cx, |project, cx| {
16817                                project.lsp_store().update(cx, |lsp_store, cx| {
16818                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16819                                })
16820                            })
16821                            .ok()
16822                    })
16823                    .collect::<FuturesUnordered<_>>()
16824            }) else {
16825                return;
16826            };
16827
16828            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16829                match pull_task {
16830                    Ok(()) => {
16831                        if editor
16832                            .update_in(cx, |editor, window, cx| {
16833                                editor.update_diagnostics_state(window, cx);
16834                            })
16835                            .is_err()
16836                        {
16837                            return;
16838                        }
16839                    }
16840                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16841                }
16842            }
16843        });
16844
16845        Some(())
16846    }
16847
16848    pub fn set_selections_from_remote(
16849        &mut self,
16850        selections: Vec<Selection<Anchor>>,
16851        pending_selection: Option<Selection<Anchor>>,
16852        window: &mut Window,
16853        cx: &mut Context<Self>,
16854    ) {
16855        let old_cursor_position = self.selections.newest_anchor().head();
16856        self.selections.change_with(cx, |s| {
16857            s.select_anchors(selections);
16858            if let Some(pending_selection) = pending_selection {
16859                s.set_pending(pending_selection, SelectMode::Character);
16860            } else {
16861                s.clear_pending();
16862            }
16863        });
16864        self.selections_did_change(
16865            false,
16866            &old_cursor_position,
16867            SelectionEffects::default(),
16868            window,
16869            cx,
16870        );
16871    }
16872
16873    pub fn transact(
16874        &mut self,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16878    ) -> Option<TransactionId> {
16879        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16880            this.start_transaction_at(Instant::now(), window, cx);
16881            update(this, window, cx);
16882            this.end_transaction_at(Instant::now(), cx)
16883        })
16884    }
16885
16886    pub fn start_transaction_at(
16887        &mut self,
16888        now: Instant,
16889        window: &mut Window,
16890        cx: &mut Context<Self>,
16891    ) {
16892        self.end_selection(window, cx);
16893        if let Some(tx_id) = self
16894            .buffer
16895            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16896        {
16897            self.selection_history
16898                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16899            cx.emit(EditorEvent::TransactionBegun {
16900                transaction_id: tx_id,
16901            })
16902        }
16903    }
16904
16905    pub fn end_transaction_at(
16906        &mut self,
16907        now: Instant,
16908        cx: &mut Context<Self>,
16909    ) -> Option<TransactionId> {
16910        if let Some(transaction_id) = self
16911            .buffer
16912            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16913        {
16914            if let Some((_, end_selections)) =
16915                self.selection_history.transaction_mut(transaction_id)
16916            {
16917                *end_selections = Some(self.selections.disjoint_anchors());
16918            } else {
16919                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16920            }
16921
16922            cx.emit(EditorEvent::Edited { transaction_id });
16923            Some(transaction_id)
16924        } else {
16925            None
16926        }
16927    }
16928
16929    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16930        if self.selection_mark_mode {
16931            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16932                s.move_with(|_, sel| {
16933                    sel.collapse_to(sel.head(), SelectionGoal::None);
16934                });
16935            })
16936        }
16937        self.selection_mark_mode = true;
16938        cx.notify();
16939    }
16940
16941    pub fn swap_selection_ends(
16942        &mut self,
16943        _: &actions::SwapSelectionEnds,
16944        window: &mut Window,
16945        cx: &mut Context<Self>,
16946    ) {
16947        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16948            s.move_with(|_, sel| {
16949                if sel.start != sel.end {
16950                    sel.reversed = !sel.reversed
16951                }
16952            });
16953        });
16954        self.request_autoscroll(Autoscroll::newest(), cx);
16955        cx.notify();
16956    }
16957
16958    pub fn toggle_focus(
16959        workspace: &mut Workspace,
16960        _: &actions::ToggleFocus,
16961        window: &mut Window,
16962        cx: &mut Context<Workspace>,
16963    ) {
16964        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
16965            return;
16966        };
16967        workspace.activate_item(&item, true, true, window, cx);
16968    }
16969
16970    pub fn toggle_fold(
16971        &mut self,
16972        _: &actions::ToggleFold,
16973        window: &mut Window,
16974        cx: &mut Context<Self>,
16975    ) {
16976        if self.is_singleton(cx) {
16977            let selection = self.selections.newest::<Point>(cx);
16978
16979            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16980            let range = if selection.is_empty() {
16981                let point = selection.head().to_display_point(&display_map);
16982                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16983                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16984                    .to_point(&display_map);
16985                start..end
16986            } else {
16987                selection.range()
16988            };
16989            if display_map.folds_in_range(range).next().is_some() {
16990                self.unfold_lines(&Default::default(), window, cx)
16991            } else {
16992                self.fold(&Default::default(), window, cx)
16993            }
16994        } else {
16995            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16996            let buffer_ids: HashSet<_> = self
16997                .selections
16998                .disjoint_anchor_ranges()
16999                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17000                .collect();
17001
17002            let should_unfold = buffer_ids
17003                .iter()
17004                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17005
17006            for buffer_id in buffer_ids {
17007                if should_unfold {
17008                    self.unfold_buffer(buffer_id, cx);
17009                } else {
17010                    self.fold_buffer(buffer_id, cx);
17011                }
17012            }
17013        }
17014    }
17015
17016    pub fn toggle_fold_recursive(
17017        &mut self,
17018        _: &actions::ToggleFoldRecursive,
17019        window: &mut Window,
17020        cx: &mut Context<Self>,
17021    ) {
17022        let selection = self.selections.newest::<Point>(cx);
17023
17024        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17025        let range = if selection.is_empty() {
17026            let point = selection.head().to_display_point(&display_map);
17027            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17028            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17029                .to_point(&display_map);
17030            start..end
17031        } else {
17032            selection.range()
17033        };
17034        if display_map.folds_in_range(range).next().is_some() {
17035            self.unfold_recursive(&Default::default(), window, cx)
17036        } else {
17037            self.fold_recursive(&Default::default(), window, cx)
17038        }
17039    }
17040
17041    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17042        if self.is_singleton(cx) {
17043            let mut to_fold = Vec::new();
17044            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17045            let selections = self.selections.all_adjusted(cx);
17046
17047            for selection in selections {
17048                let range = selection.range().sorted();
17049                let buffer_start_row = range.start.row;
17050
17051                if range.start.row != range.end.row {
17052                    let mut found = false;
17053                    let mut row = range.start.row;
17054                    while row <= range.end.row {
17055                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17056                        {
17057                            found = true;
17058                            row = crease.range().end.row + 1;
17059                            to_fold.push(crease);
17060                        } else {
17061                            row += 1
17062                        }
17063                    }
17064                    if found {
17065                        continue;
17066                    }
17067                }
17068
17069                for row in (0..=range.start.row).rev() {
17070                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17071                        if crease.range().end.row >= buffer_start_row {
17072                            to_fold.push(crease);
17073                            if row <= range.start.row {
17074                                break;
17075                            }
17076                        }
17077                    }
17078                }
17079            }
17080
17081            self.fold_creases(to_fold, true, window, cx);
17082        } else {
17083            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17084            let buffer_ids = self
17085                .selections
17086                .disjoint_anchor_ranges()
17087                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17088                .collect::<HashSet<_>>();
17089            for buffer_id in buffer_ids {
17090                self.fold_buffer(buffer_id, cx);
17091            }
17092        }
17093    }
17094
17095    pub fn toggle_fold_all(
17096        &mut self,
17097        _: &actions::ToggleFoldAll,
17098        window: &mut Window,
17099        cx: &mut Context<Self>,
17100    ) {
17101        if self.buffer.read(cx).is_singleton() {
17102            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17103            let has_folds = display_map
17104                .folds_in_range(0..display_map.buffer_snapshot.len())
17105                .next()
17106                .is_some();
17107
17108            if has_folds {
17109                self.unfold_all(&actions::UnfoldAll, window, cx);
17110            } else {
17111                self.fold_all(&actions::FoldAll, window, cx);
17112            }
17113        } else {
17114            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17115            let should_unfold = buffer_ids
17116                .iter()
17117                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17118
17119            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17120                editor
17121                    .update_in(cx, |editor, _, cx| {
17122                        for buffer_id in buffer_ids {
17123                            if should_unfold {
17124                                editor.unfold_buffer(buffer_id, cx);
17125                            } else {
17126                                editor.fold_buffer(buffer_id, cx);
17127                            }
17128                        }
17129                    })
17130                    .ok();
17131            });
17132        }
17133    }
17134
17135    fn fold_at_level(
17136        &mut self,
17137        fold_at: &FoldAtLevel,
17138        window: &mut Window,
17139        cx: &mut Context<Self>,
17140    ) {
17141        if !self.buffer.read(cx).is_singleton() {
17142            return;
17143        }
17144
17145        let fold_at_level = fold_at.0;
17146        let snapshot = self.buffer.read(cx).snapshot(cx);
17147        let mut to_fold = Vec::new();
17148        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17149
17150        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17151            while start_row < end_row {
17152                match self
17153                    .snapshot(window, cx)
17154                    .crease_for_buffer_row(MultiBufferRow(start_row))
17155                {
17156                    Some(crease) => {
17157                        let nested_start_row = crease.range().start.row + 1;
17158                        let nested_end_row = crease.range().end.row;
17159
17160                        if current_level < fold_at_level {
17161                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17162                        } else if current_level == fold_at_level {
17163                            to_fold.push(crease);
17164                        }
17165
17166                        start_row = nested_end_row + 1;
17167                    }
17168                    None => start_row += 1,
17169                }
17170            }
17171        }
17172
17173        self.fold_creases(to_fold, true, window, cx);
17174    }
17175
17176    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17177        if self.buffer.read(cx).is_singleton() {
17178            let mut fold_ranges = Vec::new();
17179            let snapshot = self.buffer.read(cx).snapshot(cx);
17180
17181            for row in 0..snapshot.max_row().0 {
17182                if let Some(foldable_range) = self
17183                    .snapshot(window, cx)
17184                    .crease_for_buffer_row(MultiBufferRow(row))
17185                {
17186                    fold_ranges.push(foldable_range);
17187                }
17188            }
17189
17190            self.fold_creases(fold_ranges, true, window, cx);
17191        } else {
17192            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17193                editor
17194                    .update_in(cx, |editor, _, cx| {
17195                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17196                            editor.fold_buffer(buffer_id, cx);
17197                        }
17198                    })
17199                    .ok();
17200            });
17201        }
17202    }
17203
17204    pub fn fold_function_bodies(
17205        &mut self,
17206        _: &actions::FoldFunctionBodies,
17207        window: &mut Window,
17208        cx: &mut Context<Self>,
17209    ) {
17210        let snapshot = self.buffer.read(cx).snapshot(cx);
17211
17212        let ranges = snapshot
17213            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17214            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17215            .collect::<Vec<_>>();
17216
17217        let creases = ranges
17218            .into_iter()
17219            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17220            .collect();
17221
17222        self.fold_creases(creases, true, window, cx);
17223    }
17224
17225    pub fn fold_recursive(
17226        &mut self,
17227        _: &actions::FoldRecursive,
17228        window: &mut Window,
17229        cx: &mut Context<Self>,
17230    ) {
17231        let mut to_fold = Vec::new();
17232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17233        let selections = self.selections.all_adjusted(cx);
17234
17235        for selection in selections {
17236            let range = selection.range().sorted();
17237            let buffer_start_row = range.start.row;
17238
17239            if range.start.row != range.end.row {
17240                let mut found = false;
17241                for row in range.start.row..=range.end.row {
17242                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17243                        found = true;
17244                        to_fold.push(crease);
17245                    }
17246                }
17247                if found {
17248                    continue;
17249                }
17250            }
17251
17252            for row in (0..=range.start.row).rev() {
17253                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17254                    if crease.range().end.row >= buffer_start_row {
17255                        to_fold.push(crease);
17256                    } else {
17257                        break;
17258                    }
17259                }
17260            }
17261        }
17262
17263        self.fold_creases(to_fold, true, window, cx);
17264    }
17265
17266    pub fn fold_at(
17267        &mut self,
17268        buffer_row: MultiBufferRow,
17269        window: &mut Window,
17270        cx: &mut Context<Self>,
17271    ) {
17272        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17273
17274        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17275            let autoscroll = self
17276                .selections
17277                .all::<Point>(cx)
17278                .iter()
17279                .any(|selection| crease.range().overlaps(&selection.range()));
17280
17281            self.fold_creases(vec![crease], autoscroll, window, cx);
17282        }
17283    }
17284
17285    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17286        if self.is_singleton(cx) {
17287            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17288            let buffer = &display_map.buffer_snapshot;
17289            let selections = self.selections.all::<Point>(cx);
17290            let ranges = selections
17291                .iter()
17292                .map(|s| {
17293                    let range = s.display_range(&display_map).sorted();
17294                    let mut start = range.start.to_point(&display_map);
17295                    let mut end = range.end.to_point(&display_map);
17296                    start.column = 0;
17297                    end.column = buffer.line_len(MultiBufferRow(end.row));
17298                    start..end
17299                })
17300                .collect::<Vec<_>>();
17301
17302            self.unfold_ranges(&ranges, true, true, cx);
17303        } else {
17304            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17305            let buffer_ids = self
17306                .selections
17307                .disjoint_anchor_ranges()
17308                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17309                .collect::<HashSet<_>>();
17310            for buffer_id in buffer_ids {
17311                self.unfold_buffer(buffer_id, cx);
17312            }
17313        }
17314    }
17315
17316    pub fn unfold_recursive(
17317        &mut self,
17318        _: &UnfoldRecursive,
17319        _window: &mut Window,
17320        cx: &mut Context<Self>,
17321    ) {
17322        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17323        let selections = self.selections.all::<Point>(cx);
17324        let ranges = selections
17325            .iter()
17326            .map(|s| {
17327                let mut range = s.display_range(&display_map).sorted();
17328                *range.start.column_mut() = 0;
17329                *range.end.column_mut() = display_map.line_len(range.end.row());
17330                let start = range.start.to_point(&display_map);
17331                let end = range.end.to_point(&display_map);
17332                start..end
17333            })
17334            .collect::<Vec<_>>();
17335
17336        self.unfold_ranges(&ranges, true, true, cx);
17337    }
17338
17339    pub fn unfold_at(
17340        &mut self,
17341        buffer_row: MultiBufferRow,
17342        _window: &mut Window,
17343        cx: &mut Context<Self>,
17344    ) {
17345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17346
17347        let intersection_range = Point::new(buffer_row.0, 0)
17348            ..Point::new(
17349                buffer_row.0,
17350                display_map.buffer_snapshot.line_len(buffer_row),
17351            );
17352
17353        let autoscroll = self
17354            .selections
17355            .all::<Point>(cx)
17356            .iter()
17357            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17358
17359        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17360    }
17361
17362    pub fn unfold_all(
17363        &mut self,
17364        _: &actions::UnfoldAll,
17365        _window: &mut Window,
17366        cx: &mut Context<Self>,
17367    ) {
17368        if self.buffer.read(cx).is_singleton() {
17369            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17370            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17371        } else {
17372            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17373                editor
17374                    .update(cx, |editor, cx| {
17375                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17376                            editor.unfold_buffer(buffer_id, cx);
17377                        }
17378                    })
17379                    .ok();
17380            });
17381        }
17382    }
17383
17384    pub fn fold_selected_ranges(
17385        &mut self,
17386        _: &FoldSelectedRanges,
17387        window: &mut Window,
17388        cx: &mut Context<Self>,
17389    ) {
17390        let selections = self.selections.all_adjusted(cx);
17391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17392        let ranges = selections
17393            .into_iter()
17394            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17395            .collect::<Vec<_>>();
17396        self.fold_creases(ranges, true, window, cx);
17397    }
17398
17399    pub fn fold_ranges<T: ToOffset + Clone>(
17400        &mut self,
17401        ranges: Vec<Range<T>>,
17402        auto_scroll: bool,
17403        window: &mut Window,
17404        cx: &mut Context<Self>,
17405    ) {
17406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17407        let ranges = ranges
17408            .into_iter()
17409            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17410            .collect::<Vec<_>>();
17411        self.fold_creases(ranges, auto_scroll, window, cx);
17412    }
17413
17414    pub fn fold_creases<T: ToOffset + Clone>(
17415        &mut self,
17416        creases: Vec<Crease<T>>,
17417        auto_scroll: bool,
17418        _window: &mut Window,
17419        cx: &mut Context<Self>,
17420    ) {
17421        if creases.is_empty() {
17422            return;
17423        }
17424
17425        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17426
17427        if auto_scroll {
17428            self.request_autoscroll(Autoscroll::fit(), cx);
17429        }
17430
17431        cx.notify();
17432
17433        self.scrollbar_marker_state.dirty = true;
17434        self.folds_did_change(cx);
17435    }
17436
17437    /// Removes any folds whose ranges intersect any of the given ranges.
17438    pub fn unfold_ranges<T: ToOffset + Clone>(
17439        &mut self,
17440        ranges: &[Range<T>],
17441        inclusive: bool,
17442        auto_scroll: bool,
17443        cx: &mut Context<Self>,
17444    ) {
17445        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17446            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17447        });
17448        self.folds_did_change(cx);
17449    }
17450
17451    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17452        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17453            return;
17454        }
17455        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17456        self.display_map.update(cx, |display_map, cx| {
17457            display_map.fold_buffers([buffer_id], cx)
17458        });
17459        cx.emit(EditorEvent::BufferFoldToggled {
17460            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17461            folded: true,
17462        });
17463        cx.notify();
17464    }
17465
17466    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17467        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17468            return;
17469        }
17470        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17471        self.display_map.update(cx, |display_map, cx| {
17472            display_map.unfold_buffers([buffer_id], cx);
17473        });
17474        cx.emit(EditorEvent::BufferFoldToggled {
17475            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17476            folded: false,
17477        });
17478        cx.notify();
17479    }
17480
17481    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17482        self.display_map.read(cx).is_buffer_folded(buffer)
17483    }
17484
17485    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17486        self.display_map.read(cx).folded_buffers()
17487    }
17488
17489    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17490        self.display_map.update(cx, |display_map, cx| {
17491            display_map.disable_header_for_buffer(buffer_id, cx);
17492        });
17493        cx.notify();
17494    }
17495
17496    /// Removes any folds with the given ranges.
17497    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17498        &mut self,
17499        ranges: &[Range<T>],
17500        type_id: TypeId,
17501        auto_scroll: bool,
17502        cx: &mut Context<Self>,
17503    ) {
17504        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17505            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17506        });
17507        self.folds_did_change(cx);
17508    }
17509
17510    fn remove_folds_with<T: ToOffset + Clone>(
17511        &mut self,
17512        ranges: &[Range<T>],
17513        auto_scroll: bool,
17514        cx: &mut Context<Self>,
17515        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17516    ) {
17517        if ranges.is_empty() {
17518            return;
17519        }
17520
17521        let mut buffers_affected = HashSet::default();
17522        let multi_buffer = self.buffer().read(cx);
17523        for range in ranges {
17524            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17525                buffers_affected.insert(buffer.read(cx).remote_id());
17526            };
17527        }
17528
17529        self.display_map.update(cx, update);
17530
17531        if auto_scroll {
17532            self.request_autoscroll(Autoscroll::fit(), cx);
17533        }
17534
17535        cx.notify();
17536        self.scrollbar_marker_state.dirty = true;
17537        self.active_indent_guides_state.dirty = true;
17538    }
17539
17540    pub fn update_renderer_widths(
17541        &mut self,
17542        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17543        cx: &mut Context<Self>,
17544    ) -> bool {
17545        self.display_map
17546            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17547    }
17548
17549    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17550        self.display_map.read(cx).fold_placeholder.clone()
17551    }
17552
17553    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17554        self.buffer.update(cx, |buffer, cx| {
17555            buffer.set_all_diff_hunks_expanded(cx);
17556        });
17557    }
17558
17559    pub fn expand_all_diff_hunks(
17560        &mut self,
17561        _: &ExpandAllDiffHunks,
17562        _window: &mut Window,
17563        cx: &mut Context<Self>,
17564    ) {
17565        self.buffer.update(cx, |buffer, cx| {
17566            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17567        });
17568    }
17569
17570    pub fn toggle_selected_diff_hunks(
17571        &mut self,
17572        _: &ToggleSelectedDiffHunks,
17573        _window: &mut Window,
17574        cx: &mut Context<Self>,
17575    ) {
17576        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17577        self.toggle_diff_hunks_in_ranges(ranges, cx);
17578    }
17579
17580    pub fn diff_hunks_in_ranges<'a>(
17581        &'a self,
17582        ranges: &'a [Range<Anchor>],
17583        buffer: &'a MultiBufferSnapshot,
17584    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17585        ranges.iter().flat_map(move |range| {
17586            let end_excerpt_id = range.end.excerpt_id;
17587            let range = range.to_point(buffer);
17588            let mut peek_end = range.end;
17589            if range.end.row < buffer.max_row().0 {
17590                peek_end = Point::new(range.end.row + 1, 0);
17591            }
17592            buffer
17593                .diff_hunks_in_range(range.start..peek_end)
17594                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17595        })
17596    }
17597
17598    pub fn has_stageable_diff_hunks_in_ranges(
17599        &self,
17600        ranges: &[Range<Anchor>],
17601        snapshot: &MultiBufferSnapshot,
17602    ) -> bool {
17603        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17604        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17605    }
17606
17607    pub fn toggle_staged_selected_diff_hunks(
17608        &mut self,
17609        _: &::git::ToggleStaged,
17610        _: &mut Window,
17611        cx: &mut Context<Self>,
17612    ) {
17613        let snapshot = self.buffer.read(cx).snapshot(cx);
17614        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17615        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17616        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17617    }
17618
17619    pub fn set_render_diff_hunk_controls(
17620        &mut self,
17621        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17622        cx: &mut Context<Self>,
17623    ) {
17624        self.render_diff_hunk_controls = render_diff_hunk_controls;
17625        cx.notify();
17626    }
17627
17628    pub fn stage_and_next(
17629        &mut self,
17630        _: &::git::StageAndNext,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        self.do_stage_or_unstage_and_next(true, window, cx);
17635    }
17636
17637    pub fn unstage_and_next(
17638        &mut self,
17639        _: &::git::UnstageAndNext,
17640        window: &mut Window,
17641        cx: &mut Context<Self>,
17642    ) {
17643        self.do_stage_or_unstage_and_next(false, window, cx);
17644    }
17645
17646    pub fn stage_or_unstage_diff_hunks(
17647        &mut self,
17648        stage: bool,
17649        ranges: Vec<Range<Anchor>>,
17650        cx: &mut Context<Self>,
17651    ) {
17652        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17653        cx.spawn(async move |this, cx| {
17654            task.await?;
17655            this.update(cx, |this, cx| {
17656                let snapshot = this.buffer.read(cx).snapshot(cx);
17657                let chunk_by = this
17658                    .diff_hunks_in_ranges(&ranges, &snapshot)
17659                    .chunk_by(|hunk| hunk.buffer_id);
17660                for (buffer_id, hunks) in &chunk_by {
17661                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17662                }
17663            })
17664        })
17665        .detach_and_log_err(cx);
17666    }
17667
17668    fn save_buffers_for_ranges_if_needed(
17669        &mut self,
17670        ranges: &[Range<Anchor>],
17671        cx: &mut Context<Editor>,
17672    ) -> Task<Result<()>> {
17673        let multibuffer = self.buffer.read(cx);
17674        let snapshot = multibuffer.read(cx);
17675        let buffer_ids: HashSet<_> = ranges
17676            .iter()
17677            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17678            .collect();
17679        drop(snapshot);
17680
17681        let mut buffers = HashSet::default();
17682        for buffer_id in buffer_ids {
17683            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17684                let buffer = buffer_entity.read(cx);
17685                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17686                {
17687                    buffers.insert(buffer_entity);
17688                }
17689            }
17690        }
17691
17692        if let Some(project) = &self.project {
17693            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17694        } else {
17695            Task::ready(Ok(()))
17696        }
17697    }
17698
17699    fn do_stage_or_unstage_and_next(
17700        &mut self,
17701        stage: bool,
17702        window: &mut Window,
17703        cx: &mut Context<Self>,
17704    ) {
17705        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17706
17707        if ranges.iter().any(|range| range.start != range.end) {
17708            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17709            return;
17710        }
17711
17712        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17713        let snapshot = self.snapshot(window, cx);
17714        let position = self.selections.newest::<Point>(cx).head();
17715        let mut row = snapshot
17716            .buffer_snapshot
17717            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17718            .find(|hunk| hunk.row_range.start.0 > position.row)
17719            .map(|hunk| hunk.row_range.start);
17720
17721        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17722        // Outside of the project diff editor, wrap around to the beginning.
17723        if !all_diff_hunks_expanded {
17724            row = row.or_else(|| {
17725                snapshot
17726                    .buffer_snapshot
17727                    .diff_hunks_in_range(Point::zero()..position)
17728                    .find(|hunk| hunk.row_range.end.0 < position.row)
17729                    .map(|hunk| hunk.row_range.start)
17730            });
17731        }
17732
17733        if let Some(row) = row {
17734            let destination = Point::new(row.0, 0);
17735            let autoscroll = Autoscroll::center();
17736
17737            self.unfold_ranges(&[destination..destination], false, false, cx);
17738            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17739                s.select_ranges([destination..destination]);
17740            });
17741        }
17742    }
17743
17744    fn do_stage_or_unstage(
17745        &self,
17746        stage: bool,
17747        buffer_id: BufferId,
17748        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17749        cx: &mut App,
17750    ) -> Option<()> {
17751        let project = self.project.as_ref()?;
17752        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17753        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17754        let buffer_snapshot = buffer.read(cx).snapshot();
17755        let file_exists = buffer_snapshot
17756            .file()
17757            .is_some_and(|file| file.disk_state().exists());
17758        diff.update(cx, |diff, cx| {
17759            diff.stage_or_unstage_hunks(
17760                stage,
17761                &hunks
17762                    .map(|hunk| buffer_diff::DiffHunk {
17763                        buffer_range: hunk.buffer_range,
17764                        diff_base_byte_range: hunk.diff_base_byte_range,
17765                        secondary_status: hunk.secondary_status,
17766                        range: Point::zero()..Point::zero(), // unused
17767                    })
17768                    .collect::<Vec<_>>(),
17769                &buffer_snapshot,
17770                file_exists,
17771                cx,
17772            )
17773        });
17774        None
17775    }
17776
17777    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17778        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17779        self.buffer
17780            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17781    }
17782
17783    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17784        self.buffer.update(cx, |buffer, cx| {
17785            let ranges = vec![Anchor::min()..Anchor::max()];
17786            if !buffer.all_diff_hunks_expanded()
17787                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17788            {
17789                buffer.collapse_diff_hunks(ranges, cx);
17790                true
17791            } else {
17792                false
17793            }
17794        })
17795    }
17796
17797    fn toggle_diff_hunks_in_ranges(
17798        &mut self,
17799        ranges: Vec<Range<Anchor>>,
17800        cx: &mut Context<Editor>,
17801    ) {
17802        self.buffer.update(cx, |buffer, cx| {
17803            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17804            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17805        })
17806    }
17807
17808    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17809        self.buffer.update(cx, |buffer, cx| {
17810            let snapshot = buffer.snapshot(cx);
17811            let excerpt_id = range.end.excerpt_id;
17812            let point_range = range.to_point(&snapshot);
17813            let expand = !buffer.single_hunk_is_expanded(range, cx);
17814            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17815        })
17816    }
17817
17818    pub(crate) fn apply_all_diff_hunks(
17819        &mut self,
17820        _: &ApplyAllDiffHunks,
17821        window: &mut Window,
17822        cx: &mut Context<Self>,
17823    ) {
17824        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17825
17826        let buffers = self.buffer.read(cx).all_buffers();
17827        for branch_buffer in buffers {
17828            branch_buffer.update(cx, |branch_buffer, cx| {
17829                branch_buffer.merge_into_base(Vec::new(), cx);
17830            });
17831        }
17832
17833        if let Some(project) = self.project.clone() {
17834            self.save(
17835                SaveOptions {
17836                    format: true,
17837                    autosave: false,
17838                },
17839                project,
17840                window,
17841                cx,
17842            )
17843            .detach_and_log_err(cx);
17844        }
17845    }
17846
17847    pub(crate) fn apply_selected_diff_hunks(
17848        &mut self,
17849        _: &ApplyDiffHunk,
17850        window: &mut Window,
17851        cx: &mut Context<Self>,
17852    ) {
17853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17854        let snapshot = self.snapshot(window, cx);
17855        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17856        let mut ranges_by_buffer = HashMap::default();
17857        self.transact(window, cx, |editor, _window, cx| {
17858            for hunk in hunks {
17859                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17860                    ranges_by_buffer
17861                        .entry(buffer.clone())
17862                        .or_insert_with(Vec::new)
17863                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17864                }
17865            }
17866
17867            for (buffer, ranges) in ranges_by_buffer {
17868                buffer.update(cx, |buffer, cx| {
17869                    buffer.merge_into_base(ranges, cx);
17870                });
17871            }
17872        });
17873
17874        if let Some(project) = self.project.clone() {
17875            self.save(
17876                SaveOptions {
17877                    format: true,
17878                    autosave: false,
17879                },
17880                project,
17881                window,
17882                cx,
17883            )
17884            .detach_and_log_err(cx);
17885        }
17886    }
17887
17888    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17889        if hovered != self.gutter_hovered {
17890            self.gutter_hovered = hovered;
17891            cx.notify();
17892        }
17893    }
17894
17895    pub fn insert_blocks(
17896        &mut self,
17897        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17898        autoscroll: Option<Autoscroll>,
17899        cx: &mut Context<Self>,
17900    ) -> Vec<CustomBlockId> {
17901        let blocks = self
17902            .display_map
17903            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17904        if let Some(autoscroll) = autoscroll {
17905            self.request_autoscroll(autoscroll, cx);
17906        }
17907        cx.notify();
17908        blocks
17909    }
17910
17911    pub fn resize_blocks(
17912        &mut self,
17913        heights: HashMap<CustomBlockId, u32>,
17914        autoscroll: Option<Autoscroll>,
17915        cx: &mut Context<Self>,
17916    ) {
17917        self.display_map
17918            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17919        if let Some(autoscroll) = autoscroll {
17920            self.request_autoscroll(autoscroll, cx);
17921        }
17922        cx.notify();
17923    }
17924
17925    pub fn replace_blocks(
17926        &mut self,
17927        renderers: HashMap<CustomBlockId, RenderBlock>,
17928        autoscroll: Option<Autoscroll>,
17929        cx: &mut Context<Self>,
17930    ) {
17931        self.display_map
17932            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17933        if let Some(autoscroll) = autoscroll {
17934            self.request_autoscroll(autoscroll, cx);
17935        }
17936        cx.notify();
17937    }
17938
17939    pub fn remove_blocks(
17940        &mut self,
17941        block_ids: HashSet<CustomBlockId>,
17942        autoscroll: Option<Autoscroll>,
17943        cx: &mut Context<Self>,
17944    ) {
17945        self.display_map.update(cx, |display_map, cx| {
17946            display_map.remove_blocks(block_ids, cx)
17947        });
17948        if let Some(autoscroll) = autoscroll {
17949            self.request_autoscroll(autoscroll, cx);
17950        }
17951        cx.notify();
17952    }
17953
17954    pub fn row_for_block(
17955        &self,
17956        block_id: CustomBlockId,
17957        cx: &mut Context<Self>,
17958    ) -> Option<DisplayRow> {
17959        self.display_map
17960            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17961    }
17962
17963    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17964        self.focused_block = Some(focused_block);
17965    }
17966
17967    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17968        self.focused_block.take()
17969    }
17970
17971    pub fn insert_creases(
17972        &mut self,
17973        creases: impl IntoIterator<Item = Crease<Anchor>>,
17974        cx: &mut Context<Self>,
17975    ) -> Vec<CreaseId> {
17976        self.display_map
17977            .update(cx, |map, cx| map.insert_creases(creases, cx))
17978    }
17979
17980    pub fn remove_creases(
17981        &mut self,
17982        ids: impl IntoIterator<Item = CreaseId>,
17983        cx: &mut Context<Self>,
17984    ) -> Vec<(CreaseId, Range<Anchor>)> {
17985        self.display_map
17986            .update(cx, |map, cx| map.remove_creases(ids, cx))
17987    }
17988
17989    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17990        self.display_map
17991            .update(cx, |map, cx| map.snapshot(cx))
17992            .longest_row()
17993    }
17994
17995    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17996        self.display_map
17997            .update(cx, |map, cx| map.snapshot(cx))
17998            .max_point()
17999    }
18000
18001    pub fn text(&self, cx: &App) -> String {
18002        self.buffer.read(cx).read(cx).text()
18003    }
18004
18005    pub fn is_empty(&self, cx: &App) -> bool {
18006        self.buffer.read(cx).read(cx).is_empty()
18007    }
18008
18009    pub fn text_option(&self, cx: &App) -> Option<String> {
18010        let text = self.text(cx);
18011        let text = text.trim();
18012
18013        if text.is_empty() {
18014            return None;
18015        }
18016
18017        Some(text.to_string())
18018    }
18019
18020    pub fn set_text(
18021        &mut self,
18022        text: impl Into<Arc<str>>,
18023        window: &mut Window,
18024        cx: &mut Context<Self>,
18025    ) {
18026        self.transact(window, cx, |this, _, cx| {
18027            this.buffer
18028                .read(cx)
18029                .as_singleton()
18030                .expect("you can only call set_text on editors for singleton buffers")
18031                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18032        });
18033    }
18034
18035    pub fn display_text(&self, cx: &mut App) -> String {
18036        self.display_map
18037            .update(cx, |map, cx| map.snapshot(cx))
18038            .text()
18039    }
18040
18041    fn create_minimap(
18042        &self,
18043        minimap_settings: MinimapSettings,
18044        window: &mut Window,
18045        cx: &mut Context<Self>,
18046    ) -> Option<Entity<Self>> {
18047        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18048            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18049    }
18050
18051    fn initialize_new_minimap(
18052        &self,
18053        minimap_settings: MinimapSettings,
18054        window: &mut Window,
18055        cx: &mut Context<Self>,
18056    ) -> Entity<Self> {
18057        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18058
18059        let mut minimap = Editor::new_internal(
18060            EditorMode::Minimap {
18061                parent: cx.weak_entity(),
18062            },
18063            self.buffer.clone(),
18064            None,
18065            Some(self.display_map.clone()),
18066            window,
18067            cx,
18068        );
18069        minimap.scroll_manager.clone_state(&self.scroll_manager);
18070        minimap.set_text_style_refinement(TextStyleRefinement {
18071            font_size: Some(MINIMAP_FONT_SIZE),
18072            font_weight: Some(MINIMAP_FONT_WEIGHT),
18073            ..Default::default()
18074        });
18075        minimap.update_minimap_configuration(minimap_settings, cx);
18076        cx.new(|_| minimap)
18077    }
18078
18079    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18080        let current_line_highlight = minimap_settings
18081            .current_line_highlight
18082            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18083        self.set_current_line_highlight(Some(current_line_highlight));
18084    }
18085
18086    pub fn minimap(&self) -> Option<&Entity<Self>> {
18087        self.minimap
18088            .as_ref()
18089            .filter(|_| self.minimap_visibility.visible())
18090    }
18091
18092    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18093        let mut wrap_guides = smallvec![];
18094
18095        if self.show_wrap_guides == Some(false) {
18096            return wrap_guides;
18097        }
18098
18099        let settings = self.buffer.read(cx).language_settings(cx);
18100        if settings.show_wrap_guides {
18101            match self.soft_wrap_mode(cx) {
18102                SoftWrap::Column(soft_wrap) => {
18103                    wrap_guides.push((soft_wrap as usize, true));
18104                }
18105                SoftWrap::Bounded(soft_wrap) => {
18106                    wrap_guides.push((soft_wrap as usize, true));
18107                }
18108                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18109            }
18110            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18111        }
18112
18113        wrap_guides
18114    }
18115
18116    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18117        let settings = self.buffer.read(cx).language_settings(cx);
18118        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18119        match mode {
18120            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18121                SoftWrap::None
18122            }
18123            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18124            language_settings::SoftWrap::PreferredLineLength => {
18125                SoftWrap::Column(settings.preferred_line_length)
18126            }
18127            language_settings::SoftWrap::Bounded => {
18128                SoftWrap::Bounded(settings.preferred_line_length)
18129            }
18130        }
18131    }
18132
18133    pub fn set_soft_wrap_mode(
18134        &mut self,
18135        mode: language_settings::SoftWrap,
18136
18137        cx: &mut Context<Self>,
18138    ) {
18139        self.soft_wrap_mode_override = Some(mode);
18140        cx.notify();
18141    }
18142
18143    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18144        self.hard_wrap = hard_wrap;
18145        cx.notify();
18146    }
18147
18148    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18149        self.text_style_refinement = Some(style);
18150    }
18151
18152    /// called by the Element so we know what style we were most recently rendered with.
18153    pub(crate) fn set_style(
18154        &mut self,
18155        style: EditorStyle,
18156        window: &mut Window,
18157        cx: &mut Context<Self>,
18158    ) {
18159        // We intentionally do not inform the display map about the minimap style
18160        // so that wrapping is not recalculated and stays consistent for the editor
18161        // and its linked minimap.
18162        if !self.mode.is_minimap() {
18163            let rem_size = window.rem_size();
18164            self.display_map.update(cx, |map, cx| {
18165                map.set_font(
18166                    style.text.font(),
18167                    style.text.font_size.to_pixels(rem_size),
18168                    cx,
18169                )
18170            });
18171        }
18172        self.style = Some(style);
18173    }
18174
18175    pub fn style(&self) -> Option<&EditorStyle> {
18176        self.style.as_ref()
18177    }
18178
18179    // Called by the element. This method is not designed to be called outside of the editor
18180    // element's layout code because it does not notify when rewrapping is computed synchronously.
18181    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18182        self.display_map
18183            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18184    }
18185
18186    pub fn set_soft_wrap(&mut self) {
18187        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18188    }
18189
18190    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18191        if self.soft_wrap_mode_override.is_some() {
18192            self.soft_wrap_mode_override.take();
18193        } else {
18194            let soft_wrap = match self.soft_wrap_mode(cx) {
18195                SoftWrap::GitDiff => return,
18196                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18197                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18198                    language_settings::SoftWrap::None
18199                }
18200            };
18201            self.soft_wrap_mode_override = Some(soft_wrap);
18202        }
18203        cx.notify();
18204    }
18205
18206    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18207        let Some(workspace) = self.workspace() else {
18208            return;
18209        };
18210        let fs = workspace.read(cx).app_state().fs.clone();
18211        let current_show = TabBarSettings::get_global(cx).show;
18212        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18213            setting.show = Some(!current_show);
18214        });
18215    }
18216
18217    pub fn toggle_indent_guides(
18218        &mut self,
18219        _: &ToggleIndentGuides,
18220        _: &mut Window,
18221        cx: &mut Context<Self>,
18222    ) {
18223        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18224            self.buffer
18225                .read(cx)
18226                .language_settings(cx)
18227                .indent_guides
18228                .enabled
18229        });
18230        self.show_indent_guides = Some(!currently_enabled);
18231        cx.notify();
18232    }
18233
18234    fn should_show_indent_guides(&self) -> Option<bool> {
18235        self.show_indent_guides
18236    }
18237
18238    pub fn toggle_line_numbers(
18239        &mut self,
18240        _: &ToggleLineNumbers,
18241        _: &mut Window,
18242        cx: &mut Context<Self>,
18243    ) {
18244        let mut editor_settings = EditorSettings::get_global(cx).clone();
18245        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18246        EditorSettings::override_global(editor_settings, cx);
18247    }
18248
18249    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18250        if let Some(show_line_numbers) = self.show_line_numbers {
18251            return show_line_numbers;
18252        }
18253        EditorSettings::get_global(cx).gutter.line_numbers
18254    }
18255
18256    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18257        self.use_relative_line_numbers
18258            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18259    }
18260
18261    pub fn toggle_relative_line_numbers(
18262        &mut self,
18263        _: &ToggleRelativeLineNumbers,
18264        _: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) {
18267        let is_relative = self.should_use_relative_line_numbers(cx);
18268        self.set_relative_line_number(Some(!is_relative), cx)
18269    }
18270
18271    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18272        self.use_relative_line_numbers = is_relative;
18273        cx.notify();
18274    }
18275
18276    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18277        self.show_gutter = show_gutter;
18278        cx.notify();
18279    }
18280
18281    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18282        self.show_scrollbars = ScrollbarAxes {
18283            horizontal: show,
18284            vertical: show,
18285        };
18286        cx.notify();
18287    }
18288
18289    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18290        self.show_scrollbars.vertical = show;
18291        cx.notify();
18292    }
18293
18294    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18295        self.show_scrollbars.horizontal = show;
18296        cx.notify();
18297    }
18298
18299    pub fn set_minimap_visibility(
18300        &mut self,
18301        minimap_visibility: MinimapVisibility,
18302        window: &mut Window,
18303        cx: &mut Context<Self>,
18304    ) {
18305        if self.minimap_visibility != minimap_visibility {
18306            if minimap_visibility.visible() && self.minimap.is_none() {
18307                let minimap_settings = EditorSettings::get_global(cx).minimap;
18308                self.minimap =
18309                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18310            }
18311            self.minimap_visibility = minimap_visibility;
18312            cx.notify();
18313        }
18314    }
18315
18316    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18317        self.set_show_scrollbars(false, cx);
18318        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18319    }
18320
18321    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18322        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18323    }
18324
18325    /// Normally the text in full mode and auto height editors is padded on the
18326    /// left side by roughly half a character width for improved hit testing.
18327    ///
18328    /// Use this method to disable this for cases where this is not wanted (e.g.
18329    /// if you want to align the editor text with some other text above or below)
18330    /// or if you want to add this padding to single-line editors.
18331    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18332        self.offset_content = offset_content;
18333        cx.notify();
18334    }
18335
18336    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18337        self.show_line_numbers = Some(show_line_numbers);
18338        cx.notify();
18339    }
18340
18341    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18342        self.disable_expand_excerpt_buttons = true;
18343        cx.notify();
18344    }
18345
18346    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18347        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18348        cx.notify();
18349    }
18350
18351    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18352        self.show_code_actions = Some(show_code_actions);
18353        cx.notify();
18354    }
18355
18356    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18357        self.show_runnables = Some(show_runnables);
18358        cx.notify();
18359    }
18360
18361    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18362        self.show_breakpoints = Some(show_breakpoints);
18363        cx.notify();
18364    }
18365
18366    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18367        if self.display_map.read(cx).masked != masked {
18368            self.display_map.update(cx, |map, _| map.masked = masked);
18369        }
18370        cx.notify()
18371    }
18372
18373    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18374        self.show_wrap_guides = Some(show_wrap_guides);
18375        cx.notify();
18376    }
18377
18378    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18379        self.show_indent_guides = Some(show_indent_guides);
18380        cx.notify();
18381    }
18382
18383    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18384        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18385            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18386                if let Some(dir) = file.abs_path(cx).parent() {
18387                    return Some(dir.to_owned());
18388                }
18389            }
18390
18391            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18392                return Some(project_path.path.to_path_buf());
18393            }
18394        }
18395
18396        None
18397    }
18398
18399    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18400        self.active_excerpt(cx)?
18401            .1
18402            .read(cx)
18403            .file()
18404            .and_then(|f| f.as_local())
18405    }
18406
18407    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18408        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18409            let buffer = buffer.read(cx);
18410            if let Some(project_path) = buffer.project_path(cx) {
18411                let project = self.project.as_ref()?.read(cx);
18412                project.absolute_path(&project_path, cx)
18413            } else {
18414                buffer
18415                    .file()
18416                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18417            }
18418        })
18419    }
18420
18421    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18422        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18423            let project_path = buffer.read(cx).project_path(cx)?;
18424            let project = self.project.as_ref()?.read(cx);
18425            let entry = project.entry_for_path(&project_path, cx)?;
18426            let path = entry.path.to_path_buf();
18427            Some(path)
18428        })
18429    }
18430
18431    pub fn reveal_in_finder(
18432        &mut self,
18433        _: &RevealInFileManager,
18434        _window: &mut Window,
18435        cx: &mut Context<Self>,
18436    ) {
18437        if let Some(target) = self.target_file(cx) {
18438            cx.reveal_path(&target.abs_path(cx));
18439        }
18440    }
18441
18442    pub fn copy_path(
18443        &mut self,
18444        _: &zed_actions::workspace::CopyPath,
18445        _window: &mut Window,
18446        cx: &mut Context<Self>,
18447    ) {
18448        if let Some(path) = self.target_file_abs_path(cx) {
18449            if let Some(path) = path.to_str() {
18450                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18451            }
18452        }
18453    }
18454
18455    pub fn copy_relative_path(
18456        &mut self,
18457        _: &zed_actions::workspace::CopyRelativePath,
18458        _window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        if let Some(path) = self.target_file_path(cx) {
18462            if let Some(path) = path.to_str() {
18463                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18464            }
18465        }
18466    }
18467
18468    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18469        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18470            buffer.read(cx).project_path(cx)
18471        } else {
18472            None
18473        }
18474    }
18475
18476    // Returns true if the editor handled a go-to-line request
18477    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18478        maybe!({
18479            let breakpoint_store = self.breakpoint_store.as_ref()?;
18480
18481            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18482            else {
18483                self.clear_row_highlights::<ActiveDebugLine>();
18484                return None;
18485            };
18486
18487            let position = active_stack_frame.position;
18488            let buffer_id = position.buffer_id?;
18489            let snapshot = self
18490                .project
18491                .as_ref()?
18492                .read(cx)
18493                .buffer_for_id(buffer_id, cx)?
18494                .read(cx)
18495                .snapshot();
18496
18497            let mut handled = false;
18498            for (id, ExcerptRange { context, .. }) in
18499                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18500            {
18501                if context.start.cmp(&position, &snapshot).is_ge()
18502                    || context.end.cmp(&position, &snapshot).is_lt()
18503                {
18504                    continue;
18505                }
18506                let snapshot = self.buffer.read(cx).snapshot(cx);
18507                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18508
18509                handled = true;
18510                self.clear_row_highlights::<ActiveDebugLine>();
18511
18512                self.go_to_line::<ActiveDebugLine>(
18513                    multibuffer_anchor,
18514                    Some(cx.theme().colors().editor_debugger_active_line_background),
18515                    window,
18516                    cx,
18517                );
18518
18519                cx.notify();
18520            }
18521
18522            handled.then_some(())
18523        })
18524        .is_some()
18525    }
18526
18527    pub fn copy_file_name_without_extension(
18528        &mut self,
18529        _: &CopyFileNameWithoutExtension,
18530        _: &mut Window,
18531        cx: &mut Context<Self>,
18532    ) {
18533        if let Some(file) = self.target_file(cx) {
18534            if let Some(file_stem) = file.path().file_stem() {
18535                if let Some(name) = file_stem.to_str() {
18536                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18537                }
18538            }
18539        }
18540    }
18541
18542    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18543        if let Some(file) = self.target_file(cx) {
18544            if let Some(file_name) = file.path().file_name() {
18545                if let Some(name) = file_name.to_str() {
18546                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18547                }
18548            }
18549        }
18550    }
18551
18552    pub fn toggle_git_blame(
18553        &mut self,
18554        _: &::git::Blame,
18555        window: &mut Window,
18556        cx: &mut Context<Self>,
18557    ) {
18558        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18559
18560        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18561            self.start_git_blame(true, window, cx);
18562        }
18563
18564        cx.notify();
18565    }
18566
18567    pub fn toggle_git_blame_inline(
18568        &mut self,
18569        _: &ToggleGitBlameInline,
18570        window: &mut Window,
18571        cx: &mut Context<Self>,
18572    ) {
18573        self.toggle_git_blame_inline_internal(true, window, cx);
18574        cx.notify();
18575    }
18576
18577    pub fn open_git_blame_commit(
18578        &mut self,
18579        _: &OpenGitBlameCommit,
18580        window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        self.open_git_blame_commit_internal(window, cx);
18584    }
18585
18586    fn open_git_blame_commit_internal(
18587        &mut self,
18588        window: &mut Window,
18589        cx: &mut Context<Self>,
18590    ) -> Option<()> {
18591        let blame = self.blame.as_ref()?;
18592        let snapshot = self.snapshot(window, cx);
18593        let cursor = self.selections.newest::<Point>(cx).head();
18594        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18595        let blame_entry = blame
18596            .update(cx, |blame, cx| {
18597                blame
18598                    .blame_for_rows(
18599                        &[RowInfo {
18600                            buffer_id: Some(buffer.remote_id()),
18601                            buffer_row: Some(point.row),
18602                            ..Default::default()
18603                        }],
18604                        cx,
18605                    )
18606                    .next()
18607            })
18608            .flatten()?;
18609        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18610        let repo = blame.read(cx).repository(cx)?;
18611        let workspace = self.workspace()?.downgrade();
18612        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18613        None
18614    }
18615
18616    pub fn git_blame_inline_enabled(&self) -> bool {
18617        self.git_blame_inline_enabled
18618    }
18619
18620    pub fn toggle_selection_menu(
18621        &mut self,
18622        _: &ToggleSelectionMenu,
18623        _: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        self.show_selection_menu = self
18627            .show_selection_menu
18628            .map(|show_selections_menu| !show_selections_menu)
18629            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18630
18631        cx.notify();
18632    }
18633
18634    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18635        self.show_selection_menu
18636            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18637    }
18638
18639    fn start_git_blame(
18640        &mut self,
18641        user_triggered: bool,
18642        window: &mut Window,
18643        cx: &mut Context<Self>,
18644    ) {
18645        if let Some(project) = self.project.as_ref() {
18646            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18647                return;
18648            };
18649
18650            if buffer.read(cx).file().is_none() {
18651                return;
18652            }
18653
18654            let focused = self.focus_handle(cx).contains_focused(window, cx);
18655
18656            let project = project.clone();
18657            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18658            self.blame_subscription =
18659                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18660            self.blame = Some(blame);
18661        }
18662    }
18663
18664    fn toggle_git_blame_inline_internal(
18665        &mut self,
18666        user_triggered: bool,
18667        window: &mut Window,
18668        cx: &mut Context<Self>,
18669    ) {
18670        if self.git_blame_inline_enabled {
18671            self.git_blame_inline_enabled = false;
18672            self.show_git_blame_inline = false;
18673            self.show_git_blame_inline_delay_task.take();
18674        } else {
18675            self.git_blame_inline_enabled = true;
18676            self.start_git_blame_inline(user_triggered, window, cx);
18677        }
18678
18679        cx.notify();
18680    }
18681
18682    fn start_git_blame_inline(
18683        &mut self,
18684        user_triggered: bool,
18685        window: &mut Window,
18686        cx: &mut Context<Self>,
18687    ) {
18688        self.start_git_blame(user_triggered, window, cx);
18689
18690        if ProjectSettings::get_global(cx)
18691            .git
18692            .inline_blame_delay()
18693            .is_some()
18694        {
18695            self.start_inline_blame_timer(window, cx);
18696        } else {
18697            self.show_git_blame_inline = true
18698        }
18699    }
18700
18701    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18702        self.blame.as_ref()
18703    }
18704
18705    pub fn show_git_blame_gutter(&self) -> bool {
18706        self.show_git_blame_gutter
18707    }
18708
18709    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18710        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18711    }
18712
18713    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18714        self.show_git_blame_inline
18715            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18716            && !self.newest_selection_head_on_empty_line(cx)
18717            && self.has_blame_entries(cx)
18718    }
18719
18720    fn has_blame_entries(&self, cx: &App) -> bool {
18721        self.blame()
18722            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18723    }
18724
18725    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18726        let cursor_anchor = self.selections.newest_anchor().head();
18727
18728        let snapshot = self.buffer.read(cx).snapshot(cx);
18729        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18730
18731        snapshot.line_len(buffer_row) == 0
18732    }
18733
18734    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18735        let buffer_and_selection = maybe!({
18736            let selection = self.selections.newest::<Point>(cx);
18737            let selection_range = selection.range();
18738
18739            let multi_buffer = self.buffer().read(cx);
18740            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18741            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18742
18743            let (buffer, range, _) = if selection.reversed {
18744                buffer_ranges.first()
18745            } else {
18746                buffer_ranges.last()
18747            }?;
18748
18749            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18750                ..text::ToPoint::to_point(&range.end, &buffer).row;
18751            Some((
18752                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18753                selection,
18754            ))
18755        });
18756
18757        let Some((buffer, selection)) = buffer_and_selection else {
18758            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18759        };
18760
18761        let Some(project) = self.project.as_ref() else {
18762            return Task::ready(Err(anyhow!("editor does not have project")));
18763        };
18764
18765        project.update(cx, |project, cx| {
18766            project.get_permalink_to_line(&buffer, selection, cx)
18767        })
18768    }
18769
18770    pub fn copy_permalink_to_line(
18771        &mut self,
18772        _: &CopyPermalinkToLine,
18773        window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        let permalink_task = self.get_permalink_to_line(cx);
18777        let workspace = self.workspace();
18778
18779        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18780            Ok(permalink) => {
18781                cx.update(|_, cx| {
18782                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18783                })
18784                .ok();
18785            }
18786            Err(err) => {
18787                let message = format!("Failed to copy permalink: {err}");
18788
18789                anyhow::Result::<()>::Err(err).log_err();
18790
18791                if let Some(workspace) = workspace {
18792                    workspace
18793                        .update_in(cx, |workspace, _, cx| {
18794                            struct CopyPermalinkToLine;
18795
18796                            workspace.show_toast(
18797                                Toast::new(
18798                                    NotificationId::unique::<CopyPermalinkToLine>(),
18799                                    message,
18800                                ),
18801                                cx,
18802                            )
18803                        })
18804                        .ok();
18805                }
18806            }
18807        })
18808        .detach();
18809    }
18810
18811    pub fn copy_file_location(
18812        &mut self,
18813        _: &CopyFileLocation,
18814        _: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) {
18817        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18818        if let Some(file) = self.target_file(cx) {
18819            if let Some(path) = file.path().to_str() {
18820                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18821            }
18822        }
18823    }
18824
18825    pub fn open_permalink_to_line(
18826        &mut self,
18827        _: &OpenPermalinkToLine,
18828        window: &mut Window,
18829        cx: &mut Context<Self>,
18830    ) {
18831        let permalink_task = self.get_permalink_to_line(cx);
18832        let workspace = self.workspace();
18833
18834        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18835            Ok(permalink) => {
18836                cx.update(|_, cx| {
18837                    cx.open_url(permalink.as_ref());
18838                })
18839                .ok();
18840            }
18841            Err(err) => {
18842                let message = format!("Failed to open permalink: {err}");
18843
18844                anyhow::Result::<()>::Err(err).log_err();
18845
18846                if let Some(workspace) = workspace {
18847                    workspace
18848                        .update(cx, |workspace, cx| {
18849                            struct OpenPermalinkToLine;
18850
18851                            workspace.show_toast(
18852                                Toast::new(
18853                                    NotificationId::unique::<OpenPermalinkToLine>(),
18854                                    message,
18855                                ),
18856                                cx,
18857                            )
18858                        })
18859                        .ok();
18860                }
18861            }
18862        })
18863        .detach();
18864    }
18865
18866    pub fn insert_uuid_v4(
18867        &mut self,
18868        _: &InsertUuidV4,
18869        window: &mut Window,
18870        cx: &mut Context<Self>,
18871    ) {
18872        self.insert_uuid(UuidVersion::V4, window, cx);
18873    }
18874
18875    pub fn insert_uuid_v7(
18876        &mut self,
18877        _: &InsertUuidV7,
18878        window: &mut Window,
18879        cx: &mut Context<Self>,
18880    ) {
18881        self.insert_uuid(UuidVersion::V7, window, cx);
18882    }
18883
18884    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18885        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18886        self.transact(window, cx, |this, window, cx| {
18887            let edits = this
18888                .selections
18889                .all::<Point>(cx)
18890                .into_iter()
18891                .map(|selection| {
18892                    let uuid = match version {
18893                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18894                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18895                    };
18896
18897                    (selection.range(), uuid.to_string())
18898                });
18899            this.edit(edits, cx);
18900            this.refresh_inline_completion(true, false, window, cx);
18901        });
18902    }
18903
18904    pub fn open_selections_in_multibuffer(
18905        &mut self,
18906        _: &OpenSelectionsInMultibuffer,
18907        window: &mut Window,
18908        cx: &mut Context<Self>,
18909    ) {
18910        let multibuffer = self.buffer.read(cx);
18911
18912        let Some(buffer) = multibuffer.as_singleton() else {
18913            return;
18914        };
18915
18916        let Some(workspace) = self.workspace() else {
18917            return;
18918        };
18919
18920        let title = multibuffer.title(cx).to_string();
18921
18922        let locations = self
18923            .selections
18924            .all_anchors(cx)
18925            .into_iter()
18926            .map(|selection| Location {
18927                buffer: buffer.clone(),
18928                range: selection.start.text_anchor..selection.end.text_anchor,
18929            })
18930            .collect::<Vec<_>>();
18931
18932        cx.spawn_in(window, async move |_, cx| {
18933            workspace.update_in(cx, |workspace, window, cx| {
18934                Self::open_locations_in_multibuffer(
18935                    workspace,
18936                    locations,
18937                    format!("Selections for '{title}'"),
18938                    false,
18939                    MultibufferSelectionMode::All,
18940                    window,
18941                    cx,
18942                );
18943            })
18944        })
18945        .detach();
18946    }
18947
18948    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18949    /// last highlight added will be used.
18950    ///
18951    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18952    pub fn highlight_rows<T: 'static>(
18953        &mut self,
18954        range: Range<Anchor>,
18955        color: Hsla,
18956        options: RowHighlightOptions,
18957        cx: &mut Context<Self>,
18958    ) {
18959        let snapshot = self.buffer().read(cx).snapshot(cx);
18960        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18961        let ix = row_highlights.binary_search_by(|highlight| {
18962            Ordering::Equal
18963                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18964                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18965        });
18966
18967        if let Err(mut ix) = ix {
18968            let index = post_inc(&mut self.highlight_order);
18969
18970            // If this range intersects with the preceding highlight, then merge it with
18971            // the preceding highlight. Otherwise insert a new highlight.
18972            let mut merged = false;
18973            if ix > 0 {
18974                let prev_highlight = &mut row_highlights[ix - 1];
18975                if prev_highlight
18976                    .range
18977                    .end
18978                    .cmp(&range.start, &snapshot)
18979                    .is_ge()
18980                {
18981                    ix -= 1;
18982                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18983                        prev_highlight.range.end = range.end;
18984                    }
18985                    merged = true;
18986                    prev_highlight.index = index;
18987                    prev_highlight.color = color;
18988                    prev_highlight.options = options;
18989                }
18990            }
18991
18992            if !merged {
18993                row_highlights.insert(
18994                    ix,
18995                    RowHighlight {
18996                        range: range.clone(),
18997                        index,
18998                        color,
18999                        options,
19000                        type_id: TypeId::of::<T>(),
19001                    },
19002                );
19003            }
19004
19005            // If any of the following highlights intersect with this one, merge them.
19006            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19007                let highlight = &row_highlights[ix];
19008                if next_highlight
19009                    .range
19010                    .start
19011                    .cmp(&highlight.range.end, &snapshot)
19012                    .is_le()
19013                {
19014                    if next_highlight
19015                        .range
19016                        .end
19017                        .cmp(&highlight.range.end, &snapshot)
19018                        .is_gt()
19019                    {
19020                        row_highlights[ix].range.end = next_highlight.range.end;
19021                    }
19022                    row_highlights.remove(ix + 1);
19023                } else {
19024                    break;
19025                }
19026            }
19027        }
19028    }
19029
19030    /// Remove any highlighted row ranges of the given type that intersect the
19031    /// given ranges.
19032    pub fn remove_highlighted_rows<T: 'static>(
19033        &mut self,
19034        ranges_to_remove: Vec<Range<Anchor>>,
19035        cx: &mut Context<Self>,
19036    ) {
19037        let snapshot = self.buffer().read(cx).snapshot(cx);
19038        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19039        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19040        row_highlights.retain(|highlight| {
19041            while let Some(range_to_remove) = ranges_to_remove.peek() {
19042                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19043                    Ordering::Less | Ordering::Equal => {
19044                        ranges_to_remove.next();
19045                    }
19046                    Ordering::Greater => {
19047                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19048                            Ordering::Less | Ordering::Equal => {
19049                                return false;
19050                            }
19051                            Ordering::Greater => break,
19052                        }
19053                    }
19054                }
19055            }
19056
19057            true
19058        })
19059    }
19060
19061    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19062    pub fn clear_row_highlights<T: 'static>(&mut self) {
19063        self.highlighted_rows.remove(&TypeId::of::<T>());
19064    }
19065
19066    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19067    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19068        self.highlighted_rows
19069            .get(&TypeId::of::<T>())
19070            .map_or(&[] as &[_], |vec| vec.as_slice())
19071            .iter()
19072            .map(|highlight| (highlight.range.clone(), highlight.color))
19073    }
19074
19075    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19076    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19077    /// Allows to ignore certain kinds of highlights.
19078    pub fn highlighted_display_rows(
19079        &self,
19080        window: &mut Window,
19081        cx: &mut App,
19082    ) -> BTreeMap<DisplayRow, LineHighlight> {
19083        let snapshot = self.snapshot(window, cx);
19084        let mut used_highlight_orders = HashMap::default();
19085        self.highlighted_rows
19086            .iter()
19087            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19088            .fold(
19089                BTreeMap::<DisplayRow, LineHighlight>::new(),
19090                |mut unique_rows, highlight| {
19091                    let start = highlight.range.start.to_display_point(&snapshot);
19092                    let end = highlight.range.end.to_display_point(&snapshot);
19093                    let start_row = start.row().0;
19094                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19095                        && end.column() == 0
19096                    {
19097                        end.row().0.saturating_sub(1)
19098                    } else {
19099                        end.row().0
19100                    };
19101                    for row in start_row..=end_row {
19102                        let used_index =
19103                            used_highlight_orders.entry(row).or_insert(highlight.index);
19104                        if highlight.index >= *used_index {
19105                            *used_index = highlight.index;
19106                            unique_rows.insert(
19107                                DisplayRow(row),
19108                                LineHighlight {
19109                                    include_gutter: highlight.options.include_gutter,
19110                                    border: None,
19111                                    background: highlight.color.into(),
19112                                    type_id: Some(highlight.type_id),
19113                                },
19114                            );
19115                        }
19116                    }
19117                    unique_rows
19118                },
19119            )
19120    }
19121
19122    pub fn highlighted_display_row_for_autoscroll(
19123        &self,
19124        snapshot: &DisplaySnapshot,
19125    ) -> Option<DisplayRow> {
19126        self.highlighted_rows
19127            .values()
19128            .flat_map(|highlighted_rows| highlighted_rows.iter())
19129            .filter_map(|highlight| {
19130                if highlight.options.autoscroll {
19131                    Some(highlight.range.start.to_display_point(snapshot).row())
19132                } else {
19133                    None
19134                }
19135            })
19136            .min()
19137    }
19138
19139    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19140        self.highlight_background::<SearchWithinRange>(
19141            ranges,
19142            |colors| colors.colors().editor_document_highlight_read_background,
19143            cx,
19144        )
19145    }
19146
19147    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19148        self.breadcrumb_header = Some(new_header);
19149    }
19150
19151    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19152        self.clear_background_highlights::<SearchWithinRange>(cx);
19153    }
19154
19155    pub fn highlight_background<T: 'static>(
19156        &mut self,
19157        ranges: &[Range<Anchor>],
19158        color_fetcher: fn(&Theme) -> Hsla,
19159        cx: &mut Context<Self>,
19160    ) {
19161        self.background_highlights.insert(
19162            HighlightKey::Type(TypeId::of::<T>()),
19163            (color_fetcher, Arc::from(ranges)),
19164        );
19165        self.scrollbar_marker_state.dirty = true;
19166        cx.notify();
19167    }
19168
19169    pub fn highlight_background_key<T: 'static>(
19170        &mut self,
19171        key: usize,
19172        ranges: &[Range<Anchor>],
19173        color_fetcher: fn(&Theme) -> Hsla,
19174        cx: &mut Context<Self>,
19175    ) {
19176        self.background_highlights.insert(
19177            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19178            (color_fetcher, Arc::from(ranges)),
19179        );
19180        self.scrollbar_marker_state.dirty = true;
19181        cx.notify();
19182    }
19183
19184    pub fn clear_background_highlights<T: 'static>(
19185        &mut self,
19186        cx: &mut Context<Self>,
19187    ) -> Option<BackgroundHighlight> {
19188        let text_highlights = self
19189            .background_highlights
19190            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19191        if !text_highlights.1.is_empty() {
19192            self.scrollbar_marker_state.dirty = true;
19193            cx.notify();
19194        }
19195        Some(text_highlights)
19196    }
19197
19198    pub fn highlight_gutter<T: 'static>(
19199        &mut self,
19200        ranges: impl Into<Vec<Range<Anchor>>>,
19201        color_fetcher: fn(&App) -> Hsla,
19202        cx: &mut Context<Self>,
19203    ) {
19204        self.gutter_highlights
19205            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19206        cx.notify();
19207    }
19208
19209    pub fn clear_gutter_highlights<T: 'static>(
19210        &mut self,
19211        cx: &mut Context<Self>,
19212    ) -> Option<GutterHighlight> {
19213        cx.notify();
19214        self.gutter_highlights.remove(&TypeId::of::<T>())
19215    }
19216
19217    pub fn insert_gutter_highlight<T: 'static>(
19218        &mut self,
19219        range: Range<Anchor>,
19220        color_fetcher: fn(&App) -> Hsla,
19221        cx: &mut Context<Self>,
19222    ) {
19223        let snapshot = self.buffer().read(cx).snapshot(cx);
19224        let mut highlights = self
19225            .gutter_highlights
19226            .remove(&TypeId::of::<T>())
19227            .map(|(_, highlights)| highlights)
19228            .unwrap_or_default();
19229        let ix = highlights.binary_search_by(|highlight| {
19230            Ordering::Equal
19231                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19232                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19233        });
19234        if let Err(ix) = ix {
19235            highlights.insert(ix, range);
19236        }
19237        self.gutter_highlights
19238            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19239    }
19240
19241    pub fn remove_gutter_highlights<T: 'static>(
19242        &mut self,
19243        ranges_to_remove: Vec<Range<Anchor>>,
19244        cx: &mut Context<Self>,
19245    ) {
19246        let snapshot = self.buffer().read(cx).snapshot(cx);
19247        let Some((color_fetcher, mut gutter_highlights)) =
19248            self.gutter_highlights.remove(&TypeId::of::<T>())
19249        else {
19250            return;
19251        };
19252        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19253        gutter_highlights.retain(|highlight| {
19254            while let Some(range_to_remove) = ranges_to_remove.peek() {
19255                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19256                    Ordering::Less | Ordering::Equal => {
19257                        ranges_to_remove.next();
19258                    }
19259                    Ordering::Greater => {
19260                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19261                            Ordering::Less | Ordering::Equal => {
19262                                return false;
19263                            }
19264                            Ordering::Greater => break,
19265                        }
19266                    }
19267                }
19268            }
19269
19270            true
19271        });
19272        self.gutter_highlights
19273            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19274    }
19275
19276    #[cfg(feature = "test-support")]
19277    pub fn all_text_highlights(
19278        &self,
19279        window: &mut Window,
19280        cx: &mut Context<Self>,
19281    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19282        let snapshot = self.snapshot(window, cx);
19283        self.display_map.update(cx, |display_map, _| {
19284            display_map
19285                .all_text_highlights()
19286                .map(|highlight| {
19287                    let (style, ranges) = highlight.as_ref();
19288                    (
19289                        *style,
19290                        ranges
19291                            .iter()
19292                            .map(|range| range.clone().to_display_points(&snapshot))
19293                            .collect(),
19294                    )
19295                })
19296                .collect()
19297        })
19298    }
19299
19300    #[cfg(feature = "test-support")]
19301    pub fn all_text_background_highlights(
19302        &self,
19303        window: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19306        let snapshot = self.snapshot(window, cx);
19307        let buffer = &snapshot.buffer_snapshot;
19308        let start = buffer.anchor_before(0);
19309        let end = buffer.anchor_after(buffer.len());
19310        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19311    }
19312
19313    #[cfg(feature = "test-support")]
19314    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19315        let snapshot = self.buffer().read(cx).snapshot(cx);
19316
19317        let highlights = self
19318            .background_highlights
19319            .get(&HighlightKey::Type(TypeId::of::<
19320                items::BufferSearchHighlights,
19321            >()));
19322
19323        if let Some((_color, ranges)) = highlights {
19324            ranges
19325                .iter()
19326                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19327                .collect_vec()
19328        } else {
19329            vec![]
19330        }
19331    }
19332
19333    fn document_highlights_for_position<'a>(
19334        &'a self,
19335        position: Anchor,
19336        buffer: &'a MultiBufferSnapshot,
19337    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19338        let read_highlights = self
19339            .background_highlights
19340            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19341            .map(|h| &h.1);
19342        let write_highlights = self
19343            .background_highlights
19344            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19345            .map(|h| &h.1);
19346        let left_position = position.bias_left(buffer);
19347        let right_position = position.bias_right(buffer);
19348        read_highlights
19349            .into_iter()
19350            .chain(write_highlights)
19351            .flat_map(move |ranges| {
19352                let start_ix = match ranges.binary_search_by(|probe| {
19353                    let cmp = probe.end.cmp(&left_position, buffer);
19354                    if cmp.is_ge() {
19355                        Ordering::Greater
19356                    } else {
19357                        Ordering::Less
19358                    }
19359                }) {
19360                    Ok(i) | Err(i) => i,
19361                };
19362
19363                ranges[start_ix..]
19364                    .iter()
19365                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19366            })
19367    }
19368
19369    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19370        self.background_highlights
19371            .get(&HighlightKey::Type(TypeId::of::<T>()))
19372            .map_or(false, |(_, highlights)| !highlights.is_empty())
19373    }
19374
19375    pub fn background_highlights_in_range(
19376        &self,
19377        search_range: Range<Anchor>,
19378        display_snapshot: &DisplaySnapshot,
19379        theme: &Theme,
19380    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19381        let mut results = Vec::new();
19382        for (color_fetcher, ranges) in self.background_highlights.values() {
19383            let color = color_fetcher(theme);
19384            let start_ix = match ranges.binary_search_by(|probe| {
19385                let cmp = probe
19386                    .end
19387                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19388                if cmp.is_gt() {
19389                    Ordering::Greater
19390                } else {
19391                    Ordering::Less
19392                }
19393            }) {
19394                Ok(i) | Err(i) => i,
19395            };
19396            for range in &ranges[start_ix..] {
19397                if range
19398                    .start
19399                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19400                    .is_ge()
19401                {
19402                    break;
19403                }
19404
19405                let start = range.start.to_display_point(display_snapshot);
19406                let end = range.end.to_display_point(display_snapshot);
19407                results.push((start..end, color))
19408            }
19409        }
19410        results
19411    }
19412
19413    pub fn background_highlight_row_ranges<T: 'static>(
19414        &self,
19415        search_range: Range<Anchor>,
19416        display_snapshot: &DisplaySnapshot,
19417        count: usize,
19418    ) -> Vec<RangeInclusive<DisplayPoint>> {
19419        let mut results = Vec::new();
19420        let Some((_, ranges)) = self
19421            .background_highlights
19422            .get(&HighlightKey::Type(TypeId::of::<T>()))
19423        else {
19424            return vec![];
19425        };
19426
19427        let start_ix = match ranges.binary_search_by(|probe| {
19428            let cmp = probe
19429                .end
19430                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19431            if cmp.is_gt() {
19432                Ordering::Greater
19433            } else {
19434                Ordering::Less
19435            }
19436        }) {
19437            Ok(i) | Err(i) => i,
19438        };
19439        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19440            if let (Some(start_display), Some(end_display)) = (start, end) {
19441                results.push(
19442                    start_display.to_display_point(display_snapshot)
19443                        ..=end_display.to_display_point(display_snapshot),
19444                );
19445            }
19446        };
19447        let mut start_row: Option<Point> = None;
19448        let mut end_row: Option<Point> = None;
19449        if ranges.len() > count {
19450            return Vec::new();
19451        }
19452        for range in &ranges[start_ix..] {
19453            if range
19454                .start
19455                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19456                .is_ge()
19457            {
19458                break;
19459            }
19460            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19461            if let Some(current_row) = &end_row {
19462                if end.row == current_row.row {
19463                    continue;
19464                }
19465            }
19466            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19467            if start_row.is_none() {
19468                assert_eq!(end_row, None);
19469                start_row = Some(start);
19470                end_row = Some(end);
19471                continue;
19472            }
19473            if let Some(current_end) = end_row.as_mut() {
19474                if start.row > current_end.row + 1 {
19475                    push_region(start_row, end_row);
19476                    start_row = Some(start);
19477                    end_row = Some(end);
19478                } else {
19479                    // Merge two hunks.
19480                    *current_end = end;
19481                }
19482            } else {
19483                unreachable!();
19484            }
19485        }
19486        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19487        push_region(start_row, end_row);
19488        results
19489    }
19490
19491    pub fn gutter_highlights_in_range(
19492        &self,
19493        search_range: Range<Anchor>,
19494        display_snapshot: &DisplaySnapshot,
19495        cx: &App,
19496    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19497        let mut results = Vec::new();
19498        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19499            let color = color_fetcher(cx);
19500            let start_ix = match ranges.binary_search_by(|probe| {
19501                let cmp = probe
19502                    .end
19503                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19504                if cmp.is_gt() {
19505                    Ordering::Greater
19506                } else {
19507                    Ordering::Less
19508                }
19509            }) {
19510                Ok(i) | Err(i) => i,
19511            };
19512            for range in &ranges[start_ix..] {
19513                if range
19514                    .start
19515                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19516                    .is_ge()
19517                {
19518                    break;
19519                }
19520
19521                let start = range.start.to_display_point(display_snapshot);
19522                let end = range.end.to_display_point(display_snapshot);
19523                results.push((start..end, color))
19524            }
19525        }
19526        results
19527    }
19528
19529    /// Get the text ranges corresponding to the redaction query
19530    pub fn redacted_ranges(
19531        &self,
19532        search_range: Range<Anchor>,
19533        display_snapshot: &DisplaySnapshot,
19534        cx: &App,
19535    ) -> Vec<Range<DisplayPoint>> {
19536        display_snapshot
19537            .buffer_snapshot
19538            .redacted_ranges(search_range, |file| {
19539                if let Some(file) = file {
19540                    file.is_private()
19541                        && EditorSettings::get(
19542                            Some(SettingsLocation {
19543                                worktree_id: file.worktree_id(cx),
19544                                path: file.path().as_ref(),
19545                            }),
19546                            cx,
19547                        )
19548                        .redact_private_values
19549                } else {
19550                    false
19551                }
19552            })
19553            .map(|range| {
19554                range.start.to_display_point(display_snapshot)
19555                    ..range.end.to_display_point(display_snapshot)
19556            })
19557            .collect()
19558    }
19559
19560    pub fn highlight_text_key<T: 'static>(
19561        &mut self,
19562        key: usize,
19563        ranges: Vec<Range<Anchor>>,
19564        style: HighlightStyle,
19565        cx: &mut Context<Self>,
19566    ) {
19567        self.display_map.update(cx, |map, _| {
19568            map.highlight_text(
19569                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19570                ranges,
19571                style,
19572            );
19573        });
19574        cx.notify();
19575    }
19576
19577    pub fn highlight_text<T: 'static>(
19578        &mut self,
19579        ranges: Vec<Range<Anchor>>,
19580        style: HighlightStyle,
19581        cx: &mut Context<Self>,
19582    ) {
19583        self.display_map.update(cx, |map, _| {
19584            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19585        });
19586        cx.notify();
19587    }
19588
19589    pub(crate) fn highlight_inlays<T: 'static>(
19590        &mut self,
19591        highlights: Vec<InlayHighlight>,
19592        style: HighlightStyle,
19593        cx: &mut Context<Self>,
19594    ) {
19595        self.display_map.update(cx, |map, _| {
19596            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19597        });
19598        cx.notify();
19599    }
19600
19601    pub fn text_highlights<'a, T: 'static>(
19602        &'a self,
19603        cx: &'a App,
19604    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19605        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19606    }
19607
19608    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19609        let cleared = self
19610            .display_map
19611            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19612        if cleared {
19613            cx.notify();
19614        }
19615    }
19616
19617    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19618        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19619            && self.focus_handle.is_focused(window)
19620    }
19621
19622    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19623        self.show_cursor_when_unfocused = is_enabled;
19624        cx.notify();
19625    }
19626
19627    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19628        cx.notify();
19629    }
19630
19631    fn on_debug_session_event(
19632        &mut self,
19633        _session: Entity<Session>,
19634        event: &SessionEvent,
19635        cx: &mut Context<Self>,
19636    ) {
19637        match event {
19638            SessionEvent::InvalidateInlineValue => {
19639                self.refresh_inline_values(cx);
19640            }
19641            _ => {}
19642        }
19643    }
19644
19645    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19646        let Some(project) = self.project.clone() else {
19647            return;
19648        };
19649
19650        if !self.inline_value_cache.enabled {
19651            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19652            self.splice_inlays(&inlays, Vec::new(), cx);
19653            return;
19654        }
19655
19656        let current_execution_position = self
19657            .highlighted_rows
19658            .get(&TypeId::of::<ActiveDebugLine>())
19659            .and_then(|lines| lines.last().map(|line| line.range.end));
19660
19661        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19662            let inline_values = editor
19663                .update(cx, |editor, cx| {
19664                    let Some(current_execution_position) = current_execution_position else {
19665                        return Some(Task::ready(Ok(Vec::new())));
19666                    };
19667
19668                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19669                        let snapshot = buffer.snapshot(cx);
19670
19671                        let excerpt = snapshot.excerpt_containing(
19672                            current_execution_position..current_execution_position,
19673                        )?;
19674
19675                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19676                    })?;
19677
19678                    let range =
19679                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19680
19681                    project.inline_values(buffer, range, cx)
19682                })
19683                .ok()
19684                .flatten()?
19685                .await
19686                .context("refreshing debugger inlays")
19687                .log_err()?;
19688
19689            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19690
19691            for (buffer_id, inline_value) in inline_values
19692                .into_iter()
19693                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19694            {
19695                buffer_inline_values
19696                    .entry(buffer_id)
19697                    .or_default()
19698                    .push(inline_value);
19699            }
19700
19701            editor
19702                .update(cx, |editor, cx| {
19703                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19704                    let mut new_inlays = Vec::default();
19705
19706                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19707                        let buffer_id = buffer_snapshot.remote_id();
19708                        buffer_inline_values
19709                            .get(&buffer_id)
19710                            .into_iter()
19711                            .flatten()
19712                            .for_each(|hint| {
19713                                let inlay = Inlay::debugger(
19714                                    post_inc(&mut editor.next_inlay_id),
19715                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19716                                    hint.text(),
19717                                );
19718                                if !inlay.text.chars().contains(&'\n') {
19719                                    new_inlays.push(inlay);
19720                                }
19721                            });
19722                    }
19723
19724                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19725                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19726
19727                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19728                })
19729                .ok()?;
19730            Some(())
19731        });
19732    }
19733
19734    fn on_buffer_event(
19735        &mut self,
19736        multibuffer: &Entity<MultiBuffer>,
19737        event: &multi_buffer::Event,
19738        window: &mut Window,
19739        cx: &mut Context<Self>,
19740    ) {
19741        match event {
19742            multi_buffer::Event::Edited {
19743                singleton_buffer_edited,
19744                edited_buffer,
19745            } => {
19746                self.scrollbar_marker_state.dirty = true;
19747                self.active_indent_guides_state.dirty = true;
19748                self.refresh_active_diagnostics(cx);
19749                self.refresh_code_actions(window, cx);
19750                self.refresh_selected_text_highlights(true, window, cx);
19751                self.refresh_single_line_folds(window, cx);
19752                refresh_matching_bracket_highlights(self, window, cx);
19753                if self.has_active_inline_completion() {
19754                    self.update_visible_inline_completion(window, cx);
19755                }
19756                if let Some(project) = self.project.as_ref() {
19757                    if let Some(edited_buffer) = edited_buffer {
19758                        project.update(cx, |project, cx| {
19759                            self.registered_buffers
19760                                .entry(edited_buffer.read(cx).remote_id())
19761                                .or_insert_with(|| {
19762                                    project
19763                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19764                                });
19765                        });
19766                    }
19767                }
19768                cx.emit(EditorEvent::BufferEdited);
19769                cx.emit(SearchEvent::MatchesInvalidated);
19770
19771                if let Some(buffer) = edited_buffer {
19772                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19773                }
19774
19775                if *singleton_buffer_edited {
19776                    if let Some(buffer) = edited_buffer {
19777                        if buffer.read(cx).file().is_none() {
19778                            cx.emit(EditorEvent::TitleChanged);
19779                        }
19780                    }
19781                    if let Some(project) = &self.project {
19782                        #[allow(clippy::mutable_key_type)]
19783                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19784                            multibuffer
19785                                .all_buffers()
19786                                .into_iter()
19787                                .filter_map(|buffer| {
19788                                    buffer.update(cx, |buffer, cx| {
19789                                        let language = buffer.language()?;
19790                                        let should_discard = project.update(cx, |project, cx| {
19791                                            project.is_local()
19792                                                && !project.has_language_servers_for(buffer, cx)
19793                                        });
19794                                        should_discard.not().then_some(language.clone())
19795                                    })
19796                                })
19797                                .collect::<HashSet<_>>()
19798                        });
19799                        if !languages_affected.is_empty() {
19800                            self.refresh_inlay_hints(
19801                                InlayHintRefreshReason::BufferEdited(languages_affected),
19802                                cx,
19803                            );
19804                        }
19805                    }
19806                }
19807
19808                let Some(project) = &self.project else { return };
19809                let (telemetry, is_via_ssh) = {
19810                    let project = project.read(cx);
19811                    let telemetry = project.client().telemetry().clone();
19812                    let is_via_ssh = project.is_via_ssh();
19813                    (telemetry, is_via_ssh)
19814                };
19815                refresh_linked_ranges(self, window, cx);
19816                telemetry.log_edit_event("editor", is_via_ssh);
19817            }
19818            multi_buffer::Event::ExcerptsAdded {
19819                buffer,
19820                predecessor,
19821                excerpts,
19822            } => {
19823                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19824                let buffer_id = buffer.read(cx).remote_id();
19825                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19826                    if let Some(project) = &self.project {
19827                        update_uncommitted_diff_for_buffer(
19828                            cx.entity(),
19829                            project,
19830                            [buffer.clone()],
19831                            self.buffer.clone(),
19832                            cx,
19833                        )
19834                        .detach();
19835                    }
19836                }
19837                self.update_lsp_data(false, Some(buffer_id), window, cx);
19838                cx.emit(EditorEvent::ExcerptsAdded {
19839                    buffer: buffer.clone(),
19840                    predecessor: *predecessor,
19841                    excerpts: excerpts.clone(),
19842                });
19843                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19844            }
19845            multi_buffer::Event::ExcerptsRemoved {
19846                ids,
19847                removed_buffer_ids,
19848            } => {
19849                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19850                let buffer = self.buffer.read(cx);
19851                self.registered_buffers
19852                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19853                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19854                cx.emit(EditorEvent::ExcerptsRemoved {
19855                    ids: ids.clone(),
19856                    removed_buffer_ids: removed_buffer_ids.clone(),
19857                });
19858            }
19859            multi_buffer::Event::ExcerptsEdited {
19860                excerpt_ids,
19861                buffer_ids,
19862            } => {
19863                self.display_map.update(cx, |map, cx| {
19864                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19865                });
19866                cx.emit(EditorEvent::ExcerptsEdited {
19867                    ids: excerpt_ids.clone(),
19868                });
19869            }
19870            multi_buffer::Event::ExcerptsExpanded { ids } => {
19871                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19872                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19873            }
19874            multi_buffer::Event::Reparsed(buffer_id) => {
19875                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19876                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19877
19878                cx.emit(EditorEvent::Reparsed(*buffer_id));
19879            }
19880            multi_buffer::Event::DiffHunksToggled => {
19881                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19882            }
19883            multi_buffer::Event::LanguageChanged(buffer_id) => {
19884                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19885                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19886                cx.emit(EditorEvent::Reparsed(*buffer_id));
19887                cx.notify();
19888            }
19889            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19890            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19891            multi_buffer::Event::FileHandleChanged
19892            | multi_buffer::Event::Reloaded
19893            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19894            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19895            multi_buffer::Event::DiagnosticsUpdated => {
19896                self.update_diagnostics_state(window, cx);
19897            }
19898            _ => {}
19899        };
19900    }
19901
19902    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19903        if !self.diagnostics_enabled() {
19904            return;
19905        }
19906        self.refresh_active_diagnostics(cx);
19907        self.refresh_inline_diagnostics(true, window, cx);
19908        self.scrollbar_marker_state.dirty = true;
19909        cx.notify();
19910    }
19911
19912    pub fn start_temporary_diff_override(&mut self) {
19913        self.load_diff_task.take();
19914        self.temporary_diff_override = true;
19915    }
19916
19917    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19918        self.temporary_diff_override = false;
19919        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19920        self.buffer.update(cx, |buffer, cx| {
19921            buffer.set_all_diff_hunks_collapsed(cx);
19922        });
19923
19924        if let Some(project) = self.project.clone() {
19925            self.load_diff_task = Some(
19926                update_uncommitted_diff_for_buffer(
19927                    cx.entity(),
19928                    &project,
19929                    self.buffer.read(cx).all_buffers(),
19930                    self.buffer.clone(),
19931                    cx,
19932                )
19933                .shared(),
19934            );
19935        }
19936    }
19937
19938    fn on_display_map_changed(
19939        &mut self,
19940        _: Entity<DisplayMap>,
19941        _: &mut Window,
19942        cx: &mut Context<Self>,
19943    ) {
19944        cx.notify();
19945    }
19946
19947    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19948        if self.diagnostics_enabled() {
19949            let new_severity = EditorSettings::get_global(cx)
19950                .diagnostics_max_severity
19951                .unwrap_or(DiagnosticSeverity::Hint);
19952            self.set_max_diagnostics_severity(new_severity, cx);
19953        }
19954        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19955        self.update_edit_prediction_settings(cx);
19956        self.refresh_inline_completion(true, false, window, cx);
19957        self.refresh_inline_values(cx);
19958        self.refresh_inlay_hints(
19959            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19960                self.selections.newest_anchor().head(),
19961                &self.buffer.read(cx).snapshot(cx),
19962                cx,
19963            )),
19964            cx,
19965        );
19966
19967        let old_cursor_shape = self.cursor_shape;
19968
19969        {
19970            let editor_settings = EditorSettings::get_global(cx);
19971            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19972            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19973            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19974            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19975        }
19976
19977        if old_cursor_shape != self.cursor_shape {
19978            cx.emit(EditorEvent::CursorShapeChanged);
19979        }
19980
19981        let project_settings = ProjectSettings::get_global(cx);
19982        self.serialize_dirty_buffers =
19983            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19984
19985        if self.mode.is_full() {
19986            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19987            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19988            if self.show_inline_diagnostics != show_inline_diagnostics {
19989                self.show_inline_diagnostics = show_inline_diagnostics;
19990                self.refresh_inline_diagnostics(false, window, cx);
19991            }
19992
19993            if self.git_blame_inline_enabled != inline_blame_enabled {
19994                self.toggle_git_blame_inline_internal(false, window, cx);
19995            }
19996
19997            let minimap_settings = EditorSettings::get_global(cx).minimap;
19998            if self.minimap_visibility != MinimapVisibility::Disabled {
19999                if self.minimap_visibility.settings_visibility()
20000                    != minimap_settings.minimap_enabled()
20001                {
20002                    self.set_minimap_visibility(
20003                        MinimapVisibility::for_mode(self.mode(), cx),
20004                        window,
20005                        cx,
20006                    );
20007                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20008                    minimap_entity.update(cx, |minimap_editor, cx| {
20009                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20010                    })
20011                }
20012            }
20013        }
20014
20015        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20016            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20017        }) {
20018            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20019                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20020            }
20021            self.refresh_colors(false, None, window, cx);
20022        }
20023
20024        cx.notify();
20025    }
20026
20027    pub fn set_searchable(&mut self, searchable: bool) {
20028        self.searchable = searchable;
20029    }
20030
20031    pub fn searchable(&self) -> bool {
20032        self.searchable
20033    }
20034
20035    fn open_proposed_changes_editor(
20036        &mut self,
20037        _: &OpenProposedChangesEditor,
20038        window: &mut Window,
20039        cx: &mut Context<Self>,
20040    ) {
20041        let Some(workspace) = self.workspace() else {
20042            cx.propagate();
20043            return;
20044        };
20045
20046        let selections = self.selections.all::<usize>(cx);
20047        let multi_buffer = self.buffer.read(cx);
20048        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20049        let mut new_selections_by_buffer = HashMap::default();
20050        for selection in selections {
20051            for (buffer, range, _) in
20052                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20053            {
20054                let mut range = range.to_point(buffer);
20055                range.start.column = 0;
20056                range.end.column = buffer.line_len(range.end.row);
20057                new_selections_by_buffer
20058                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20059                    .or_insert(Vec::new())
20060                    .push(range)
20061            }
20062        }
20063
20064        let proposed_changes_buffers = new_selections_by_buffer
20065            .into_iter()
20066            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20067            .collect::<Vec<_>>();
20068        let proposed_changes_editor = cx.new(|cx| {
20069            ProposedChangesEditor::new(
20070                "Proposed changes",
20071                proposed_changes_buffers,
20072                self.project.clone(),
20073                window,
20074                cx,
20075            )
20076        });
20077
20078        window.defer(cx, move |window, cx| {
20079            workspace.update(cx, |workspace, cx| {
20080                workspace.active_pane().update(cx, |pane, cx| {
20081                    pane.add_item(
20082                        Box::new(proposed_changes_editor),
20083                        true,
20084                        true,
20085                        None,
20086                        window,
20087                        cx,
20088                    );
20089                });
20090            });
20091        });
20092    }
20093
20094    pub fn open_excerpts_in_split(
20095        &mut self,
20096        _: &OpenExcerptsSplit,
20097        window: &mut Window,
20098        cx: &mut Context<Self>,
20099    ) {
20100        self.open_excerpts_common(None, true, window, cx)
20101    }
20102
20103    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20104        self.open_excerpts_common(None, false, window, cx)
20105    }
20106
20107    fn open_excerpts_common(
20108        &mut self,
20109        jump_data: Option<JumpData>,
20110        split: bool,
20111        window: &mut Window,
20112        cx: &mut Context<Self>,
20113    ) {
20114        let Some(workspace) = self.workspace() else {
20115            cx.propagate();
20116            return;
20117        };
20118
20119        if self.buffer.read(cx).is_singleton() {
20120            cx.propagate();
20121            return;
20122        }
20123
20124        let mut new_selections_by_buffer = HashMap::default();
20125        match &jump_data {
20126            Some(JumpData::MultiBufferPoint {
20127                excerpt_id,
20128                position,
20129                anchor,
20130                line_offset_from_top,
20131            }) => {
20132                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20133                if let Some(buffer) = multi_buffer_snapshot
20134                    .buffer_id_for_excerpt(*excerpt_id)
20135                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20136                {
20137                    let buffer_snapshot = buffer.read(cx).snapshot();
20138                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20139                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20140                    } else {
20141                        buffer_snapshot.clip_point(*position, Bias::Left)
20142                    };
20143                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20144                    new_selections_by_buffer.insert(
20145                        buffer,
20146                        (
20147                            vec![jump_to_offset..jump_to_offset],
20148                            Some(*line_offset_from_top),
20149                        ),
20150                    );
20151                }
20152            }
20153            Some(JumpData::MultiBufferRow {
20154                row,
20155                line_offset_from_top,
20156            }) => {
20157                let point = MultiBufferPoint::new(row.0, 0);
20158                if let Some((buffer, buffer_point, _)) =
20159                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20160                {
20161                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20162                    new_selections_by_buffer
20163                        .entry(buffer)
20164                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20165                        .0
20166                        .push(buffer_offset..buffer_offset)
20167                }
20168            }
20169            None => {
20170                let selections = self.selections.all::<usize>(cx);
20171                let multi_buffer = self.buffer.read(cx);
20172                for selection in selections {
20173                    for (snapshot, range, _, anchor) in multi_buffer
20174                        .snapshot(cx)
20175                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20176                    {
20177                        if let Some(anchor) = anchor {
20178                            // selection is in a deleted hunk
20179                            let Some(buffer_id) = anchor.buffer_id else {
20180                                continue;
20181                            };
20182                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20183                                continue;
20184                            };
20185                            let offset = text::ToOffset::to_offset(
20186                                &anchor.text_anchor,
20187                                &buffer_handle.read(cx).snapshot(),
20188                            );
20189                            let range = offset..offset;
20190                            new_selections_by_buffer
20191                                .entry(buffer_handle)
20192                                .or_insert((Vec::new(), None))
20193                                .0
20194                                .push(range)
20195                        } else {
20196                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20197                            else {
20198                                continue;
20199                            };
20200                            new_selections_by_buffer
20201                                .entry(buffer_handle)
20202                                .or_insert((Vec::new(), None))
20203                                .0
20204                                .push(range)
20205                        }
20206                    }
20207                }
20208            }
20209        }
20210
20211        new_selections_by_buffer
20212            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20213
20214        if new_selections_by_buffer.is_empty() {
20215            return;
20216        }
20217
20218        // We defer the pane interaction because we ourselves are a workspace item
20219        // and activating a new item causes the pane to call a method on us reentrantly,
20220        // which panics if we're on the stack.
20221        window.defer(cx, move |window, cx| {
20222            workspace.update(cx, |workspace, cx| {
20223                let pane = if split {
20224                    workspace.adjacent_pane(window, cx)
20225                } else {
20226                    workspace.active_pane().clone()
20227                };
20228
20229                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20230                    let editor = buffer
20231                        .read(cx)
20232                        .file()
20233                        .is_none()
20234                        .then(|| {
20235                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20236                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20237                            // Instead, we try to activate the existing editor in the pane first.
20238                            let (editor, pane_item_index) =
20239                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20240                                    let editor = item.downcast::<Editor>()?;
20241                                    let singleton_buffer =
20242                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20243                                    if singleton_buffer == buffer {
20244                                        Some((editor, i))
20245                                    } else {
20246                                        None
20247                                    }
20248                                })?;
20249                            pane.update(cx, |pane, cx| {
20250                                pane.activate_item(pane_item_index, true, true, window, cx)
20251                            });
20252                            Some(editor)
20253                        })
20254                        .flatten()
20255                        .unwrap_or_else(|| {
20256                            workspace.open_project_item::<Self>(
20257                                pane.clone(),
20258                                buffer,
20259                                true,
20260                                true,
20261                                window,
20262                                cx,
20263                            )
20264                        });
20265
20266                    editor.update(cx, |editor, cx| {
20267                        let autoscroll = match scroll_offset {
20268                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20269                            None => Autoscroll::newest(),
20270                        };
20271                        let nav_history = editor.nav_history.take();
20272                        editor.change_selections(
20273                            SelectionEffects::scroll(autoscroll),
20274                            window,
20275                            cx,
20276                            |s| {
20277                                s.select_ranges(ranges);
20278                            },
20279                        );
20280                        editor.nav_history = nav_history;
20281                    });
20282                }
20283            })
20284        });
20285    }
20286
20287    // For now, don't allow opening excerpts in buffers that aren't backed by
20288    // regular project files.
20289    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20290        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20291    }
20292
20293    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20294        let snapshot = self.buffer.read(cx).read(cx);
20295        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20296        Some(
20297            ranges
20298                .iter()
20299                .map(move |range| {
20300                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20301                })
20302                .collect(),
20303        )
20304    }
20305
20306    fn selection_replacement_ranges(
20307        &self,
20308        range: Range<OffsetUtf16>,
20309        cx: &mut App,
20310    ) -> Vec<Range<OffsetUtf16>> {
20311        let selections = self.selections.all::<OffsetUtf16>(cx);
20312        let newest_selection = selections
20313            .iter()
20314            .max_by_key(|selection| selection.id)
20315            .unwrap();
20316        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20317        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20318        let snapshot = self.buffer.read(cx).read(cx);
20319        selections
20320            .into_iter()
20321            .map(|mut selection| {
20322                selection.start.0 =
20323                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20324                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20325                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20326                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20327            })
20328            .collect()
20329    }
20330
20331    fn report_editor_event(
20332        &self,
20333        event_type: &'static str,
20334        file_extension: Option<String>,
20335        cx: &App,
20336    ) {
20337        if cfg!(any(test, feature = "test-support")) {
20338            return;
20339        }
20340
20341        let Some(project) = &self.project else { return };
20342
20343        // If None, we are in a file without an extension
20344        let file = self
20345            .buffer
20346            .read(cx)
20347            .as_singleton()
20348            .and_then(|b| b.read(cx).file());
20349        let file_extension = file_extension.or(file
20350            .as_ref()
20351            .and_then(|file| Path::new(file.file_name(cx)).extension())
20352            .and_then(|e| e.to_str())
20353            .map(|a| a.to_string()));
20354
20355        let vim_mode = vim_enabled(cx);
20356
20357        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20358        let copilot_enabled = edit_predictions_provider
20359            == language::language_settings::EditPredictionProvider::Copilot;
20360        let copilot_enabled_for_language = self
20361            .buffer
20362            .read(cx)
20363            .language_settings(cx)
20364            .show_edit_predictions;
20365
20366        let project = project.read(cx);
20367        telemetry::event!(
20368            event_type,
20369            file_extension,
20370            vim_mode,
20371            copilot_enabled,
20372            copilot_enabled_for_language,
20373            edit_predictions_provider,
20374            is_via_ssh = project.is_via_ssh(),
20375        );
20376    }
20377
20378    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20379    /// with each line being an array of {text, highlight} objects.
20380    fn copy_highlight_json(
20381        &mut self,
20382        _: &CopyHighlightJson,
20383        window: &mut Window,
20384        cx: &mut Context<Self>,
20385    ) {
20386        #[derive(Serialize)]
20387        struct Chunk<'a> {
20388            text: String,
20389            highlight: Option<&'a str>,
20390        }
20391
20392        let snapshot = self.buffer.read(cx).snapshot(cx);
20393        let range = self
20394            .selected_text_range(false, window, cx)
20395            .and_then(|selection| {
20396                if selection.range.is_empty() {
20397                    None
20398                } else {
20399                    Some(selection.range)
20400                }
20401            })
20402            .unwrap_or_else(|| 0..snapshot.len());
20403
20404        let chunks = snapshot.chunks(range, true);
20405        let mut lines = Vec::new();
20406        let mut line: VecDeque<Chunk> = VecDeque::new();
20407
20408        let Some(style) = self.style.as_ref() else {
20409            return;
20410        };
20411
20412        for chunk in chunks {
20413            let highlight = chunk
20414                .syntax_highlight_id
20415                .and_then(|id| id.name(&style.syntax));
20416            let mut chunk_lines = chunk.text.split('\n').peekable();
20417            while let Some(text) = chunk_lines.next() {
20418                let mut merged_with_last_token = false;
20419                if let Some(last_token) = line.back_mut() {
20420                    if last_token.highlight == highlight {
20421                        last_token.text.push_str(text);
20422                        merged_with_last_token = true;
20423                    }
20424                }
20425
20426                if !merged_with_last_token {
20427                    line.push_back(Chunk {
20428                        text: text.into(),
20429                        highlight,
20430                    });
20431                }
20432
20433                if chunk_lines.peek().is_some() {
20434                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20435                        line.pop_front();
20436                    }
20437                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20438                        line.pop_back();
20439                    }
20440
20441                    lines.push(mem::take(&mut line));
20442                }
20443            }
20444        }
20445
20446        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20447            return;
20448        };
20449        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20450    }
20451
20452    pub fn open_context_menu(
20453        &mut self,
20454        _: &OpenContextMenu,
20455        window: &mut Window,
20456        cx: &mut Context<Self>,
20457    ) {
20458        self.request_autoscroll(Autoscroll::newest(), cx);
20459        let position = self.selections.newest_display(cx).start;
20460        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20461    }
20462
20463    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20464        &self.inlay_hint_cache
20465    }
20466
20467    pub fn replay_insert_event(
20468        &mut self,
20469        text: &str,
20470        relative_utf16_range: Option<Range<isize>>,
20471        window: &mut Window,
20472        cx: &mut Context<Self>,
20473    ) {
20474        if !self.input_enabled {
20475            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20476            return;
20477        }
20478        if let Some(relative_utf16_range) = relative_utf16_range {
20479            let selections = self.selections.all::<OffsetUtf16>(cx);
20480            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20481                let new_ranges = selections.into_iter().map(|range| {
20482                    let start = OffsetUtf16(
20483                        range
20484                            .head()
20485                            .0
20486                            .saturating_add_signed(relative_utf16_range.start),
20487                    );
20488                    let end = OffsetUtf16(
20489                        range
20490                            .head()
20491                            .0
20492                            .saturating_add_signed(relative_utf16_range.end),
20493                    );
20494                    start..end
20495                });
20496                s.select_ranges(new_ranges);
20497            });
20498        }
20499
20500        self.handle_input(text, window, cx);
20501    }
20502
20503    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20504        let Some(provider) = self.semantics_provider.as_ref() else {
20505            return false;
20506        };
20507
20508        let mut supports = false;
20509        self.buffer().update(cx, |this, cx| {
20510            this.for_each_buffer(|buffer| {
20511                supports |= provider.supports_inlay_hints(buffer, cx);
20512            });
20513        });
20514
20515        supports
20516    }
20517
20518    pub fn is_focused(&self, window: &Window) -> bool {
20519        self.focus_handle.is_focused(window)
20520    }
20521
20522    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20523        cx.emit(EditorEvent::Focused);
20524
20525        if let Some(descendant) = self
20526            .last_focused_descendant
20527            .take()
20528            .and_then(|descendant| descendant.upgrade())
20529        {
20530            window.focus(&descendant);
20531        } else {
20532            if let Some(blame) = self.blame.as_ref() {
20533                blame.update(cx, GitBlame::focus)
20534            }
20535
20536            self.blink_manager.update(cx, BlinkManager::enable);
20537            self.show_cursor_names(window, cx);
20538            self.buffer.update(cx, |buffer, cx| {
20539                buffer.finalize_last_transaction(cx);
20540                if self.leader_id.is_none() {
20541                    buffer.set_active_selections(
20542                        &self.selections.disjoint_anchors(),
20543                        self.selections.line_mode,
20544                        self.cursor_shape,
20545                        cx,
20546                    );
20547                }
20548            });
20549        }
20550    }
20551
20552    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20553        cx.emit(EditorEvent::FocusedIn)
20554    }
20555
20556    fn handle_focus_out(
20557        &mut self,
20558        event: FocusOutEvent,
20559        _window: &mut Window,
20560        cx: &mut Context<Self>,
20561    ) {
20562        if event.blurred != self.focus_handle {
20563            self.last_focused_descendant = Some(event.blurred);
20564        }
20565        self.selection_drag_state = SelectionDragState::None;
20566        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20567    }
20568
20569    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20570        self.blink_manager.update(cx, BlinkManager::disable);
20571        self.buffer
20572            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20573
20574        if let Some(blame) = self.blame.as_ref() {
20575            blame.update(cx, GitBlame::blur)
20576        }
20577        if !self.hover_state.focused(window, cx) {
20578            hide_hover(self, cx);
20579        }
20580        if !self
20581            .context_menu
20582            .borrow()
20583            .as_ref()
20584            .is_some_and(|context_menu| context_menu.focused(window, cx))
20585        {
20586            self.hide_context_menu(window, cx);
20587        }
20588        self.discard_inline_completion(false, cx);
20589        cx.emit(EditorEvent::Blurred);
20590        cx.notify();
20591    }
20592
20593    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20594        let mut pending: String = window
20595            .pending_input_keystrokes()
20596            .into_iter()
20597            .flatten()
20598            .filter_map(|keystroke| {
20599                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20600                    keystroke.key_char.clone()
20601                } else {
20602                    None
20603                }
20604            })
20605            .collect();
20606
20607        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20608            pending = "".to_string();
20609        }
20610
20611        let existing_pending = self
20612            .text_highlights::<PendingInput>(cx)
20613            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20614        if existing_pending.is_none() && pending.is_empty() {
20615            return;
20616        }
20617        let transaction =
20618            self.transact(window, cx, |this, window, cx| {
20619                let selections = this.selections.all::<usize>(cx);
20620                let edits = selections
20621                    .iter()
20622                    .map(|selection| (selection.end..selection.end, pending.clone()));
20623                this.edit(edits, cx);
20624                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20625                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20626                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20627                    }));
20628                });
20629                if let Some(existing_ranges) = existing_pending {
20630                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20631                    this.edit(edits, cx);
20632                }
20633            });
20634
20635        let snapshot = self.snapshot(window, cx);
20636        let ranges = self
20637            .selections
20638            .all::<usize>(cx)
20639            .into_iter()
20640            .map(|selection| {
20641                snapshot.buffer_snapshot.anchor_after(selection.end)
20642                    ..snapshot
20643                        .buffer_snapshot
20644                        .anchor_before(selection.end + pending.len())
20645            })
20646            .collect();
20647
20648        if pending.is_empty() {
20649            self.clear_highlights::<PendingInput>(cx);
20650        } else {
20651            self.highlight_text::<PendingInput>(
20652                ranges,
20653                HighlightStyle {
20654                    underline: Some(UnderlineStyle {
20655                        thickness: px(1.),
20656                        color: None,
20657                        wavy: false,
20658                    }),
20659                    ..Default::default()
20660                },
20661                cx,
20662            );
20663        }
20664
20665        self.ime_transaction = self.ime_transaction.or(transaction);
20666        if let Some(transaction) = self.ime_transaction {
20667            self.buffer.update(cx, |buffer, cx| {
20668                buffer.group_until_transaction(transaction, cx);
20669            });
20670        }
20671
20672        if self.text_highlights::<PendingInput>(cx).is_none() {
20673            self.ime_transaction.take();
20674        }
20675    }
20676
20677    pub fn register_action_renderer(
20678        &mut self,
20679        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20680    ) -> Subscription {
20681        let id = self.next_editor_action_id.post_inc();
20682        self.editor_actions
20683            .borrow_mut()
20684            .insert(id, Box::new(listener));
20685
20686        let editor_actions = self.editor_actions.clone();
20687        Subscription::new(move || {
20688            editor_actions.borrow_mut().remove(&id);
20689        })
20690    }
20691
20692    pub fn register_action<A: Action>(
20693        &mut self,
20694        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20695    ) -> Subscription {
20696        let id = self.next_editor_action_id.post_inc();
20697        let listener = Arc::new(listener);
20698        self.editor_actions.borrow_mut().insert(
20699            id,
20700            Box::new(move |_, window, _| {
20701                let listener = listener.clone();
20702                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20703                    let action = action.downcast_ref().unwrap();
20704                    if phase == DispatchPhase::Bubble {
20705                        listener(action, window, cx)
20706                    }
20707                })
20708            }),
20709        );
20710
20711        let editor_actions = self.editor_actions.clone();
20712        Subscription::new(move || {
20713            editor_actions.borrow_mut().remove(&id);
20714        })
20715    }
20716
20717    pub fn file_header_size(&self) -> u32 {
20718        FILE_HEADER_HEIGHT
20719    }
20720
20721    pub fn restore(
20722        &mut self,
20723        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20724        window: &mut Window,
20725        cx: &mut Context<Self>,
20726    ) {
20727        let workspace = self.workspace();
20728        let project = self.project.as_ref();
20729        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20730            let mut tasks = Vec::new();
20731            for (buffer_id, changes) in revert_changes {
20732                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20733                    buffer.update(cx, |buffer, cx| {
20734                        buffer.edit(
20735                            changes
20736                                .into_iter()
20737                                .map(|(range, text)| (range, text.to_string())),
20738                            None,
20739                            cx,
20740                        );
20741                    });
20742
20743                    if let Some(project) =
20744                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20745                    {
20746                        project.update(cx, |project, cx| {
20747                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20748                        })
20749                    }
20750                }
20751            }
20752            tasks
20753        });
20754        cx.spawn_in(window, async move |_, cx| {
20755            for (buffer, task) in save_tasks {
20756                let result = task.await;
20757                if result.is_err() {
20758                    let Some(path) = buffer
20759                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20760                        .ok()
20761                    else {
20762                        continue;
20763                    };
20764                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20765                        let Some(task) = cx
20766                            .update_window_entity(&workspace, |workspace, window, cx| {
20767                                workspace
20768                                    .open_path_preview(path, None, false, false, false, window, cx)
20769                            })
20770                            .ok()
20771                        else {
20772                            continue;
20773                        };
20774                        task.await.log_err();
20775                    }
20776                }
20777            }
20778        })
20779        .detach();
20780        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20781            selections.refresh()
20782        });
20783    }
20784
20785    pub fn to_pixel_point(
20786        &self,
20787        source: multi_buffer::Anchor,
20788        editor_snapshot: &EditorSnapshot,
20789        window: &mut Window,
20790    ) -> Option<gpui::Point<Pixels>> {
20791        let source_point = source.to_display_point(editor_snapshot);
20792        self.display_to_pixel_point(source_point, editor_snapshot, window)
20793    }
20794
20795    pub fn display_to_pixel_point(
20796        &self,
20797        source: DisplayPoint,
20798        editor_snapshot: &EditorSnapshot,
20799        window: &mut Window,
20800    ) -> Option<gpui::Point<Pixels>> {
20801        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20802        let text_layout_details = self.text_layout_details(window);
20803        let scroll_top = text_layout_details
20804            .scroll_anchor
20805            .scroll_position(editor_snapshot)
20806            .y;
20807
20808        if source.row().as_f32() < scroll_top.floor() {
20809            return None;
20810        }
20811        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20812        let source_y = line_height * (source.row().as_f32() - scroll_top);
20813        Some(gpui::Point::new(source_x, source_y))
20814    }
20815
20816    pub fn has_visible_completions_menu(&self) -> bool {
20817        !self.edit_prediction_preview_is_active()
20818            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20819                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20820            })
20821    }
20822
20823    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20824        if self.mode.is_minimap() {
20825            return;
20826        }
20827        self.addons
20828            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20829    }
20830
20831    pub fn unregister_addon<T: Addon>(&mut self) {
20832        self.addons.remove(&std::any::TypeId::of::<T>());
20833    }
20834
20835    pub fn addon<T: Addon>(&self) -> Option<&T> {
20836        let type_id = std::any::TypeId::of::<T>();
20837        self.addons
20838            .get(&type_id)
20839            .and_then(|item| item.to_any().downcast_ref::<T>())
20840    }
20841
20842    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20843        let type_id = std::any::TypeId::of::<T>();
20844        self.addons
20845            .get_mut(&type_id)
20846            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20847    }
20848
20849    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20850        let text_layout_details = self.text_layout_details(window);
20851        let style = &text_layout_details.editor_style;
20852        let font_id = window.text_system().resolve_font(&style.text.font());
20853        let font_size = style.text.font_size.to_pixels(window.rem_size());
20854        let line_height = style.text.line_height_in_pixels(window.rem_size());
20855        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20856        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20857
20858        CharacterDimensions {
20859            em_width,
20860            em_advance,
20861            line_height,
20862        }
20863    }
20864
20865    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20866        self.load_diff_task.clone()
20867    }
20868
20869    fn read_metadata_from_db(
20870        &mut self,
20871        item_id: u64,
20872        workspace_id: WorkspaceId,
20873        window: &mut Window,
20874        cx: &mut Context<Editor>,
20875    ) {
20876        if self.is_singleton(cx)
20877            && !self.mode.is_minimap()
20878            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20879        {
20880            let buffer_snapshot = OnceCell::new();
20881
20882            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20883                if !folds.is_empty() {
20884                    let snapshot =
20885                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20886                    self.fold_ranges(
20887                        folds
20888                            .into_iter()
20889                            .map(|(start, end)| {
20890                                snapshot.clip_offset(start, Bias::Left)
20891                                    ..snapshot.clip_offset(end, Bias::Right)
20892                            })
20893                            .collect(),
20894                        false,
20895                        window,
20896                        cx,
20897                    );
20898                }
20899            }
20900
20901            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20902                if !selections.is_empty() {
20903                    let snapshot =
20904                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20905                    // skip adding the initial selection to selection history
20906                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20907                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20908                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20909                            snapshot.clip_offset(start, Bias::Left)
20910                                ..snapshot.clip_offset(end, Bias::Right)
20911                        }));
20912                    });
20913                    self.selection_history.mode = SelectionHistoryMode::Normal;
20914                }
20915            };
20916        }
20917
20918        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20919    }
20920
20921    fn update_lsp_data(
20922        &mut self,
20923        ignore_cache: bool,
20924        for_buffer: Option<BufferId>,
20925        window: &mut Window,
20926        cx: &mut Context<'_, Self>,
20927    ) {
20928        self.pull_diagnostics(for_buffer, window, cx);
20929        self.refresh_colors(ignore_cache, for_buffer, window, cx);
20930    }
20931}
20932
20933fn vim_enabled(cx: &App) -> bool {
20934    cx.global::<SettingsStore>()
20935        .raw_user_settings()
20936        .get("vim_mode")
20937        == Some(&serde_json::Value::Bool(true))
20938}
20939
20940fn process_completion_for_edit(
20941    completion: &Completion,
20942    intent: CompletionIntent,
20943    buffer: &Entity<Buffer>,
20944    cursor_position: &text::Anchor,
20945    cx: &mut Context<Editor>,
20946) -> CompletionEdit {
20947    let buffer = buffer.read(cx);
20948    let buffer_snapshot = buffer.snapshot();
20949    let (snippet, new_text) = if completion.is_snippet() {
20950        // Workaround for typescript language server issues so that methods don't expand within
20951        // strings and functions with type expressions. The previous point is used because the query
20952        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20953        let mut snippet_source = completion.new_text.clone();
20954        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20955        previous_point.column = previous_point.column.saturating_sub(1);
20956        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20957            if scope.prefers_label_for_snippet_in_completion() {
20958                if let Some(label) = completion.label() {
20959                    if matches!(
20960                        completion.kind(),
20961                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20962                    ) {
20963                        snippet_source = label;
20964                    }
20965                }
20966            }
20967        }
20968        match Snippet::parse(&snippet_source).log_err() {
20969            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20970            None => (None, completion.new_text.clone()),
20971        }
20972    } else {
20973        (None, completion.new_text.clone())
20974    };
20975
20976    let mut range_to_replace = {
20977        let replace_range = &completion.replace_range;
20978        if let CompletionSource::Lsp {
20979            insert_range: Some(insert_range),
20980            ..
20981        } = &completion.source
20982        {
20983            debug_assert_eq!(
20984                insert_range.start, replace_range.start,
20985                "insert_range and replace_range should start at the same position"
20986            );
20987            debug_assert!(
20988                insert_range
20989                    .start
20990                    .cmp(&cursor_position, &buffer_snapshot)
20991                    .is_le(),
20992                "insert_range should start before or at cursor position"
20993            );
20994            debug_assert!(
20995                replace_range
20996                    .start
20997                    .cmp(&cursor_position, &buffer_snapshot)
20998                    .is_le(),
20999                "replace_range should start before or at cursor position"
21000            );
21001            debug_assert!(
21002                insert_range
21003                    .end
21004                    .cmp(&cursor_position, &buffer_snapshot)
21005                    .is_le(),
21006                "insert_range should end before or at cursor position"
21007            );
21008
21009            let should_replace = match intent {
21010                CompletionIntent::CompleteWithInsert => false,
21011                CompletionIntent::CompleteWithReplace => true,
21012                CompletionIntent::Complete | CompletionIntent::Compose => {
21013                    let insert_mode =
21014                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21015                            .completions
21016                            .lsp_insert_mode;
21017                    match insert_mode {
21018                        LspInsertMode::Insert => false,
21019                        LspInsertMode::Replace => true,
21020                        LspInsertMode::ReplaceSubsequence => {
21021                            let mut text_to_replace = buffer.chars_for_range(
21022                                buffer.anchor_before(replace_range.start)
21023                                    ..buffer.anchor_after(replace_range.end),
21024                            );
21025                            let mut current_needle = text_to_replace.next();
21026                            for haystack_ch in completion.label.text.chars() {
21027                                if let Some(needle_ch) = current_needle {
21028                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21029                                        current_needle = text_to_replace.next();
21030                                    }
21031                                }
21032                            }
21033                            current_needle.is_none()
21034                        }
21035                        LspInsertMode::ReplaceSuffix => {
21036                            if replace_range
21037                                .end
21038                                .cmp(&cursor_position, &buffer_snapshot)
21039                                .is_gt()
21040                            {
21041                                let range_after_cursor = *cursor_position..replace_range.end;
21042                                let text_after_cursor = buffer
21043                                    .text_for_range(
21044                                        buffer.anchor_before(range_after_cursor.start)
21045                                            ..buffer.anchor_after(range_after_cursor.end),
21046                                    )
21047                                    .collect::<String>()
21048                                    .to_ascii_lowercase();
21049                                completion
21050                                    .label
21051                                    .text
21052                                    .to_ascii_lowercase()
21053                                    .ends_with(&text_after_cursor)
21054                            } else {
21055                                true
21056                            }
21057                        }
21058                    }
21059                }
21060            };
21061
21062            if should_replace {
21063                replace_range.clone()
21064            } else {
21065                insert_range.clone()
21066            }
21067        } else {
21068            replace_range.clone()
21069        }
21070    };
21071
21072    if range_to_replace
21073        .end
21074        .cmp(&cursor_position, &buffer_snapshot)
21075        .is_lt()
21076    {
21077        range_to_replace.end = *cursor_position;
21078    }
21079
21080    CompletionEdit {
21081        new_text,
21082        replace_range: range_to_replace.to_offset(&buffer),
21083        snippet,
21084    }
21085}
21086
21087struct CompletionEdit {
21088    new_text: String,
21089    replace_range: Range<usize>,
21090    snippet: Option<Snippet>,
21091}
21092
21093fn insert_extra_newline_brackets(
21094    buffer: &MultiBufferSnapshot,
21095    range: Range<usize>,
21096    language: &language::LanguageScope,
21097) -> bool {
21098    let leading_whitespace_len = buffer
21099        .reversed_chars_at(range.start)
21100        .take_while(|c| c.is_whitespace() && *c != '\n')
21101        .map(|c| c.len_utf8())
21102        .sum::<usize>();
21103    let trailing_whitespace_len = buffer
21104        .chars_at(range.end)
21105        .take_while(|c| c.is_whitespace() && *c != '\n')
21106        .map(|c| c.len_utf8())
21107        .sum::<usize>();
21108    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21109
21110    language.brackets().any(|(pair, enabled)| {
21111        let pair_start = pair.start.trim_end();
21112        let pair_end = pair.end.trim_start();
21113
21114        enabled
21115            && pair.newline
21116            && buffer.contains_str_at(range.end, pair_end)
21117            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21118    })
21119}
21120
21121fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21122    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21123        [(buffer, range, _)] => (*buffer, range.clone()),
21124        _ => return false,
21125    };
21126    let pair = {
21127        let mut result: Option<BracketMatch> = None;
21128
21129        for pair in buffer
21130            .all_bracket_ranges(range.clone())
21131            .filter(move |pair| {
21132                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21133            })
21134        {
21135            let len = pair.close_range.end - pair.open_range.start;
21136
21137            if let Some(existing) = &result {
21138                let existing_len = existing.close_range.end - existing.open_range.start;
21139                if len > existing_len {
21140                    continue;
21141                }
21142            }
21143
21144            result = Some(pair);
21145        }
21146
21147        result
21148    };
21149    let Some(pair) = pair else {
21150        return false;
21151    };
21152    pair.newline_only
21153        && buffer
21154            .chars_for_range(pair.open_range.end..range.start)
21155            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21156            .all(|c| c.is_whitespace() && c != '\n')
21157}
21158
21159fn update_uncommitted_diff_for_buffer(
21160    editor: Entity<Editor>,
21161    project: &Entity<Project>,
21162    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21163    buffer: Entity<MultiBuffer>,
21164    cx: &mut App,
21165) -> Task<()> {
21166    let mut tasks = Vec::new();
21167    project.update(cx, |project, cx| {
21168        for buffer in buffers {
21169            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21170                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21171            }
21172        }
21173    });
21174    cx.spawn(async move |cx| {
21175        let diffs = future::join_all(tasks).await;
21176        if editor
21177            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21178            .unwrap_or(false)
21179        {
21180            return;
21181        }
21182
21183        buffer
21184            .update(cx, |buffer, cx| {
21185                for diff in diffs.into_iter().flatten() {
21186                    buffer.add_diff(diff, cx);
21187                }
21188            })
21189            .ok();
21190    })
21191}
21192
21193fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21194    let tab_size = tab_size.get() as usize;
21195    let mut width = offset;
21196
21197    for ch in text.chars() {
21198        width += if ch == '\t' {
21199            tab_size - (width % tab_size)
21200        } else {
21201            1
21202        };
21203    }
21204
21205    width - offset
21206}
21207
21208#[cfg(test)]
21209mod tests {
21210    use super::*;
21211
21212    #[test]
21213    fn test_string_size_with_expanded_tabs() {
21214        let nz = |val| NonZeroU32::new(val).unwrap();
21215        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21216        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21217        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21218        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21219        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21220        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21221        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21222        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21223    }
21224}
21225
21226/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21227struct WordBreakingTokenizer<'a> {
21228    input: &'a str,
21229}
21230
21231impl<'a> WordBreakingTokenizer<'a> {
21232    fn new(input: &'a str) -> Self {
21233        Self { input }
21234    }
21235}
21236
21237fn is_char_ideographic(ch: char) -> bool {
21238    use unicode_script::Script::*;
21239    use unicode_script::UnicodeScript;
21240    matches!(ch.script(), Han | Tangut | Yi)
21241}
21242
21243fn is_grapheme_ideographic(text: &str) -> bool {
21244    text.chars().any(is_char_ideographic)
21245}
21246
21247fn is_grapheme_whitespace(text: &str) -> bool {
21248    text.chars().any(|x| x.is_whitespace())
21249}
21250
21251fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21252    text.chars().next().map_or(false, |ch| {
21253        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21254    })
21255}
21256
21257#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21258enum WordBreakToken<'a> {
21259    Word { token: &'a str, grapheme_len: usize },
21260    InlineWhitespace { token: &'a str, grapheme_len: usize },
21261    Newline,
21262}
21263
21264impl<'a> Iterator for WordBreakingTokenizer<'a> {
21265    /// Yields a span, the count of graphemes in the token, and whether it was
21266    /// whitespace. Note that it also breaks at word boundaries.
21267    type Item = WordBreakToken<'a>;
21268
21269    fn next(&mut self) -> Option<Self::Item> {
21270        use unicode_segmentation::UnicodeSegmentation;
21271        if self.input.is_empty() {
21272            return None;
21273        }
21274
21275        let mut iter = self.input.graphemes(true).peekable();
21276        let mut offset = 0;
21277        let mut grapheme_len = 0;
21278        if let Some(first_grapheme) = iter.next() {
21279            let is_newline = first_grapheme == "\n";
21280            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21281            offset += first_grapheme.len();
21282            grapheme_len += 1;
21283            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21284                if let Some(grapheme) = iter.peek().copied() {
21285                    if should_stay_with_preceding_ideograph(grapheme) {
21286                        offset += grapheme.len();
21287                        grapheme_len += 1;
21288                    }
21289                }
21290            } else {
21291                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21292                let mut next_word_bound = words.peek().copied();
21293                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21294                    next_word_bound = words.next();
21295                }
21296                while let Some(grapheme) = iter.peek().copied() {
21297                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21298                        break;
21299                    };
21300                    if is_grapheme_whitespace(grapheme) != is_whitespace
21301                        || (grapheme == "\n") != is_newline
21302                    {
21303                        break;
21304                    };
21305                    offset += grapheme.len();
21306                    grapheme_len += 1;
21307                    iter.next();
21308                }
21309            }
21310            let token = &self.input[..offset];
21311            self.input = &self.input[offset..];
21312            if token == "\n" {
21313                Some(WordBreakToken::Newline)
21314            } else if is_whitespace {
21315                Some(WordBreakToken::InlineWhitespace {
21316                    token,
21317                    grapheme_len,
21318                })
21319            } else {
21320                Some(WordBreakToken::Word {
21321                    token,
21322                    grapheme_len,
21323                })
21324            }
21325        } else {
21326            None
21327        }
21328    }
21329}
21330
21331#[test]
21332fn test_word_breaking_tokenizer() {
21333    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21334        ("", &[]),
21335        ("  ", &[whitespace("  ", 2)]),
21336        ("Ʒ", &[word("Ʒ", 1)]),
21337        ("Ǽ", &[word("Ǽ", 1)]),
21338        ("", &[word("", 1)]),
21339        ("⋑⋑", &[word("⋑⋑", 2)]),
21340        (
21341            "原理,进而",
21342            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21343        ),
21344        (
21345            "hello world",
21346            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21347        ),
21348        (
21349            "hello, world",
21350            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21351        ),
21352        (
21353            "  hello world",
21354            &[
21355                whitespace("  ", 2),
21356                word("hello", 5),
21357                whitespace(" ", 1),
21358                word("world", 5),
21359            ],
21360        ),
21361        (
21362            "这是什么 \n 钢笔",
21363            &[
21364                word("", 1),
21365                word("", 1),
21366                word("", 1),
21367                word("", 1),
21368                whitespace(" ", 1),
21369                newline(),
21370                whitespace(" ", 1),
21371                word("", 1),
21372                word("", 1),
21373            ],
21374        ),
21375        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21376    ];
21377
21378    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21379        WordBreakToken::Word {
21380            token,
21381            grapheme_len,
21382        }
21383    }
21384
21385    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21386        WordBreakToken::InlineWhitespace {
21387            token,
21388            grapheme_len,
21389        }
21390    }
21391
21392    fn newline() -> WordBreakToken<'static> {
21393        WordBreakToken::Newline
21394    }
21395
21396    for (input, result) in tests {
21397        assert_eq!(
21398            WordBreakingTokenizer::new(input)
21399                .collect::<Vec<_>>()
21400                .as_slice(),
21401            *result,
21402        );
21403    }
21404}
21405
21406fn wrap_with_prefix(
21407    first_line_prefix: String,
21408    subsequent_lines_prefix: String,
21409    unwrapped_text: String,
21410    wrap_column: usize,
21411    tab_size: NonZeroU32,
21412    preserve_existing_whitespace: bool,
21413) -> String {
21414    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21415    let subsequent_lines_prefix_len =
21416        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21417    let mut wrapped_text = String::new();
21418    let mut current_line = first_line_prefix.clone();
21419    let mut is_first_line = true;
21420
21421    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21422    let mut current_line_len = first_line_prefix_len;
21423    let mut in_whitespace = false;
21424    for token in tokenizer {
21425        let have_preceding_whitespace = in_whitespace;
21426        match token {
21427            WordBreakToken::Word {
21428                token,
21429                grapheme_len,
21430            } => {
21431                in_whitespace = false;
21432                let current_prefix_len = if is_first_line {
21433                    first_line_prefix_len
21434                } else {
21435                    subsequent_lines_prefix_len
21436                };
21437                if current_line_len + grapheme_len > wrap_column
21438                    && current_line_len != current_prefix_len
21439                {
21440                    wrapped_text.push_str(current_line.trim_end());
21441                    wrapped_text.push('\n');
21442                    is_first_line = false;
21443                    current_line = subsequent_lines_prefix.clone();
21444                    current_line_len = subsequent_lines_prefix_len;
21445                }
21446                current_line.push_str(token);
21447                current_line_len += grapheme_len;
21448            }
21449            WordBreakToken::InlineWhitespace {
21450                mut token,
21451                mut grapheme_len,
21452            } => {
21453                in_whitespace = true;
21454                if have_preceding_whitespace && !preserve_existing_whitespace {
21455                    continue;
21456                }
21457                if !preserve_existing_whitespace {
21458                    token = " ";
21459                    grapheme_len = 1;
21460                }
21461                let current_prefix_len = if is_first_line {
21462                    first_line_prefix_len
21463                } else {
21464                    subsequent_lines_prefix_len
21465                };
21466                if current_line_len + grapheme_len > wrap_column {
21467                    wrapped_text.push_str(current_line.trim_end());
21468                    wrapped_text.push('\n');
21469                    is_first_line = false;
21470                    current_line = subsequent_lines_prefix.clone();
21471                    current_line_len = subsequent_lines_prefix_len;
21472                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21473                    current_line.push_str(token);
21474                    current_line_len += grapheme_len;
21475                }
21476            }
21477            WordBreakToken::Newline => {
21478                in_whitespace = true;
21479                let current_prefix_len = if is_first_line {
21480                    first_line_prefix_len
21481                } else {
21482                    subsequent_lines_prefix_len
21483                };
21484                if preserve_existing_whitespace {
21485                    wrapped_text.push_str(current_line.trim_end());
21486                    wrapped_text.push('\n');
21487                    is_first_line = false;
21488                    current_line = subsequent_lines_prefix.clone();
21489                    current_line_len = subsequent_lines_prefix_len;
21490                } else if have_preceding_whitespace {
21491                    continue;
21492                } else if current_line_len + 1 > wrap_column
21493                    && current_line_len != current_prefix_len
21494                {
21495                    wrapped_text.push_str(current_line.trim_end());
21496                    wrapped_text.push('\n');
21497                    is_first_line = false;
21498                    current_line = subsequent_lines_prefix.clone();
21499                    current_line_len = subsequent_lines_prefix_len;
21500                } else if current_line_len != current_prefix_len {
21501                    current_line.push(' ');
21502                    current_line_len += 1;
21503                }
21504            }
21505        }
21506    }
21507
21508    if !current_line.is_empty() {
21509        wrapped_text.push_str(&current_line);
21510    }
21511    wrapped_text
21512}
21513
21514#[test]
21515fn test_wrap_with_prefix() {
21516    assert_eq!(
21517        wrap_with_prefix(
21518            "# ".to_string(),
21519            "# ".to_string(),
21520            "abcdefg".to_string(),
21521            4,
21522            NonZeroU32::new(4).unwrap(),
21523            false,
21524        ),
21525        "# abcdefg"
21526    );
21527    assert_eq!(
21528        wrap_with_prefix(
21529            "".to_string(),
21530            "".to_string(),
21531            "\thello world".to_string(),
21532            8,
21533            NonZeroU32::new(4).unwrap(),
21534            false,
21535        ),
21536        "hello\nworld"
21537    );
21538    assert_eq!(
21539        wrap_with_prefix(
21540            "// ".to_string(),
21541            "// ".to_string(),
21542            "xx \nyy zz aa bb cc".to_string(),
21543            12,
21544            NonZeroU32::new(4).unwrap(),
21545            false,
21546        ),
21547        "// xx yy zz\n// aa bb cc"
21548    );
21549    assert_eq!(
21550        wrap_with_prefix(
21551            String::new(),
21552            String::new(),
21553            "这是什么 \n 钢笔".to_string(),
21554            3,
21555            NonZeroU32::new(4).unwrap(),
21556            false,
21557        ),
21558        "这是什\n么 钢\n"
21559    );
21560}
21561
21562pub trait CollaborationHub {
21563    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21564    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21565    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21566}
21567
21568impl CollaborationHub for Entity<Project> {
21569    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21570        self.read(cx).collaborators()
21571    }
21572
21573    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21574        self.read(cx).user_store().read(cx).participant_indices()
21575    }
21576
21577    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21578        let this = self.read(cx);
21579        let user_ids = this.collaborators().values().map(|c| c.user_id);
21580        this.user_store().read(cx).participant_names(user_ids, cx)
21581    }
21582}
21583
21584pub trait SemanticsProvider {
21585    fn hover(
21586        &self,
21587        buffer: &Entity<Buffer>,
21588        position: text::Anchor,
21589        cx: &mut App,
21590    ) -> Option<Task<Vec<project::Hover>>>;
21591
21592    fn inline_values(
21593        &self,
21594        buffer_handle: Entity<Buffer>,
21595        range: Range<text::Anchor>,
21596        cx: &mut App,
21597    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21598
21599    fn inlay_hints(
21600        &self,
21601        buffer_handle: Entity<Buffer>,
21602        range: Range<text::Anchor>,
21603        cx: &mut App,
21604    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21605
21606    fn resolve_inlay_hint(
21607        &self,
21608        hint: InlayHint,
21609        buffer_handle: Entity<Buffer>,
21610        server_id: LanguageServerId,
21611        cx: &mut App,
21612    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21613
21614    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21615
21616    fn document_highlights(
21617        &self,
21618        buffer: &Entity<Buffer>,
21619        position: text::Anchor,
21620        cx: &mut App,
21621    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21622
21623    fn definitions(
21624        &self,
21625        buffer: &Entity<Buffer>,
21626        position: text::Anchor,
21627        kind: GotoDefinitionKind,
21628        cx: &mut App,
21629    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21630
21631    fn range_for_rename(
21632        &self,
21633        buffer: &Entity<Buffer>,
21634        position: text::Anchor,
21635        cx: &mut App,
21636    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21637
21638    fn perform_rename(
21639        &self,
21640        buffer: &Entity<Buffer>,
21641        position: text::Anchor,
21642        new_name: String,
21643        cx: &mut App,
21644    ) -> Option<Task<Result<ProjectTransaction>>>;
21645}
21646
21647pub trait CompletionProvider {
21648    fn completions(
21649        &self,
21650        excerpt_id: ExcerptId,
21651        buffer: &Entity<Buffer>,
21652        buffer_position: text::Anchor,
21653        trigger: CompletionContext,
21654        window: &mut Window,
21655        cx: &mut Context<Editor>,
21656    ) -> Task<Result<Vec<CompletionResponse>>>;
21657
21658    fn resolve_completions(
21659        &self,
21660        _buffer: Entity<Buffer>,
21661        _completion_indices: Vec<usize>,
21662        _completions: Rc<RefCell<Box<[Completion]>>>,
21663        _cx: &mut Context<Editor>,
21664    ) -> Task<Result<bool>> {
21665        Task::ready(Ok(false))
21666    }
21667
21668    fn apply_additional_edits_for_completion(
21669        &self,
21670        _buffer: Entity<Buffer>,
21671        _completions: Rc<RefCell<Box<[Completion]>>>,
21672        _completion_index: usize,
21673        _push_to_history: bool,
21674        _cx: &mut Context<Editor>,
21675    ) -> Task<Result<Option<language::Transaction>>> {
21676        Task::ready(Ok(None))
21677    }
21678
21679    fn is_completion_trigger(
21680        &self,
21681        buffer: &Entity<Buffer>,
21682        position: language::Anchor,
21683        text: &str,
21684        trigger_in_words: bool,
21685        menu_is_open: bool,
21686        cx: &mut Context<Editor>,
21687    ) -> bool;
21688
21689    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21690
21691    fn sort_completions(&self) -> bool {
21692        true
21693    }
21694
21695    fn filter_completions(&self) -> bool {
21696        true
21697    }
21698}
21699
21700pub trait CodeActionProvider {
21701    fn id(&self) -> Arc<str>;
21702
21703    fn code_actions(
21704        &self,
21705        buffer: &Entity<Buffer>,
21706        range: Range<text::Anchor>,
21707        window: &mut Window,
21708        cx: &mut App,
21709    ) -> Task<Result<Vec<CodeAction>>>;
21710
21711    fn apply_code_action(
21712        &self,
21713        buffer_handle: Entity<Buffer>,
21714        action: CodeAction,
21715        excerpt_id: ExcerptId,
21716        push_to_history: bool,
21717        window: &mut Window,
21718        cx: &mut App,
21719    ) -> Task<Result<ProjectTransaction>>;
21720}
21721
21722impl CodeActionProvider for Entity<Project> {
21723    fn id(&self) -> Arc<str> {
21724        "project".into()
21725    }
21726
21727    fn code_actions(
21728        &self,
21729        buffer: &Entity<Buffer>,
21730        range: Range<text::Anchor>,
21731        _window: &mut Window,
21732        cx: &mut App,
21733    ) -> Task<Result<Vec<CodeAction>>> {
21734        self.update(cx, |project, cx| {
21735            let code_lens = project.code_lens(buffer, range.clone(), cx);
21736            let code_actions = project.code_actions(buffer, range, None, cx);
21737            cx.background_spawn(async move {
21738                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21739                Ok(code_lens
21740                    .context("code lens fetch")?
21741                    .into_iter()
21742                    .chain(code_actions.context("code action fetch")?)
21743                    .collect())
21744            })
21745        })
21746    }
21747
21748    fn apply_code_action(
21749        &self,
21750        buffer_handle: Entity<Buffer>,
21751        action: CodeAction,
21752        _excerpt_id: ExcerptId,
21753        push_to_history: bool,
21754        _window: &mut Window,
21755        cx: &mut App,
21756    ) -> Task<Result<ProjectTransaction>> {
21757        self.update(cx, |project, cx| {
21758            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21759        })
21760    }
21761}
21762
21763fn snippet_completions(
21764    project: &Project,
21765    buffer: &Entity<Buffer>,
21766    buffer_position: text::Anchor,
21767    cx: &mut App,
21768) -> Task<Result<CompletionResponse>> {
21769    let languages = buffer.read(cx).languages_at(buffer_position);
21770    let snippet_store = project.snippets().read(cx);
21771
21772    let scopes: Vec<_> = languages
21773        .iter()
21774        .filter_map(|language| {
21775            let language_name = language.lsp_id();
21776            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21777
21778            if snippets.is_empty() {
21779                None
21780            } else {
21781                Some((language.default_scope(), snippets))
21782            }
21783        })
21784        .collect();
21785
21786    if scopes.is_empty() {
21787        return Task::ready(Ok(CompletionResponse {
21788            completions: vec![],
21789            is_incomplete: false,
21790        }));
21791    }
21792
21793    let snapshot = buffer.read(cx).text_snapshot();
21794    let chars: String = snapshot
21795        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21796        .collect();
21797    let executor = cx.background_executor().clone();
21798
21799    cx.background_spawn(async move {
21800        let mut is_incomplete = false;
21801        let mut completions: Vec<Completion> = Vec::new();
21802        for (scope, snippets) in scopes.into_iter() {
21803            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21804            let mut last_word = chars
21805                .chars()
21806                .take_while(|c| classifier.is_word(*c))
21807                .collect::<String>();
21808            last_word = last_word.chars().rev().collect();
21809
21810            if last_word.is_empty() {
21811                return Ok(CompletionResponse {
21812                    completions: vec![],
21813                    is_incomplete: true,
21814                });
21815            }
21816
21817            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21818            let to_lsp = |point: &text::Anchor| {
21819                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21820                point_to_lsp(end)
21821            };
21822            let lsp_end = to_lsp(&buffer_position);
21823
21824            let candidates = snippets
21825                .iter()
21826                .enumerate()
21827                .flat_map(|(ix, snippet)| {
21828                    snippet
21829                        .prefix
21830                        .iter()
21831                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21832                })
21833                .collect::<Vec<StringMatchCandidate>>();
21834
21835            const MAX_RESULTS: usize = 100;
21836            let mut matches = fuzzy::match_strings(
21837                &candidates,
21838                &last_word,
21839                last_word.chars().any(|c| c.is_uppercase()),
21840                true,
21841                MAX_RESULTS,
21842                &Default::default(),
21843                executor.clone(),
21844            )
21845            .await;
21846
21847            if matches.len() >= MAX_RESULTS {
21848                is_incomplete = true;
21849            }
21850
21851            // Remove all candidates where the query's start does not match the start of any word in the candidate
21852            if let Some(query_start) = last_word.chars().next() {
21853                matches.retain(|string_match| {
21854                    split_words(&string_match.string).any(|word| {
21855                        // Check that the first codepoint of the word as lowercase matches the first
21856                        // codepoint of the query as lowercase
21857                        word.chars()
21858                            .flat_map(|codepoint| codepoint.to_lowercase())
21859                            .zip(query_start.to_lowercase())
21860                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21861                    })
21862                });
21863            }
21864
21865            let matched_strings = matches
21866                .into_iter()
21867                .map(|m| m.string)
21868                .collect::<HashSet<_>>();
21869
21870            completions.extend(snippets.iter().filter_map(|snippet| {
21871                let matching_prefix = snippet
21872                    .prefix
21873                    .iter()
21874                    .find(|prefix| matched_strings.contains(*prefix))?;
21875                let start = as_offset - last_word.len();
21876                let start = snapshot.anchor_before(start);
21877                let range = start..buffer_position;
21878                let lsp_start = to_lsp(&start);
21879                let lsp_range = lsp::Range {
21880                    start: lsp_start,
21881                    end: lsp_end,
21882                };
21883                Some(Completion {
21884                    replace_range: range,
21885                    new_text: snippet.body.clone(),
21886                    source: CompletionSource::Lsp {
21887                        insert_range: None,
21888                        server_id: LanguageServerId(usize::MAX),
21889                        resolved: true,
21890                        lsp_completion: Box::new(lsp::CompletionItem {
21891                            label: snippet.prefix.first().unwrap().clone(),
21892                            kind: Some(CompletionItemKind::SNIPPET),
21893                            label_details: snippet.description.as_ref().map(|description| {
21894                                lsp::CompletionItemLabelDetails {
21895                                    detail: Some(description.clone()),
21896                                    description: None,
21897                                }
21898                            }),
21899                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21900                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21901                                lsp::InsertReplaceEdit {
21902                                    new_text: snippet.body.clone(),
21903                                    insert: lsp_range,
21904                                    replace: lsp_range,
21905                                },
21906                            )),
21907                            filter_text: Some(snippet.body.clone()),
21908                            sort_text: Some(char::MAX.to_string()),
21909                            ..lsp::CompletionItem::default()
21910                        }),
21911                        lsp_defaults: None,
21912                    },
21913                    label: CodeLabel {
21914                        text: matching_prefix.clone(),
21915                        runs: Vec::new(),
21916                        filter_range: 0..matching_prefix.len(),
21917                    },
21918                    icon_path: None,
21919                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21920                        single_line: snippet.name.clone().into(),
21921                        plain_text: snippet
21922                            .description
21923                            .clone()
21924                            .map(|description| description.into()),
21925                    }),
21926                    insert_text_mode: None,
21927                    confirm: None,
21928                })
21929            }))
21930        }
21931
21932        Ok(CompletionResponse {
21933            completions,
21934            is_incomplete,
21935        })
21936    })
21937}
21938
21939impl CompletionProvider for Entity<Project> {
21940    fn completions(
21941        &self,
21942        _excerpt_id: ExcerptId,
21943        buffer: &Entity<Buffer>,
21944        buffer_position: text::Anchor,
21945        options: CompletionContext,
21946        _window: &mut Window,
21947        cx: &mut Context<Editor>,
21948    ) -> Task<Result<Vec<CompletionResponse>>> {
21949        self.update(cx, |project, cx| {
21950            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21951            let project_completions = project.completions(buffer, buffer_position, options, cx);
21952            cx.background_spawn(async move {
21953                let mut responses = project_completions.await?;
21954                let snippets = snippets.await?;
21955                if !snippets.completions.is_empty() {
21956                    responses.push(snippets);
21957                }
21958                Ok(responses)
21959            })
21960        })
21961    }
21962
21963    fn resolve_completions(
21964        &self,
21965        buffer: Entity<Buffer>,
21966        completion_indices: Vec<usize>,
21967        completions: Rc<RefCell<Box<[Completion]>>>,
21968        cx: &mut Context<Editor>,
21969    ) -> Task<Result<bool>> {
21970        self.update(cx, |project, cx| {
21971            project.lsp_store().update(cx, |lsp_store, cx| {
21972                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21973            })
21974        })
21975    }
21976
21977    fn apply_additional_edits_for_completion(
21978        &self,
21979        buffer: Entity<Buffer>,
21980        completions: Rc<RefCell<Box<[Completion]>>>,
21981        completion_index: usize,
21982        push_to_history: bool,
21983        cx: &mut Context<Editor>,
21984    ) -> Task<Result<Option<language::Transaction>>> {
21985        self.update(cx, |project, cx| {
21986            project.lsp_store().update(cx, |lsp_store, cx| {
21987                lsp_store.apply_additional_edits_for_completion(
21988                    buffer,
21989                    completions,
21990                    completion_index,
21991                    push_to_history,
21992                    cx,
21993                )
21994            })
21995        })
21996    }
21997
21998    fn is_completion_trigger(
21999        &self,
22000        buffer: &Entity<Buffer>,
22001        position: language::Anchor,
22002        text: &str,
22003        trigger_in_words: bool,
22004        menu_is_open: bool,
22005        cx: &mut Context<Editor>,
22006    ) -> bool {
22007        let mut chars = text.chars();
22008        let char = if let Some(char) = chars.next() {
22009            char
22010        } else {
22011            return false;
22012        };
22013        if chars.next().is_some() {
22014            return false;
22015        }
22016
22017        let buffer = buffer.read(cx);
22018        let snapshot = buffer.snapshot();
22019        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22020            return false;
22021        }
22022        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22023        if trigger_in_words && classifier.is_word(char) {
22024            return true;
22025        }
22026
22027        buffer.completion_triggers().contains(text)
22028    }
22029}
22030
22031impl SemanticsProvider for Entity<Project> {
22032    fn hover(
22033        &self,
22034        buffer: &Entity<Buffer>,
22035        position: text::Anchor,
22036        cx: &mut App,
22037    ) -> Option<Task<Vec<project::Hover>>> {
22038        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22039    }
22040
22041    fn document_highlights(
22042        &self,
22043        buffer: &Entity<Buffer>,
22044        position: text::Anchor,
22045        cx: &mut App,
22046    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22047        Some(self.update(cx, |project, cx| {
22048            project.document_highlights(buffer, position, cx)
22049        }))
22050    }
22051
22052    fn definitions(
22053        &self,
22054        buffer: &Entity<Buffer>,
22055        position: text::Anchor,
22056        kind: GotoDefinitionKind,
22057        cx: &mut App,
22058    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22059        Some(self.update(cx, |project, cx| match kind {
22060            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22061            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22062            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22063            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22064        }))
22065    }
22066
22067    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22068        // TODO: make this work for remote projects
22069        self.update(cx, |project, cx| {
22070            if project
22071                .active_debug_session(cx)
22072                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22073            {
22074                return true;
22075            }
22076
22077            buffer.update(cx, |buffer, cx| {
22078                project.any_language_server_supports_inlay_hints(buffer, cx)
22079            })
22080        })
22081    }
22082
22083    fn inline_values(
22084        &self,
22085        buffer_handle: Entity<Buffer>,
22086        range: Range<text::Anchor>,
22087        cx: &mut App,
22088    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22089        self.update(cx, |project, cx| {
22090            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22091
22092            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22093        })
22094    }
22095
22096    fn inlay_hints(
22097        &self,
22098        buffer_handle: Entity<Buffer>,
22099        range: Range<text::Anchor>,
22100        cx: &mut App,
22101    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22102        Some(self.update(cx, |project, cx| {
22103            project.inlay_hints(buffer_handle, range, cx)
22104        }))
22105    }
22106
22107    fn resolve_inlay_hint(
22108        &self,
22109        hint: InlayHint,
22110        buffer_handle: Entity<Buffer>,
22111        server_id: LanguageServerId,
22112        cx: &mut App,
22113    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22114        Some(self.update(cx, |project, cx| {
22115            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22116        }))
22117    }
22118
22119    fn range_for_rename(
22120        &self,
22121        buffer: &Entity<Buffer>,
22122        position: text::Anchor,
22123        cx: &mut App,
22124    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22125        Some(self.update(cx, |project, cx| {
22126            let buffer = buffer.clone();
22127            let task = project.prepare_rename(buffer.clone(), position, cx);
22128            cx.spawn(async move |_, cx| {
22129                Ok(match task.await? {
22130                    PrepareRenameResponse::Success(range) => Some(range),
22131                    PrepareRenameResponse::InvalidPosition => None,
22132                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22133                        // Fallback on using TreeSitter info to determine identifier range
22134                        buffer.read_with(cx, |buffer, _| {
22135                            let snapshot = buffer.snapshot();
22136                            let (range, kind) = snapshot.surrounding_word(position);
22137                            if kind != Some(CharKind::Word) {
22138                                return None;
22139                            }
22140                            Some(
22141                                snapshot.anchor_before(range.start)
22142                                    ..snapshot.anchor_after(range.end),
22143                            )
22144                        })?
22145                    }
22146                })
22147            })
22148        }))
22149    }
22150
22151    fn perform_rename(
22152        &self,
22153        buffer: &Entity<Buffer>,
22154        position: text::Anchor,
22155        new_name: String,
22156        cx: &mut App,
22157    ) -> Option<Task<Result<ProjectTransaction>>> {
22158        Some(self.update(cx, |project, cx| {
22159            project.perform_rename(buffer.clone(), position, new_name, cx)
22160        }))
22161    }
22162}
22163
22164fn inlay_hint_settings(
22165    location: Anchor,
22166    snapshot: &MultiBufferSnapshot,
22167    cx: &mut Context<Editor>,
22168) -> InlayHintSettings {
22169    let file = snapshot.file_at(location);
22170    let language = snapshot.language_at(location).map(|l| l.name());
22171    language_settings(language, file, cx).inlay_hints
22172}
22173
22174fn consume_contiguous_rows(
22175    contiguous_row_selections: &mut Vec<Selection<Point>>,
22176    selection: &Selection<Point>,
22177    display_map: &DisplaySnapshot,
22178    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22179) -> (MultiBufferRow, MultiBufferRow) {
22180    contiguous_row_selections.push(selection.clone());
22181    let start_row = MultiBufferRow(selection.start.row);
22182    let mut end_row = ending_row(selection, display_map);
22183
22184    while let Some(next_selection) = selections.peek() {
22185        if next_selection.start.row <= end_row.0 {
22186            end_row = ending_row(next_selection, display_map);
22187            contiguous_row_selections.push(selections.next().unwrap().clone());
22188        } else {
22189            break;
22190        }
22191    }
22192    (start_row, end_row)
22193}
22194
22195fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22196    if next_selection.end.column > 0 || next_selection.is_empty() {
22197        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22198    } else {
22199        MultiBufferRow(next_selection.end.row)
22200    }
22201}
22202
22203impl EditorSnapshot {
22204    pub fn remote_selections_in_range<'a>(
22205        &'a self,
22206        range: &'a Range<Anchor>,
22207        collaboration_hub: &dyn CollaborationHub,
22208        cx: &'a App,
22209    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22210        let participant_names = collaboration_hub.user_names(cx);
22211        let participant_indices = collaboration_hub.user_participant_indices(cx);
22212        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22213        let collaborators_by_replica_id = collaborators_by_peer_id
22214            .values()
22215            .map(|collaborator| (collaborator.replica_id, collaborator))
22216            .collect::<HashMap<_, _>>();
22217        self.buffer_snapshot
22218            .selections_in_range(range, false)
22219            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22220                if replica_id == AGENT_REPLICA_ID {
22221                    Some(RemoteSelection {
22222                        replica_id,
22223                        selection,
22224                        cursor_shape,
22225                        line_mode,
22226                        collaborator_id: CollaboratorId::Agent,
22227                        user_name: Some("Agent".into()),
22228                        color: cx.theme().players().agent(),
22229                    })
22230                } else {
22231                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22232                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22233                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22234                    Some(RemoteSelection {
22235                        replica_id,
22236                        selection,
22237                        cursor_shape,
22238                        line_mode,
22239                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22240                        user_name,
22241                        color: if let Some(index) = participant_index {
22242                            cx.theme().players().color_for_participant(index.0)
22243                        } else {
22244                            cx.theme().players().absent()
22245                        },
22246                    })
22247                }
22248            })
22249    }
22250
22251    pub fn hunks_for_ranges(
22252        &self,
22253        ranges: impl IntoIterator<Item = Range<Point>>,
22254    ) -> Vec<MultiBufferDiffHunk> {
22255        let mut hunks = Vec::new();
22256        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22257            HashMap::default();
22258        for query_range in ranges {
22259            let query_rows =
22260                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22261            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22262                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22263            ) {
22264                // Include deleted hunks that are adjacent to the query range, because
22265                // otherwise they would be missed.
22266                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22267                if hunk.status().is_deleted() {
22268                    intersects_range |= hunk.row_range.start == query_rows.end;
22269                    intersects_range |= hunk.row_range.end == query_rows.start;
22270                }
22271                if intersects_range {
22272                    if !processed_buffer_rows
22273                        .entry(hunk.buffer_id)
22274                        .or_default()
22275                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22276                    {
22277                        continue;
22278                    }
22279                    hunks.push(hunk);
22280                }
22281            }
22282        }
22283
22284        hunks
22285    }
22286
22287    fn display_diff_hunks_for_rows<'a>(
22288        &'a self,
22289        display_rows: Range<DisplayRow>,
22290        folded_buffers: &'a HashSet<BufferId>,
22291    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22292        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22293        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22294
22295        self.buffer_snapshot
22296            .diff_hunks_in_range(buffer_start..buffer_end)
22297            .filter_map(|hunk| {
22298                if folded_buffers.contains(&hunk.buffer_id) {
22299                    return None;
22300                }
22301
22302                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22303                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22304
22305                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22306                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22307
22308                let display_hunk = if hunk_display_start.column() != 0 {
22309                    DisplayDiffHunk::Folded {
22310                        display_row: hunk_display_start.row(),
22311                    }
22312                } else {
22313                    let mut end_row = hunk_display_end.row();
22314                    if hunk_display_end.column() > 0 {
22315                        end_row.0 += 1;
22316                    }
22317                    let is_created_file = hunk.is_created_file();
22318                    DisplayDiffHunk::Unfolded {
22319                        status: hunk.status(),
22320                        diff_base_byte_range: hunk.diff_base_byte_range,
22321                        display_row_range: hunk_display_start.row()..end_row,
22322                        multi_buffer_range: Anchor::range_in_buffer(
22323                            hunk.excerpt_id,
22324                            hunk.buffer_id,
22325                            hunk.buffer_range,
22326                        ),
22327                        is_created_file,
22328                    }
22329                };
22330
22331                Some(display_hunk)
22332            })
22333    }
22334
22335    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22336        self.display_snapshot.buffer_snapshot.language_at(position)
22337    }
22338
22339    pub fn is_focused(&self) -> bool {
22340        self.is_focused
22341    }
22342
22343    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22344        self.placeholder_text.as_ref()
22345    }
22346
22347    pub fn scroll_position(&self) -> gpui::Point<f32> {
22348        self.scroll_anchor.scroll_position(&self.display_snapshot)
22349    }
22350
22351    fn gutter_dimensions(
22352        &self,
22353        font_id: FontId,
22354        font_size: Pixels,
22355        max_line_number_width: Pixels,
22356        cx: &App,
22357    ) -> Option<GutterDimensions> {
22358        if !self.show_gutter {
22359            return None;
22360        }
22361
22362        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22363        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22364
22365        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22366            matches!(
22367                ProjectSettings::get_global(cx).git.git_gutter,
22368                Some(GitGutterSetting::TrackedFiles)
22369            )
22370        });
22371        let gutter_settings = EditorSettings::get_global(cx).gutter;
22372        let show_line_numbers = self
22373            .show_line_numbers
22374            .unwrap_or(gutter_settings.line_numbers);
22375        let line_gutter_width = if show_line_numbers {
22376            // Avoid flicker-like gutter resizes when the line number gains another digit by
22377            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22378            let min_width_for_number_on_gutter =
22379                ch_advance * gutter_settings.min_line_number_digits as f32;
22380            max_line_number_width.max(min_width_for_number_on_gutter)
22381        } else {
22382            0.0.into()
22383        };
22384
22385        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22386        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22387
22388        let git_blame_entries_width =
22389            self.git_blame_gutter_max_author_length
22390                .map(|max_author_length| {
22391                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22392                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22393
22394                    /// The number of characters to dedicate to gaps and margins.
22395                    const SPACING_WIDTH: usize = 4;
22396
22397                    let max_char_count = max_author_length.min(renderer.max_author_length())
22398                        + ::git::SHORT_SHA_LENGTH
22399                        + MAX_RELATIVE_TIMESTAMP.len()
22400                        + SPACING_WIDTH;
22401
22402                    ch_advance * max_char_count
22403                });
22404
22405        let is_singleton = self.buffer_snapshot.is_singleton();
22406
22407        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22408        left_padding += if !is_singleton {
22409            ch_width * 4.0
22410        } else if show_runnables || show_breakpoints {
22411            ch_width * 3.0
22412        } else if show_git_gutter && show_line_numbers {
22413            ch_width * 2.0
22414        } else if show_git_gutter || show_line_numbers {
22415            ch_width
22416        } else {
22417            px(0.)
22418        };
22419
22420        let shows_folds = is_singleton && gutter_settings.folds;
22421
22422        let right_padding = if shows_folds && show_line_numbers {
22423            ch_width * 4.0
22424        } else if shows_folds || (!is_singleton && show_line_numbers) {
22425            ch_width * 3.0
22426        } else if show_line_numbers {
22427            ch_width
22428        } else {
22429            px(0.)
22430        };
22431
22432        Some(GutterDimensions {
22433            left_padding,
22434            right_padding,
22435            width: line_gutter_width + left_padding + right_padding,
22436            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22437            git_blame_entries_width,
22438        })
22439    }
22440
22441    pub fn render_crease_toggle(
22442        &self,
22443        buffer_row: MultiBufferRow,
22444        row_contains_cursor: bool,
22445        editor: Entity<Editor>,
22446        window: &mut Window,
22447        cx: &mut App,
22448    ) -> Option<AnyElement> {
22449        let folded = self.is_line_folded(buffer_row);
22450        let mut is_foldable = false;
22451
22452        if let Some(crease) = self
22453            .crease_snapshot
22454            .query_row(buffer_row, &self.buffer_snapshot)
22455        {
22456            is_foldable = true;
22457            match crease {
22458                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22459                    if let Some(render_toggle) = render_toggle {
22460                        let toggle_callback =
22461                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22462                                if folded {
22463                                    editor.update(cx, |editor, cx| {
22464                                        editor.fold_at(buffer_row, window, cx)
22465                                    });
22466                                } else {
22467                                    editor.update(cx, |editor, cx| {
22468                                        editor.unfold_at(buffer_row, window, cx)
22469                                    });
22470                                }
22471                            });
22472                        return Some((render_toggle)(
22473                            buffer_row,
22474                            folded,
22475                            toggle_callback,
22476                            window,
22477                            cx,
22478                        ));
22479                    }
22480                }
22481            }
22482        }
22483
22484        is_foldable |= self.starts_indent(buffer_row);
22485
22486        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22487            Some(
22488                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22489                    .toggle_state(folded)
22490                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22491                        if folded {
22492                            this.unfold_at(buffer_row, window, cx);
22493                        } else {
22494                            this.fold_at(buffer_row, window, cx);
22495                        }
22496                    }))
22497                    .into_any_element(),
22498            )
22499        } else {
22500            None
22501        }
22502    }
22503
22504    pub fn render_crease_trailer(
22505        &self,
22506        buffer_row: MultiBufferRow,
22507        window: &mut Window,
22508        cx: &mut App,
22509    ) -> Option<AnyElement> {
22510        let folded = self.is_line_folded(buffer_row);
22511        if let Crease::Inline { render_trailer, .. } = self
22512            .crease_snapshot
22513            .query_row(buffer_row, &self.buffer_snapshot)?
22514        {
22515            let render_trailer = render_trailer.as_ref()?;
22516            Some(render_trailer(buffer_row, folded, window, cx))
22517        } else {
22518            None
22519        }
22520    }
22521}
22522
22523impl Deref for EditorSnapshot {
22524    type Target = DisplaySnapshot;
22525
22526    fn deref(&self) -> &Self::Target {
22527        &self.display_snapshot
22528    }
22529}
22530
22531#[derive(Clone, Debug, PartialEq, Eq)]
22532pub enum EditorEvent {
22533    InputIgnored {
22534        text: Arc<str>,
22535    },
22536    InputHandled {
22537        utf16_range_to_replace: Option<Range<isize>>,
22538        text: Arc<str>,
22539    },
22540    ExcerptsAdded {
22541        buffer: Entity<Buffer>,
22542        predecessor: ExcerptId,
22543        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22544    },
22545    ExcerptsRemoved {
22546        ids: Vec<ExcerptId>,
22547        removed_buffer_ids: Vec<BufferId>,
22548    },
22549    BufferFoldToggled {
22550        ids: Vec<ExcerptId>,
22551        folded: bool,
22552    },
22553    ExcerptsEdited {
22554        ids: Vec<ExcerptId>,
22555    },
22556    ExcerptsExpanded {
22557        ids: Vec<ExcerptId>,
22558    },
22559    BufferEdited,
22560    Edited {
22561        transaction_id: clock::Lamport,
22562    },
22563    Reparsed(BufferId),
22564    Focused,
22565    FocusedIn,
22566    Blurred,
22567    DirtyChanged,
22568    Saved,
22569    TitleChanged,
22570    DiffBaseChanged,
22571    SelectionsChanged {
22572        local: bool,
22573    },
22574    ScrollPositionChanged {
22575        local: bool,
22576        autoscroll: bool,
22577    },
22578    Closed,
22579    TransactionUndone {
22580        transaction_id: clock::Lamport,
22581    },
22582    TransactionBegun {
22583        transaction_id: clock::Lamport,
22584    },
22585    Reloaded,
22586    CursorShapeChanged,
22587    PushedToNavHistory {
22588        anchor: Anchor,
22589        is_deactivate: bool,
22590    },
22591}
22592
22593impl EventEmitter<EditorEvent> for Editor {}
22594
22595impl Focusable for Editor {
22596    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22597        self.focus_handle.clone()
22598    }
22599}
22600
22601impl Render for Editor {
22602    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22603        let settings = ThemeSettings::get_global(cx);
22604
22605        let mut text_style = match self.mode {
22606            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22607                color: cx.theme().colors().editor_foreground,
22608                font_family: settings.ui_font.family.clone(),
22609                font_features: settings.ui_font.features.clone(),
22610                font_fallbacks: settings.ui_font.fallbacks.clone(),
22611                font_size: rems(0.875).into(),
22612                font_weight: settings.ui_font.weight,
22613                line_height: relative(settings.buffer_line_height.value()),
22614                ..Default::default()
22615            },
22616            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22617                color: cx.theme().colors().editor_foreground,
22618                font_family: settings.buffer_font.family.clone(),
22619                font_features: settings.buffer_font.features.clone(),
22620                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22621                font_size: settings.buffer_font_size(cx).into(),
22622                font_weight: settings.buffer_font.weight,
22623                line_height: relative(settings.buffer_line_height.value()),
22624                ..Default::default()
22625            },
22626        };
22627        if let Some(text_style_refinement) = &self.text_style_refinement {
22628            text_style.refine(text_style_refinement)
22629        }
22630
22631        let background = match self.mode {
22632            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22633            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22634            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22635            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22636        };
22637
22638        EditorElement::new(
22639            &cx.entity(),
22640            EditorStyle {
22641                background,
22642                border: cx.theme().colors().border,
22643                local_player: cx.theme().players().local(),
22644                text: text_style,
22645                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22646                syntax: cx.theme().syntax().clone(),
22647                status: cx.theme().status().clone(),
22648                inlay_hints_style: make_inlay_hints_style(cx),
22649                inline_completion_styles: make_suggestion_styles(cx),
22650                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22651                show_underlines: self.diagnostics_enabled(),
22652            },
22653        )
22654    }
22655}
22656
22657impl EntityInputHandler for Editor {
22658    fn text_for_range(
22659        &mut self,
22660        range_utf16: Range<usize>,
22661        adjusted_range: &mut Option<Range<usize>>,
22662        _: &mut Window,
22663        cx: &mut Context<Self>,
22664    ) -> Option<String> {
22665        let snapshot = self.buffer.read(cx).read(cx);
22666        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22667        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22668        if (start.0..end.0) != range_utf16 {
22669            adjusted_range.replace(start.0..end.0);
22670        }
22671        Some(snapshot.text_for_range(start..end).collect())
22672    }
22673
22674    fn selected_text_range(
22675        &mut self,
22676        ignore_disabled_input: bool,
22677        _: &mut Window,
22678        cx: &mut Context<Self>,
22679    ) -> Option<UTF16Selection> {
22680        // Prevent the IME menu from appearing when holding down an alphabetic key
22681        // while input is disabled.
22682        if !ignore_disabled_input && !self.input_enabled {
22683            return None;
22684        }
22685
22686        let selection = self.selections.newest::<OffsetUtf16>(cx);
22687        let range = selection.range();
22688
22689        Some(UTF16Selection {
22690            range: range.start.0..range.end.0,
22691            reversed: selection.reversed,
22692        })
22693    }
22694
22695    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22696        let snapshot = self.buffer.read(cx).read(cx);
22697        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22698        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22699    }
22700
22701    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22702        self.clear_highlights::<InputComposition>(cx);
22703        self.ime_transaction.take();
22704    }
22705
22706    fn replace_text_in_range(
22707        &mut self,
22708        range_utf16: Option<Range<usize>>,
22709        text: &str,
22710        window: &mut Window,
22711        cx: &mut Context<Self>,
22712    ) {
22713        if !self.input_enabled {
22714            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22715            return;
22716        }
22717
22718        self.transact(window, cx, |this, window, cx| {
22719            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22720                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22721                Some(this.selection_replacement_ranges(range_utf16, cx))
22722            } else {
22723                this.marked_text_ranges(cx)
22724            };
22725
22726            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22727                let newest_selection_id = this.selections.newest_anchor().id;
22728                this.selections
22729                    .all::<OffsetUtf16>(cx)
22730                    .iter()
22731                    .zip(ranges_to_replace.iter())
22732                    .find_map(|(selection, range)| {
22733                        if selection.id == newest_selection_id {
22734                            Some(
22735                                (range.start.0 as isize - selection.head().0 as isize)
22736                                    ..(range.end.0 as isize - selection.head().0 as isize),
22737                            )
22738                        } else {
22739                            None
22740                        }
22741                    })
22742            });
22743
22744            cx.emit(EditorEvent::InputHandled {
22745                utf16_range_to_replace: range_to_replace,
22746                text: text.into(),
22747            });
22748
22749            if let Some(new_selected_ranges) = new_selected_ranges {
22750                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22751                    selections.select_ranges(new_selected_ranges)
22752                });
22753                this.backspace(&Default::default(), window, cx);
22754            }
22755
22756            this.handle_input(text, window, cx);
22757        });
22758
22759        if let Some(transaction) = self.ime_transaction {
22760            self.buffer.update(cx, |buffer, cx| {
22761                buffer.group_until_transaction(transaction, cx);
22762            });
22763        }
22764
22765        self.unmark_text(window, cx);
22766    }
22767
22768    fn replace_and_mark_text_in_range(
22769        &mut self,
22770        range_utf16: Option<Range<usize>>,
22771        text: &str,
22772        new_selected_range_utf16: Option<Range<usize>>,
22773        window: &mut Window,
22774        cx: &mut Context<Self>,
22775    ) {
22776        if !self.input_enabled {
22777            return;
22778        }
22779
22780        let transaction = self.transact(window, cx, |this, window, cx| {
22781            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22782                let snapshot = this.buffer.read(cx).read(cx);
22783                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22784                    for marked_range in &mut marked_ranges {
22785                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22786                        marked_range.start.0 += relative_range_utf16.start;
22787                        marked_range.start =
22788                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22789                        marked_range.end =
22790                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22791                    }
22792                }
22793                Some(marked_ranges)
22794            } else if let Some(range_utf16) = range_utf16 {
22795                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22796                Some(this.selection_replacement_ranges(range_utf16, cx))
22797            } else {
22798                None
22799            };
22800
22801            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22802                let newest_selection_id = this.selections.newest_anchor().id;
22803                this.selections
22804                    .all::<OffsetUtf16>(cx)
22805                    .iter()
22806                    .zip(ranges_to_replace.iter())
22807                    .find_map(|(selection, range)| {
22808                        if selection.id == newest_selection_id {
22809                            Some(
22810                                (range.start.0 as isize - selection.head().0 as isize)
22811                                    ..(range.end.0 as isize - selection.head().0 as isize),
22812                            )
22813                        } else {
22814                            None
22815                        }
22816                    })
22817            });
22818
22819            cx.emit(EditorEvent::InputHandled {
22820                utf16_range_to_replace: range_to_replace,
22821                text: text.into(),
22822            });
22823
22824            if let Some(ranges) = ranges_to_replace {
22825                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22826                    s.select_ranges(ranges)
22827                });
22828            }
22829
22830            let marked_ranges = {
22831                let snapshot = this.buffer.read(cx).read(cx);
22832                this.selections
22833                    .disjoint_anchors()
22834                    .iter()
22835                    .map(|selection| {
22836                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22837                    })
22838                    .collect::<Vec<_>>()
22839            };
22840
22841            if text.is_empty() {
22842                this.unmark_text(window, cx);
22843            } else {
22844                this.highlight_text::<InputComposition>(
22845                    marked_ranges.clone(),
22846                    HighlightStyle {
22847                        underline: Some(UnderlineStyle {
22848                            thickness: px(1.),
22849                            color: None,
22850                            wavy: false,
22851                        }),
22852                        ..Default::default()
22853                    },
22854                    cx,
22855                );
22856            }
22857
22858            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22859            let use_autoclose = this.use_autoclose;
22860            let use_auto_surround = this.use_auto_surround;
22861            this.set_use_autoclose(false);
22862            this.set_use_auto_surround(false);
22863            this.handle_input(text, window, cx);
22864            this.set_use_autoclose(use_autoclose);
22865            this.set_use_auto_surround(use_auto_surround);
22866
22867            if let Some(new_selected_range) = new_selected_range_utf16 {
22868                let snapshot = this.buffer.read(cx).read(cx);
22869                let new_selected_ranges = marked_ranges
22870                    .into_iter()
22871                    .map(|marked_range| {
22872                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22873                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22874                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22875                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22876                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22877                    })
22878                    .collect::<Vec<_>>();
22879
22880                drop(snapshot);
22881                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22882                    selections.select_ranges(new_selected_ranges)
22883                });
22884            }
22885        });
22886
22887        self.ime_transaction = self.ime_transaction.or(transaction);
22888        if let Some(transaction) = self.ime_transaction {
22889            self.buffer.update(cx, |buffer, cx| {
22890                buffer.group_until_transaction(transaction, cx);
22891            });
22892        }
22893
22894        if self.text_highlights::<InputComposition>(cx).is_none() {
22895            self.ime_transaction.take();
22896        }
22897    }
22898
22899    fn bounds_for_range(
22900        &mut self,
22901        range_utf16: Range<usize>,
22902        element_bounds: gpui::Bounds<Pixels>,
22903        window: &mut Window,
22904        cx: &mut Context<Self>,
22905    ) -> Option<gpui::Bounds<Pixels>> {
22906        let text_layout_details = self.text_layout_details(window);
22907        let CharacterDimensions {
22908            em_width,
22909            em_advance,
22910            line_height,
22911        } = self.character_dimensions(window);
22912
22913        let snapshot = self.snapshot(window, cx);
22914        let scroll_position = snapshot.scroll_position();
22915        let scroll_left = scroll_position.x * em_advance;
22916
22917        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22918        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22919            + self.gutter_dimensions.full_width();
22920        let y = line_height * (start.row().as_f32() - scroll_position.y);
22921
22922        Some(Bounds {
22923            origin: element_bounds.origin + point(x, y),
22924            size: size(em_width, line_height),
22925        })
22926    }
22927
22928    fn character_index_for_point(
22929        &mut self,
22930        point: gpui::Point<Pixels>,
22931        _window: &mut Window,
22932        _cx: &mut Context<Self>,
22933    ) -> Option<usize> {
22934        let position_map = self.last_position_map.as_ref()?;
22935        if !position_map.text_hitbox.contains(&point) {
22936            return None;
22937        }
22938        let display_point = position_map.point_for_position(point).previous_valid;
22939        let anchor = position_map
22940            .snapshot
22941            .display_point_to_anchor(display_point, Bias::Left);
22942        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22943        Some(utf16_offset.0)
22944    }
22945}
22946
22947trait SelectionExt {
22948    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22949    fn spanned_rows(
22950        &self,
22951        include_end_if_at_line_start: bool,
22952        map: &DisplaySnapshot,
22953    ) -> Range<MultiBufferRow>;
22954}
22955
22956impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22957    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22958        let start = self
22959            .start
22960            .to_point(&map.buffer_snapshot)
22961            .to_display_point(map);
22962        let end = self
22963            .end
22964            .to_point(&map.buffer_snapshot)
22965            .to_display_point(map);
22966        if self.reversed {
22967            end..start
22968        } else {
22969            start..end
22970        }
22971    }
22972
22973    fn spanned_rows(
22974        &self,
22975        include_end_if_at_line_start: bool,
22976        map: &DisplaySnapshot,
22977    ) -> Range<MultiBufferRow> {
22978        let start = self.start.to_point(&map.buffer_snapshot);
22979        let mut end = self.end.to_point(&map.buffer_snapshot);
22980        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22981            end.row -= 1;
22982        }
22983
22984        let buffer_start = map.prev_line_boundary(start).0;
22985        let buffer_end = map.next_line_boundary(end).0;
22986        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22987    }
22988}
22989
22990impl<T: InvalidationRegion> InvalidationStack<T> {
22991    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22992    where
22993        S: Clone + ToOffset,
22994    {
22995        while let Some(region) = self.last() {
22996            let all_selections_inside_invalidation_ranges =
22997                if selections.len() == region.ranges().len() {
22998                    selections
22999                        .iter()
23000                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23001                        .all(|(selection, invalidation_range)| {
23002                            let head = selection.head().to_offset(buffer);
23003                            invalidation_range.start <= head && invalidation_range.end >= head
23004                        })
23005                } else {
23006                    false
23007                };
23008
23009            if all_selections_inside_invalidation_ranges {
23010                break;
23011            } else {
23012                self.pop();
23013            }
23014        }
23015    }
23016}
23017
23018impl<T> Default for InvalidationStack<T> {
23019    fn default() -> Self {
23020        Self(Default::default())
23021    }
23022}
23023
23024impl<T> Deref for InvalidationStack<T> {
23025    type Target = Vec<T>;
23026
23027    fn deref(&self) -> &Self::Target {
23028        &self.0
23029    }
23030}
23031
23032impl<T> DerefMut for InvalidationStack<T> {
23033    fn deref_mut(&mut self) -> &mut Self::Target {
23034        &mut self.0
23035    }
23036}
23037
23038impl InvalidationRegion for SnippetState {
23039    fn ranges(&self) -> &[Range<Anchor>] {
23040        &self.ranges[self.active_index]
23041    }
23042}
23043
23044fn inline_completion_edit_text(
23045    current_snapshot: &BufferSnapshot,
23046    edits: &[(Range<Anchor>, String)],
23047    edit_preview: &EditPreview,
23048    include_deletions: bool,
23049    cx: &App,
23050) -> HighlightedText {
23051    let edits = edits
23052        .iter()
23053        .map(|(anchor, text)| {
23054            (
23055                anchor.start.text_anchor..anchor.end.text_anchor,
23056                text.clone(),
23057            )
23058        })
23059        .collect::<Vec<_>>();
23060
23061    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23062}
23063
23064pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23065    match severity {
23066        lsp::DiagnosticSeverity::ERROR => colors.error,
23067        lsp::DiagnosticSeverity::WARNING => colors.warning,
23068        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23069        lsp::DiagnosticSeverity::HINT => colors.info,
23070        _ => colors.ignored,
23071    }
23072}
23073
23074pub fn styled_runs_for_code_label<'a>(
23075    label: &'a CodeLabel,
23076    syntax_theme: &'a theme::SyntaxTheme,
23077) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23078    let fade_out = HighlightStyle {
23079        fade_out: Some(0.35),
23080        ..Default::default()
23081    };
23082
23083    let mut prev_end = label.filter_range.end;
23084    label
23085        .runs
23086        .iter()
23087        .enumerate()
23088        .flat_map(move |(ix, (range, highlight_id))| {
23089            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23090                style
23091            } else {
23092                return Default::default();
23093            };
23094            let mut muted_style = style;
23095            muted_style.highlight(fade_out);
23096
23097            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23098            if range.start >= label.filter_range.end {
23099                if range.start > prev_end {
23100                    runs.push((prev_end..range.start, fade_out));
23101                }
23102                runs.push((range.clone(), muted_style));
23103            } else if range.end <= label.filter_range.end {
23104                runs.push((range.clone(), style));
23105            } else {
23106                runs.push((range.start..label.filter_range.end, style));
23107                runs.push((label.filter_range.end..range.end, muted_style));
23108            }
23109            prev_end = cmp::max(prev_end, range.end);
23110
23111            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23112                runs.push((prev_end..label.text.len(), fade_out));
23113            }
23114
23115            runs
23116        })
23117}
23118
23119pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23120    let mut prev_index = 0;
23121    let mut prev_codepoint: Option<char> = None;
23122    text.char_indices()
23123        .chain([(text.len(), '\0')])
23124        .filter_map(move |(index, codepoint)| {
23125            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23126            let is_boundary = index == text.len()
23127                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23128                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23129            if is_boundary {
23130                let chunk = &text[prev_index..index];
23131                prev_index = index;
23132                Some(chunk)
23133            } else {
23134                None
23135            }
23136        })
23137}
23138
23139pub trait RangeToAnchorExt: Sized {
23140    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23141
23142    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23143        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23144        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23145    }
23146}
23147
23148impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23149    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23150        let start_offset = self.start.to_offset(snapshot);
23151        let end_offset = self.end.to_offset(snapshot);
23152        if start_offset == end_offset {
23153            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23154        } else {
23155            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23156        }
23157    }
23158}
23159
23160pub trait RowExt {
23161    fn as_f32(&self) -> f32;
23162
23163    fn next_row(&self) -> Self;
23164
23165    fn previous_row(&self) -> Self;
23166
23167    fn minus(&self, other: Self) -> u32;
23168}
23169
23170impl RowExt for DisplayRow {
23171    fn as_f32(&self) -> f32 {
23172        self.0 as f32
23173    }
23174
23175    fn next_row(&self) -> Self {
23176        Self(self.0 + 1)
23177    }
23178
23179    fn previous_row(&self) -> Self {
23180        Self(self.0.saturating_sub(1))
23181    }
23182
23183    fn minus(&self, other: Self) -> u32 {
23184        self.0 - other.0
23185    }
23186}
23187
23188impl RowExt for MultiBufferRow {
23189    fn as_f32(&self) -> f32 {
23190        self.0 as f32
23191    }
23192
23193    fn next_row(&self) -> Self {
23194        Self(self.0 + 1)
23195    }
23196
23197    fn previous_row(&self) -> Self {
23198        Self(self.0.saturating_sub(1))
23199    }
23200
23201    fn minus(&self, other: Self) -> u32 {
23202        self.0 - other.0
23203    }
23204}
23205
23206trait RowRangeExt {
23207    type Row;
23208
23209    fn len(&self) -> usize;
23210
23211    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23212}
23213
23214impl RowRangeExt for Range<MultiBufferRow> {
23215    type Row = MultiBufferRow;
23216
23217    fn len(&self) -> usize {
23218        (self.end.0 - self.start.0) as usize
23219    }
23220
23221    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23222        (self.start.0..self.end.0).map(MultiBufferRow)
23223    }
23224}
23225
23226impl RowRangeExt for Range<DisplayRow> {
23227    type Row = DisplayRow;
23228
23229    fn len(&self) -> usize {
23230        (self.end.0 - self.start.0) as usize
23231    }
23232
23233    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23234        (self.start.0..self.end.0).map(DisplayRow)
23235    }
23236}
23237
23238/// If select range has more than one line, we
23239/// just point the cursor to range.start.
23240fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23241    if range.start.row == range.end.row {
23242        range
23243    } else {
23244        range.start..range.start
23245    }
23246}
23247pub struct KillRing(ClipboardItem);
23248impl Global for KillRing {}
23249
23250const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23251
23252enum BreakpointPromptEditAction {
23253    Log,
23254    Condition,
23255    HitCondition,
23256}
23257
23258struct BreakpointPromptEditor {
23259    pub(crate) prompt: Entity<Editor>,
23260    editor: WeakEntity<Editor>,
23261    breakpoint_anchor: Anchor,
23262    breakpoint: Breakpoint,
23263    edit_action: BreakpointPromptEditAction,
23264    block_ids: HashSet<CustomBlockId>,
23265    editor_margins: Arc<Mutex<EditorMargins>>,
23266    _subscriptions: Vec<Subscription>,
23267}
23268
23269impl BreakpointPromptEditor {
23270    const MAX_LINES: u8 = 4;
23271
23272    fn new(
23273        editor: WeakEntity<Editor>,
23274        breakpoint_anchor: Anchor,
23275        breakpoint: Breakpoint,
23276        edit_action: BreakpointPromptEditAction,
23277        window: &mut Window,
23278        cx: &mut Context<Self>,
23279    ) -> Self {
23280        let base_text = match edit_action {
23281            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23282            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23283            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23284        }
23285        .map(|msg| msg.to_string())
23286        .unwrap_or_default();
23287
23288        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23289        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23290
23291        let prompt = cx.new(|cx| {
23292            let mut prompt = Editor::new(
23293                EditorMode::AutoHeight {
23294                    min_lines: 1,
23295                    max_lines: Some(Self::MAX_LINES as usize),
23296                },
23297                buffer,
23298                None,
23299                window,
23300                cx,
23301            );
23302            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23303            prompt.set_show_cursor_when_unfocused(false, cx);
23304            prompt.set_placeholder_text(
23305                match edit_action {
23306                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23307                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23308                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23309                },
23310                cx,
23311            );
23312
23313            prompt
23314        });
23315
23316        Self {
23317            prompt,
23318            editor,
23319            breakpoint_anchor,
23320            breakpoint,
23321            edit_action,
23322            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23323            block_ids: Default::default(),
23324            _subscriptions: vec![],
23325        }
23326    }
23327
23328    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23329        self.block_ids.extend(block_ids)
23330    }
23331
23332    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23333        if let Some(editor) = self.editor.upgrade() {
23334            let message = self
23335                .prompt
23336                .read(cx)
23337                .buffer
23338                .read(cx)
23339                .as_singleton()
23340                .expect("A multi buffer in breakpoint prompt isn't possible")
23341                .read(cx)
23342                .as_rope()
23343                .to_string();
23344
23345            editor.update(cx, |editor, cx| {
23346                editor.edit_breakpoint_at_anchor(
23347                    self.breakpoint_anchor,
23348                    self.breakpoint.clone(),
23349                    match self.edit_action {
23350                        BreakpointPromptEditAction::Log => {
23351                            BreakpointEditAction::EditLogMessage(message.into())
23352                        }
23353                        BreakpointPromptEditAction::Condition => {
23354                            BreakpointEditAction::EditCondition(message.into())
23355                        }
23356                        BreakpointPromptEditAction::HitCondition => {
23357                            BreakpointEditAction::EditHitCondition(message.into())
23358                        }
23359                    },
23360                    cx,
23361                );
23362
23363                editor.remove_blocks(self.block_ids.clone(), None, cx);
23364                cx.focus_self(window);
23365            });
23366        }
23367    }
23368
23369    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23370        self.editor
23371            .update(cx, |editor, cx| {
23372                editor.remove_blocks(self.block_ids.clone(), None, cx);
23373                window.focus(&editor.focus_handle);
23374            })
23375            .log_err();
23376    }
23377
23378    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23379        let settings = ThemeSettings::get_global(cx);
23380        let text_style = TextStyle {
23381            color: if self.prompt.read(cx).read_only(cx) {
23382                cx.theme().colors().text_disabled
23383            } else {
23384                cx.theme().colors().text
23385            },
23386            font_family: settings.buffer_font.family.clone(),
23387            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23388            font_size: settings.buffer_font_size(cx).into(),
23389            font_weight: settings.buffer_font.weight,
23390            line_height: relative(settings.buffer_line_height.value()),
23391            ..Default::default()
23392        };
23393        EditorElement::new(
23394            &self.prompt,
23395            EditorStyle {
23396                background: cx.theme().colors().editor_background,
23397                local_player: cx.theme().players().local(),
23398                text: text_style,
23399                ..Default::default()
23400            },
23401        )
23402    }
23403}
23404
23405impl Render for BreakpointPromptEditor {
23406    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23407        let editor_margins = *self.editor_margins.lock();
23408        let gutter_dimensions = editor_margins.gutter;
23409        h_flex()
23410            .key_context("Editor")
23411            .bg(cx.theme().colors().editor_background)
23412            .border_y_1()
23413            .border_color(cx.theme().status().info_border)
23414            .size_full()
23415            .py(window.line_height() / 2.5)
23416            .on_action(cx.listener(Self::confirm))
23417            .on_action(cx.listener(Self::cancel))
23418            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23419            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23420    }
23421}
23422
23423impl Focusable for BreakpointPromptEditor {
23424    fn focus_handle(&self, cx: &App) -> FocusHandle {
23425        self.prompt.focus_handle(cx)
23426    }
23427}
23428
23429fn all_edits_insertions_or_deletions(
23430    edits: &Vec<(Range<Anchor>, String)>,
23431    snapshot: &MultiBufferSnapshot,
23432) -> bool {
23433    let mut all_insertions = true;
23434    let mut all_deletions = true;
23435
23436    for (range, new_text) in edits.iter() {
23437        let range_is_empty = range.to_offset(&snapshot).is_empty();
23438        let text_is_empty = new_text.is_empty();
23439
23440        if range_is_empty != text_is_empty {
23441            if range_is_empty {
23442                all_deletions = false;
23443            } else {
23444                all_insertions = false;
23445            }
23446        } else {
23447            return false;
23448        }
23449
23450        if !all_insertions && !all_deletions {
23451            return false;
23452        }
23453    }
23454    all_insertions || all_deletions
23455}
23456
23457struct MissingEditPredictionKeybindingTooltip;
23458
23459impl Render for MissingEditPredictionKeybindingTooltip {
23460    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23461        ui::tooltip_container(window, cx, |container, _, cx| {
23462            container
23463                .flex_shrink_0()
23464                .max_w_80()
23465                .min_h(rems_from_px(124.))
23466                .justify_between()
23467                .child(
23468                    v_flex()
23469                        .flex_1()
23470                        .text_ui_sm(cx)
23471                        .child(Label::new("Conflict with Accept Keybinding"))
23472                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23473                )
23474                .child(
23475                    h_flex()
23476                        .pb_1()
23477                        .gap_1()
23478                        .items_end()
23479                        .w_full()
23480                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23481                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23482                        }))
23483                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23484                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23485                        })),
23486                )
23487        })
23488    }
23489}
23490
23491#[derive(Debug, Clone, Copy, PartialEq)]
23492pub struct LineHighlight {
23493    pub background: Background,
23494    pub border: Option<gpui::Hsla>,
23495    pub include_gutter: bool,
23496    pub type_id: Option<TypeId>,
23497}
23498
23499struct LineManipulationResult {
23500    pub new_text: String,
23501    pub line_count_before: usize,
23502    pub line_count_after: usize,
23503}
23504
23505fn render_diff_hunk_controls(
23506    row: u32,
23507    status: &DiffHunkStatus,
23508    hunk_range: Range<Anchor>,
23509    is_created_file: bool,
23510    line_height: Pixels,
23511    editor: &Entity<Editor>,
23512    _window: &mut Window,
23513    cx: &mut App,
23514) -> AnyElement {
23515    h_flex()
23516        .h(line_height)
23517        .mr_1()
23518        .gap_1()
23519        .px_0p5()
23520        .pb_1()
23521        .border_x_1()
23522        .border_b_1()
23523        .border_color(cx.theme().colors().border_variant)
23524        .rounded_b_lg()
23525        .bg(cx.theme().colors().editor_background)
23526        .gap_1()
23527        .block_mouse_except_scroll()
23528        .shadow_md()
23529        .child(if status.has_secondary_hunk() {
23530            Button::new(("stage", row as u64), "Stage")
23531                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23532                .tooltip({
23533                    let focus_handle = editor.focus_handle(cx);
23534                    move |window, cx| {
23535                        Tooltip::for_action_in(
23536                            "Stage Hunk",
23537                            &::git::ToggleStaged,
23538                            &focus_handle,
23539                            window,
23540                            cx,
23541                        )
23542                    }
23543                })
23544                .on_click({
23545                    let editor = editor.clone();
23546                    move |_event, _window, cx| {
23547                        editor.update(cx, |editor, cx| {
23548                            editor.stage_or_unstage_diff_hunks(
23549                                true,
23550                                vec![hunk_range.start..hunk_range.start],
23551                                cx,
23552                            );
23553                        });
23554                    }
23555                })
23556        } else {
23557            Button::new(("unstage", row as u64), "Unstage")
23558                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23559                .tooltip({
23560                    let focus_handle = editor.focus_handle(cx);
23561                    move |window, cx| {
23562                        Tooltip::for_action_in(
23563                            "Unstage Hunk",
23564                            &::git::ToggleStaged,
23565                            &focus_handle,
23566                            window,
23567                            cx,
23568                        )
23569                    }
23570                })
23571                .on_click({
23572                    let editor = editor.clone();
23573                    move |_event, _window, cx| {
23574                        editor.update(cx, |editor, cx| {
23575                            editor.stage_or_unstage_diff_hunks(
23576                                false,
23577                                vec![hunk_range.start..hunk_range.start],
23578                                cx,
23579                            );
23580                        });
23581                    }
23582                })
23583        })
23584        .child(
23585            Button::new(("restore", row as u64), "Restore")
23586                .tooltip({
23587                    let focus_handle = editor.focus_handle(cx);
23588                    move |window, cx| {
23589                        Tooltip::for_action_in(
23590                            "Restore Hunk",
23591                            &::git::Restore,
23592                            &focus_handle,
23593                            window,
23594                            cx,
23595                        )
23596                    }
23597                })
23598                .on_click({
23599                    let editor = editor.clone();
23600                    move |_event, window, cx| {
23601                        editor.update(cx, |editor, cx| {
23602                            let snapshot = editor.snapshot(window, cx);
23603                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23604                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23605                        });
23606                    }
23607                })
23608                .disabled(is_created_file),
23609        )
23610        .when(
23611            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23612            |el| {
23613                el.child(
23614                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23615                        .shape(IconButtonShape::Square)
23616                        .icon_size(IconSize::Small)
23617                        // .disabled(!has_multiple_hunks)
23618                        .tooltip({
23619                            let focus_handle = editor.focus_handle(cx);
23620                            move |window, cx| {
23621                                Tooltip::for_action_in(
23622                                    "Next Hunk",
23623                                    &GoToHunk,
23624                                    &focus_handle,
23625                                    window,
23626                                    cx,
23627                                )
23628                            }
23629                        })
23630                        .on_click({
23631                            let editor = editor.clone();
23632                            move |_event, window, cx| {
23633                                editor.update(cx, |editor, cx| {
23634                                    let snapshot = editor.snapshot(window, cx);
23635                                    let position =
23636                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23637                                    editor.go_to_hunk_before_or_after_position(
23638                                        &snapshot,
23639                                        position,
23640                                        Direction::Next,
23641                                        window,
23642                                        cx,
23643                                    );
23644                                    editor.expand_selected_diff_hunks(cx);
23645                                });
23646                            }
23647                        }),
23648                )
23649                .child(
23650                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23651                        .shape(IconButtonShape::Square)
23652                        .icon_size(IconSize::Small)
23653                        // .disabled(!has_multiple_hunks)
23654                        .tooltip({
23655                            let focus_handle = editor.focus_handle(cx);
23656                            move |window, cx| {
23657                                Tooltip::for_action_in(
23658                                    "Previous Hunk",
23659                                    &GoToPreviousHunk,
23660                                    &focus_handle,
23661                                    window,
23662                                    cx,
23663                                )
23664                            }
23665                        })
23666                        .on_click({
23667                            let editor = editor.clone();
23668                            move |_event, window, cx| {
23669                                editor.update(cx, |editor, cx| {
23670                                    let snapshot = editor.snapshot(window, cx);
23671                                    let point =
23672                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23673                                    editor.go_to_hunk_before_or_after_position(
23674                                        &snapshot,
23675                                        point,
23676                                        Direction::Prev,
23677                                        window,
23678                                        cx,
23679                                    );
23680                                    editor.expand_selected_diff_hunks(cx);
23681                                });
23682                            }
23683                        }),
23684                )
23685            },
23686        )
23687        .into_any_element()
23688}