editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47#[cfg(test)]
   48mod inline_completion_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   55use aho_corasick::AhoCorasick;
   56use anyhow::{Context as _, Result, anyhow};
   57use blink_manager::BlinkManager;
   58use buffer_diff::DiffHunkStatus;
   59use client::{Collaborator, ParticipantIndex};
   60use clock::{AGENT_REPLICA_ID, ReplicaId};
   61use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   62use convert_case::{Case, Casing};
   63use dap::TelemetrySpawnLocation;
   64use display_map::*;
   65pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   66pub use editor_settings::{
   67    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   68    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowScrollbar,
   69};
   70use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   71pub use editor_settings_controls::*;
   72use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   73pub use element::{
   74    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   75};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82use lsp_colors::LspColorData;
   83
   84use ::git::blame::BlameEntry;
   85use ::git::{Restore, blame::ParsedCommitMessage};
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use git::blame::{GitBlame, GlobalBlameRenderer};
   91use gpui::{
   92    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   93    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   94    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   95    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   96    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   97    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   98    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   99    div, point, prelude::*, pulsating_between, px, relative, size,
  100};
  101use highlight_matching_bracket::refresh_matching_bracket_highlights;
  102use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  103pub use hover_popover::hover_markdown_style;
  104use hover_popover::{HoverState, hide_hover};
  105use indent_guides::ActiveIndentGuidesState;
  106use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  107pub use inline_completion::Direction;
  108use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  109pub use items::MAX_TAB_TITLE_LEN;
  110use itertools::Itertools;
  111use language::{
  112    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, Capability, CharKind,
  113    CodeLabel, CursorShape, DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview,
  114    HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection,
  115    SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, ProjectPath,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    git_store::{GitStoreEvent, RepositoryEvent},
  137    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  138};
  139
  140pub use git::blame::BlameRenderer;
  141pub use proposed_changes_editor::{
  142    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  143};
  144use std::{cell::OnceCell, iter::Peekable, ops::Not};
  145use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  146
  147pub use lsp::CompletionContext;
  148use lsp::{
  149    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  150    LanguageServerId, LanguageServerName,
  151};
  152
  153use language::BufferSnapshot;
  154pub use lsp_ext::lsp_tasks;
  155use movement::TextLayoutDetails;
  156pub use multi_buffer::{
  157    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  158    RowInfo, ToOffset, ToPoint,
  159};
  160use multi_buffer::{
  161    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  162    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  163};
  164use parking_lot::Mutex;
  165use project::{
  166    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  167    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  168    TaskSourceKind,
  169    debugger::breakpoint_store::Breakpoint,
  170    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  171    project_settings::{GitGutterSetting, ProjectSettings},
  172};
  173use rand::prelude::*;
  174use rpc::{ErrorExt, proto::*};
  175use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  176use selections_collection::{
  177    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  178};
  179use serde::{Deserialize, Serialize};
  180use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  181use smallvec::{SmallVec, smallvec};
  182use snippet::Snippet;
  183use std::sync::Arc;
  184use std::{
  185    any::TypeId,
  186    borrow::Cow,
  187    cell::RefCell,
  188    cmp::{self, Ordering, Reverse},
  189    mem,
  190    num::NonZeroU32,
  191    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  192    path::{Path, PathBuf},
  193    rc::Rc,
  194    time::{Duration, Instant},
  195};
  196pub use sum_tree::Bias;
  197use sum_tree::TreeMap;
  198use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  199use theme::{
  200    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  201    observe_buffer_font_size_adjustment,
  202};
  203use ui::{
  204    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  205    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  206};
  207use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  208use workspace::{
  209    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  210    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  211    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  212    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  213    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  214    searchable::SearchEvent,
  215};
  216use zed_actions;
  217
  218use crate::{
  219    code_context_menus::CompletionsMenuSource,
  220    hover_links::{find_url, find_url_from_range},
  221};
  222use crate::{
  223    editor_settings::MultiCursorModifier,
  224    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  225};
  226
  227pub const FILE_HEADER_HEIGHT: u32 = 2;
  228pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  229pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242
  243pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  244pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  245pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  246
  247pub type RenderDiffHunkControlsFn = Arc<
  248    dyn Fn(
  249        u32,
  250        &DiffHunkStatus,
  251        Range<Anchor>,
  252        bool,
  253        Pixels,
  254        &Entity<Editor>,
  255        &mut Window,
  256        &mut App,
  257    ) -> AnyElement,
  258>;
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    DebuggerValue(usize),
  280    // LSP
  281    Hint(usize),
  282    Color(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::DebuggerValue(id) => *id,
  290            Self::Hint(id) => *id,
  291            Self::Color(id) => *id,
  292        }
  293    }
  294}
  295
  296pub enum ActiveDebugLine {}
  297pub enum DebugStackFrameLine {}
  298enum DocumentHighlightRead {}
  299enum DocumentHighlightWrite {}
  300enum InputComposition {}
  301pub enum PendingInput {}
  302enum SelectedTextHighlight {}
  303
  304pub enum ConflictsOuter {}
  305pub enum ConflictsOurs {}
  306pub enum ConflictsTheirs {}
  307pub enum ConflictsOursMarker {}
  308pub enum ConflictsTheirsMarker {}
  309
  310#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  311pub enum Navigated {
  312    Yes,
  313    No,
  314}
  315
  316impl Navigated {
  317    pub fn from_bool(yes: bool) -> Navigated {
  318        if yes { Navigated::Yes } else { Navigated::No }
  319    }
  320}
  321
  322#[derive(Debug, Clone, PartialEq, Eq)]
  323enum DisplayDiffHunk {
  324    Folded {
  325        display_row: DisplayRow,
  326    },
  327    Unfolded {
  328        is_created_file: bool,
  329        diff_base_byte_range: Range<usize>,
  330        display_row_range: Range<DisplayRow>,
  331        multi_buffer_range: Range<Anchor>,
  332        status: DiffHunkStatus,
  333    },
  334}
  335
  336pub enum HideMouseCursorOrigin {
  337    TypingAction,
  338    MovementAction,
  339}
  340
  341pub fn init_settings(cx: &mut App) {
  342    EditorSettings::register(cx);
  343}
  344
  345pub fn init(cx: &mut App) {
  346    init_settings(cx);
  347
  348    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  349
  350    workspace::register_project_item::<Editor>(cx);
  351    workspace::FollowableViewRegistry::register::<Editor>(cx);
  352    workspace::register_serializable_item::<Editor>(cx);
  353
  354    cx.observe_new(
  355        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  356            workspace.register_action(Editor::new_file);
  357            workspace.register_action(Editor::new_file_vertical);
  358            workspace.register_action(Editor::new_file_horizontal);
  359            workspace.register_action(Editor::cancel_language_server_work);
  360            workspace.register_action(Editor::toggle_focus);
  361        },
  362    )
  363    .detach();
  364
  365    cx.on_action(move |_: &workspace::NewFile, cx| {
  366        let app_state = workspace::AppState::global(cx);
  367        if let Some(app_state) = app_state.upgrade() {
  368            workspace::open_new(
  369                Default::default(),
  370                app_state,
  371                cx,
  372                |workspace, window, cx| {
  373                    Editor::new_file(workspace, &Default::default(), window, cx)
  374                },
  375            )
  376            .detach();
  377        }
  378    });
  379    cx.on_action(move |_: &workspace::NewWindow, cx| {
  380        let app_state = workspace::AppState::global(cx);
  381        if let Some(app_state) = app_state.upgrade() {
  382            workspace::open_new(
  383                Default::default(),
  384                app_state,
  385                cx,
  386                |workspace, window, cx| {
  387                    cx.activate(true);
  388                    Editor::new_file(workspace, &Default::default(), window, cx)
  389                },
  390            )
  391            .detach();
  392        }
  393    });
  394}
  395
  396pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  397    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  398}
  399
  400pub trait DiagnosticRenderer {
  401    fn render_group(
  402        &self,
  403        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  404        buffer_id: BufferId,
  405        snapshot: EditorSnapshot,
  406        editor: WeakEntity<Editor>,
  407        cx: &mut App,
  408    ) -> Vec<BlockProperties<Anchor>>;
  409
  410    fn render_hover(
  411        &self,
  412        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  413        range: Range<Point>,
  414        buffer_id: BufferId,
  415        cx: &mut App,
  416    ) -> Option<Entity<markdown::Markdown>>;
  417
  418    fn open_link(
  419        &self,
  420        editor: &mut Editor,
  421        link: SharedString,
  422        window: &mut Window,
  423        cx: &mut Context<Editor>,
  424    );
  425}
  426
  427pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  428
  429impl GlobalDiagnosticRenderer {
  430    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  431        cx.try_global::<Self>().map(|g| g.0.clone())
  432    }
  433}
  434
  435impl gpui::Global for GlobalDiagnosticRenderer {}
  436pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  437    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  438}
  439
  440pub struct SearchWithinRange;
  441
  442trait InvalidationRegion {
  443    fn ranges(&self) -> &[Range<Anchor>];
  444}
  445
  446#[derive(Clone, Debug, PartialEq)]
  447pub enum SelectPhase {
  448    Begin {
  449        position: DisplayPoint,
  450        add: bool,
  451        click_count: usize,
  452    },
  453    BeginColumnar {
  454        position: DisplayPoint,
  455        reset: bool,
  456        mode: ColumnarMode,
  457        goal_column: u32,
  458    },
  459    Extend {
  460        position: DisplayPoint,
  461        click_count: usize,
  462    },
  463    Update {
  464        position: DisplayPoint,
  465        goal_column: u32,
  466        scroll_delta: gpui::Point<f32>,
  467    },
  468    End,
  469}
  470
  471#[derive(Clone, Debug, PartialEq)]
  472pub enum ColumnarMode {
  473    FromMouse,
  474    FromSelection,
  475}
  476
  477#[derive(Clone, Debug)]
  478pub enum SelectMode {
  479    Character,
  480    Word(Range<Anchor>),
  481    Line(Range<Anchor>),
  482    All,
  483}
  484
  485#[derive(Clone, PartialEq, Eq, Debug)]
  486pub enum EditorMode {
  487    SingleLine,
  488    AutoHeight {
  489        min_lines: usize,
  490        max_lines: Option<usize>,
  491    },
  492    Full {
  493        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  494        scale_ui_elements_with_buffer_font_size: bool,
  495        /// When set to `true`, the editor will render a background for the active line.
  496        show_active_line_background: bool,
  497        /// When set to `true`, the editor's height will be determined by its content.
  498        sized_by_content: bool,
  499    },
  500    Minimap {
  501        parent: WeakEntity<Editor>,
  502    },
  503}
  504
  505impl EditorMode {
  506    pub fn full() -> Self {
  507        Self::Full {
  508            scale_ui_elements_with_buffer_font_size: true,
  509            show_active_line_background: true,
  510            sized_by_content: false,
  511        }
  512    }
  513
  514    #[inline]
  515    pub fn is_full(&self) -> bool {
  516        matches!(self, Self::Full { .. })
  517    }
  518
  519    #[inline]
  520    pub fn is_single_line(&self) -> bool {
  521        matches!(self, Self::SingleLine { .. })
  522    }
  523
  524    #[inline]
  525    fn is_minimap(&self) -> bool {
  526        matches!(self, Self::Minimap { .. })
  527    }
  528}
  529
  530#[derive(Copy, Clone, Debug)]
  531pub enum SoftWrap {
  532    /// Prefer not to wrap at all.
  533    ///
  534    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  535    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  536    GitDiff,
  537    /// Prefer a single line generally, unless an overly long line is encountered.
  538    None,
  539    /// Soft wrap lines that exceed the editor width.
  540    EditorWidth,
  541    /// Soft wrap lines at the preferred line length.
  542    Column(u32),
  543    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  544    Bounded(u32),
  545}
  546
  547#[derive(Clone)]
  548pub struct EditorStyle {
  549    pub background: Hsla,
  550    pub border: Hsla,
  551    pub local_player: PlayerColor,
  552    pub text: TextStyle,
  553    pub scrollbar_width: Pixels,
  554    pub syntax: Arc<SyntaxTheme>,
  555    pub status: StatusColors,
  556    pub inlay_hints_style: HighlightStyle,
  557    pub inline_completion_styles: InlineCompletionStyles,
  558    pub unnecessary_code_fade: f32,
  559    pub show_underlines: bool,
  560}
  561
  562impl Default for EditorStyle {
  563    fn default() -> Self {
  564        Self {
  565            background: Hsla::default(),
  566            border: Hsla::default(),
  567            local_player: PlayerColor::default(),
  568            text: TextStyle::default(),
  569            scrollbar_width: Pixels::default(),
  570            syntax: Default::default(),
  571            // HACK: Status colors don't have a real default.
  572            // We should look into removing the status colors from the editor
  573            // style and retrieve them directly from the theme.
  574            status: StatusColors::dark(),
  575            inlay_hints_style: HighlightStyle::default(),
  576            inline_completion_styles: InlineCompletionStyles {
  577                insertion: HighlightStyle::default(),
  578                whitespace: HighlightStyle::default(),
  579            },
  580            unnecessary_code_fade: Default::default(),
  581            show_underlines: true,
  582        }
  583    }
  584}
  585
  586pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  587    let show_background = language_settings::language_settings(None, None, cx)
  588        .inlay_hints
  589        .show_background;
  590
  591    HighlightStyle {
  592        color: Some(cx.theme().status().hint),
  593        background_color: show_background.then(|| cx.theme().status().hint_background),
  594        ..HighlightStyle::default()
  595    }
  596}
  597
  598pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  599    InlineCompletionStyles {
  600        insertion: HighlightStyle {
  601            color: Some(cx.theme().status().predictive),
  602            ..HighlightStyle::default()
  603        },
  604        whitespace: HighlightStyle {
  605            background_color: Some(cx.theme().status().created_background),
  606            ..HighlightStyle::default()
  607        },
  608    }
  609}
  610
  611type CompletionId = usize;
  612
  613pub(crate) enum EditDisplayMode {
  614    TabAccept,
  615    DiffPopover,
  616    Inline,
  617}
  618
  619enum InlineCompletion {
  620    Edit {
  621        edits: Vec<(Range<Anchor>, String)>,
  622        edit_preview: Option<EditPreview>,
  623        display_mode: EditDisplayMode,
  624        snapshot: BufferSnapshot,
  625    },
  626    Move {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630}
  631
  632struct InlineCompletionState {
  633    inlay_ids: Vec<InlayId>,
  634    completion: InlineCompletion,
  635    completion_id: Option<SharedString>,
  636    invalidation_range: Range<Anchor>,
  637}
  638
  639enum EditPredictionSettings {
  640    Disabled,
  641    Enabled {
  642        show_in_menu: bool,
  643        preview_requires_modifier: bool,
  644    },
  645}
  646
  647enum InlineCompletionHighlight {}
  648
  649#[derive(Debug, Clone)]
  650struct InlineDiagnostic {
  651    message: SharedString,
  652    group_id: usize,
  653    is_primary: bool,
  654    start: Point,
  655    severity: lsp::DiagnosticSeverity,
  656}
  657
  658pub enum MenuInlineCompletionsPolicy {
  659    Never,
  660    ByProvider,
  661}
  662
  663pub enum EditPredictionPreview {
  664    /// Modifier is not pressed
  665    Inactive { released_too_fast: bool },
  666    /// Modifier pressed
  667    Active {
  668        since: Instant,
  669        previous_scroll_position: Option<ScrollAnchor>,
  670    },
  671}
  672
  673impl EditPredictionPreview {
  674    pub fn released_too_fast(&self) -> bool {
  675        match self {
  676            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  677            EditPredictionPreview::Active { .. } => false,
  678        }
  679    }
  680
  681    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  682        if let EditPredictionPreview::Active {
  683            previous_scroll_position,
  684            ..
  685        } = self
  686        {
  687            *previous_scroll_position = scroll_position;
  688        }
  689    }
  690}
  691
  692pub struct ContextMenuOptions {
  693    pub min_entries_visible: usize,
  694    pub max_entries_visible: usize,
  695    pub placement: Option<ContextMenuPlacement>,
  696}
  697
  698#[derive(Debug, Clone, PartialEq, Eq)]
  699pub enum ContextMenuPlacement {
  700    Above,
  701    Below,
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  705struct EditorActionId(usize);
  706
  707impl EditorActionId {
  708    pub fn post_inc(&mut self) -> Self {
  709        let answer = self.0;
  710
  711        *self = Self(answer + 1);
  712
  713        Self(answer)
  714    }
  715}
  716
  717// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  718// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  719
  720type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  721type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  722
  723#[derive(Default)]
  724struct ScrollbarMarkerState {
  725    scrollbar_size: Size<Pixels>,
  726    dirty: bool,
  727    markers: Arc<[PaintQuad]>,
  728    pending_refresh: Option<Task<Result<()>>>,
  729}
  730
  731impl ScrollbarMarkerState {
  732    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  733        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  734    }
  735}
  736
  737#[derive(Clone, Copy, PartialEq, Eq)]
  738pub enum MinimapVisibility {
  739    Disabled,
  740    Enabled {
  741        /// The configuration currently present in the users settings.
  742        setting_configuration: bool,
  743        /// Whether to override the currently set visibility from the users setting.
  744        toggle_override: bool,
  745    },
  746}
  747
  748impl MinimapVisibility {
  749    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  750        if mode.is_full() {
  751            Self::Enabled {
  752                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  753                toggle_override: false,
  754            }
  755        } else {
  756            Self::Disabled
  757        }
  758    }
  759
  760    fn hidden(&self) -> Self {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => Self::Enabled {
  766                setting_configuration,
  767                toggle_override: setting_configuration,
  768            },
  769            Self::Disabled => Self::Disabled,
  770        }
  771    }
  772
  773    fn disabled(&self) -> bool {
  774        match *self {
  775            Self::Disabled => true,
  776            _ => false,
  777        }
  778    }
  779
  780    fn settings_visibility(&self) -> bool {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => setting_configuration,
  786            _ => false,
  787        }
  788    }
  789
  790    fn visible(&self) -> bool {
  791        match *self {
  792            Self::Enabled {
  793                setting_configuration,
  794                toggle_override,
  795            } => setting_configuration ^ toggle_override,
  796            _ => false,
  797        }
  798    }
  799
  800    fn toggle_visibility(&self) -> Self {
  801        match *self {
  802            Self::Enabled {
  803                toggle_override,
  804                setting_configuration,
  805            } => Self::Enabled {
  806                setting_configuration,
  807                toggle_override: !toggle_override,
  808            },
  809            Self::Disabled => Self::Disabled,
  810        }
  811    }
  812}
  813
  814#[derive(Clone, Debug)]
  815struct RunnableTasks {
  816    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  817    offset: multi_buffer::Anchor,
  818    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  819    column: u32,
  820    // Values of all named captures, including those starting with '_'
  821    extra_variables: HashMap<String, String>,
  822    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  823    context_range: Range<BufferOffset>,
  824}
  825
  826impl RunnableTasks {
  827    fn resolve<'a>(
  828        &'a self,
  829        cx: &'a task::TaskContext,
  830    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  831        self.templates.iter().filter_map(|(kind, template)| {
  832            template
  833                .resolve_task(&kind.to_id_base(), cx)
  834                .map(|task| (kind.clone(), task))
  835        })
  836    }
  837}
  838
  839#[derive(Clone)]
  840pub struct ResolvedTasks {
  841    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  842    position: Anchor,
  843}
  844
  845#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  846struct BufferOffset(usize);
  847
  848// Addons allow storing per-editor state in other crates (e.g. Vim)
  849pub trait Addon: 'static {
  850    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  851
  852    fn render_buffer_header_controls(
  853        &self,
  854        _: &ExcerptInfo,
  855        _: &Window,
  856        _: &App,
  857    ) -> Option<AnyElement> {
  858        None
  859    }
  860
  861    fn to_any(&self) -> &dyn std::any::Any;
  862
  863    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  864        None
  865    }
  866}
  867
  868struct ChangeLocation {
  869    current: Option<Vec<Anchor>>,
  870    original: Vec<Anchor>,
  871}
  872impl ChangeLocation {
  873    fn locations(&self) -> &[Anchor] {
  874        self.current.as_ref().unwrap_or(&self.original)
  875    }
  876}
  877
  878/// A set of caret positions, registered when the editor was edited.
  879pub struct ChangeList {
  880    changes: Vec<ChangeLocation>,
  881    /// Currently "selected" change.
  882    position: Option<usize>,
  883}
  884
  885impl ChangeList {
  886    pub fn new() -> Self {
  887        Self {
  888            changes: Vec::new(),
  889            position: None,
  890        }
  891    }
  892
  893    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  894    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  895    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  896        if self.changes.is_empty() {
  897            return None;
  898        }
  899
  900        let prev = self.position.unwrap_or(self.changes.len());
  901        let next = if direction == Direction::Prev {
  902            prev.saturating_sub(count)
  903        } else {
  904            (prev + count).min(self.changes.len() - 1)
  905        };
  906        self.position = Some(next);
  907        self.changes.get(next).map(|change| change.locations())
  908    }
  909
  910    /// Adds a new change to the list, resetting the change list position.
  911    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  912        self.position.take();
  913        if let Some(last) = self.changes.last_mut()
  914            && group
  915        {
  916            last.current = Some(new_positions)
  917        } else {
  918            self.changes.push(ChangeLocation {
  919                original: new_positions,
  920                current: None,
  921            });
  922        }
  923    }
  924
  925    pub fn last(&self) -> Option<&[Anchor]> {
  926        self.changes.last().map(|change| change.locations())
  927    }
  928
  929    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  930        self.changes.last().map(|change| change.original.as_slice())
  931    }
  932
  933    pub fn invert_last_group(&mut self) {
  934        if let Some(last) = self.changes.last_mut() {
  935            if let Some(current) = last.current.as_mut() {
  936                mem::swap(&mut last.original, current);
  937            }
  938        }
  939    }
  940}
  941
  942#[derive(Clone)]
  943struct InlineBlamePopoverState {
  944    scroll_handle: ScrollHandle,
  945    commit_message: Option<ParsedCommitMessage>,
  946    markdown: Entity<Markdown>,
  947}
  948
  949struct InlineBlamePopover {
  950    position: gpui::Point<Pixels>,
  951    hide_task: Option<Task<()>>,
  952    popover_bounds: Option<Bounds<Pixels>>,
  953    popover_state: InlineBlamePopoverState,
  954    keyboard_grace: bool,
  955}
  956
  957enum SelectionDragState {
  958    /// State when no drag related activity is detected.
  959    None,
  960    /// State when the mouse is down on a selection that is about to be dragged.
  961    ReadyToDrag {
  962        selection: Selection<Anchor>,
  963        click_position: gpui::Point<Pixels>,
  964        mouse_down_time: Instant,
  965    },
  966    /// State when the mouse is dragging the selection in the editor.
  967    Dragging {
  968        selection: Selection<Anchor>,
  969        drop_cursor: Selection<Anchor>,
  970        hide_drop_cursor: bool,
  971    },
  972}
  973
  974enum ColumnarSelectionState {
  975    FromMouse {
  976        selection_tail: Anchor,
  977        display_point: Option<DisplayPoint>,
  978    },
  979    FromSelection {
  980        selection_tail: Anchor,
  981    },
  982}
  983
  984/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  985/// a breakpoint on them.
  986#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  987struct PhantomBreakpointIndicator {
  988    display_row: DisplayRow,
  989    /// There's a small debounce between hovering over the line and showing the indicator.
  990    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  991    is_active: bool,
  992    collides_with_existing_breakpoint: bool,
  993}
  994
  995/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  996///
  997/// See the [module level documentation](self) for more information.
  998pub struct Editor {
  999    focus_handle: FocusHandle,
 1000    last_focused_descendant: Option<WeakFocusHandle>,
 1001    /// The text buffer being edited
 1002    buffer: Entity<MultiBuffer>,
 1003    /// Map of how text in the buffer should be displayed.
 1004    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1005    pub display_map: Entity<DisplayMap>,
 1006    pub selections: SelectionsCollection,
 1007    pub scroll_manager: ScrollManager,
 1008    /// When inline assist editors are linked, they all render cursors because
 1009    /// typing enters text into each of them, even the ones that aren't focused.
 1010    pub(crate) show_cursor_when_unfocused: bool,
 1011    columnar_selection_state: Option<ColumnarSelectionState>,
 1012    add_selections_state: Option<AddSelectionsState>,
 1013    select_next_state: Option<SelectNextState>,
 1014    select_prev_state: Option<SelectNextState>,
 1015    selection_history: SelectionHistory,
 1016    defer_selection_effects: bool,
 1017    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1018    autoclose_regions: Vec<AutocloseRegion>,
 1019    snippet_stack: InvalidationStack<SnippetState>,
 1020    select_syntax_node_history: SelectSyntaxNodeHistory,
 1021    ime_transaction: Option<TransactionId>,
 1022    pub diagnostics_max_severity: DiagnosticSeverity,
 1023    active_diagnostics: ActiveDiagnostic,
 1024    show_inline_diagnostics: bool,
 1025    inline_diagnostics_update: Task<()>,
 1026    inline_diagnostics_enabled: bool,
 1027    diagnostics_enabled: bool,
 1028    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1029    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1030    hard_wrap: Option<usize>,
 1031
 1032    // TODO: make this a access method
 1033    pub project: Option<Entity<Project>>,
 1034    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1035    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1036    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1037    blink_manager: Entity<BlinkManager>,
 1038    show_cursor_names: bool,
 1039    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1040    pub show_local_selections: bool,
 1041    mode: EditorMode,
 1042    show_breadcrumbs: bool,
 1043    show_gutter: bool,
 1044    show_scrollbars: ScrollbarAxes,
 1045    minimap_visibility: MinimapVisibility,
 1046    offset_content: bool,
 1047    disable_expand_excerpt_buttons: bool,
 1048    show_line_numbers: Option<bool>,
 1049    use_relative_line_numbers: Option<bool>,
 1050    show_git_diff_gutter: Option<bool>,
 1051    show_code_actions: Option<bool>,
 1052    show_runnables: Option<bool>,
 1053    show_breakpoints: Option<bool>,
 1054    show_wrap_guides: Option<bool>,
 1055    show_indent_guides: Option<bool>,
 1056    placeholder_text: Option<Arc<str>>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_inline_completion: Option<InlineCompletionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    inline_completions_hidden_for_vim_mode: bool,
 1104    show_inline_completions_override: Option<bool>,
 1105    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177}
 1178
 1179#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1180enum NextScrollCursorCenterTopBottom {
 1181    #[default]
 1182    Center,
 1183    Top,
 1184    Bottom,
 1185}
 1186
 1187impl NextScrollCursorCenterTopBottom {
 1188    fn next(&self) -> Self {
 1189        match self {
 1190            Self::Center => Self::Top,
 1191            Self::Top => Self::Bottom,
 1192            Self::Bottom => Self::Center,
 1193        }
 1194    }
 1195}
 1196
 1197#[derive(Clone)]
 1198pub struct EditorSnapshot {
 1199    pub mode: EditorMode,
 1200    show_gutter: bool,
 1201    show_line_numbers: Option<bool>,
 1202    show_git_diff_gutter: Option<bool>,
 1203    show_code_actions: Option<bool>,
 1204    show_runnables: Option<bool>,
 1205    show_breakpoints: Option<bool>,
 1206    git_blame_gutter_max_author_length: Option<usize>,
 1207    pub display_snapshot: DisplaySnapshot,
 1208    pub placeholder_text: Option<Arc<str>>,
 1209    is_focused: bool,
 1210    scroll_anchor: ScrollAnchor,
 1211    ongoing_scroll: OngoingScroll,
 1212    current_line_highlight: CurrentLineHighlight,
 1213    gutter_hovered: bool,
 1214}
 1215
 1216#[derive(Default, Debug, Clone, Copy)]
 1217pub struct GutterDimensions {
 1218    pub left_padding: Pixels,
 1219    pub right_padding: Pixels,
 1220    pub width: Pixels,
 1221    pub margin: Pixels,
 1222    pub git_blame_entries_width: Option<Pixels>,
 1223}
 1224
 1225impl GutterDimensions {
 1226    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1227        Self {
 1228            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1229            ..Default::default()
 1230        }
 1231    }
 1232
 1233    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1234        -cx.text_system().descent(font_id, font_size)
 1235    }
 1236    /// The full width of the space taken up by the gutter.
 1237    pub fn full_width(&self) -> Pixels {
 1238        self.margin + self.width
 1239    }
 1240
 1241    /// The width of the space reserved for the fold indicators,
 1242    /// use alongside 'justify_end' and `gutter_width` to
 1243    /// right align content with the line numbers
 1244    pub fn fold_area_width(&self) -> Pixels {
 1245        self.margin + self.right_padding
 1246    }
 1247}
 1248
 1249struct CharacterDimensions {
 1250    em_width: Pixels,
 1251    em_advance: Pixels,
 1252    line_height: Pixels,
 1253}
 1254
 1255#[derive(Debug)]
 1256pub struct RemoteSelection {
 1257    pub replica_id: ReplicaId,
 1258    pub selection: Selection<Anchor>,
 1259    pub cursor_shape: CursorShape,
 1260    pub collaborator_id: CollaboratorId,
 1261    pub line_mode: bool,
 1262    pub user_name: Option<SharedString>,
 1263    pub color: PlayerColor,
 1264}
 1265
 1266#[derive(Clone, Debug)]
 1267struct SelectionHistoryEntry {
 1268    selections: Arc<[Selection<Anchor>]>,
 1269    select_next_state: Option<SelectNextState>,
 1270    select_prev_state: Option<SelectNextState>,
 1271    add_selections_state: Option<AddSelectionsState>,
 1272}
 1273
 1274#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1275enum SelectionHistoryMode {
 1276    Normal,
 1277    Undoing,
 1278    Redoing,
 1279    Skipping,
 1280}
 1281
 1282#[derive(Clone, PartialEq, Eq, Hash)]
 1283struct HoveredCursor {
 1284    replica_id: u16,
 1285    selection_id: usize,
 1286}
 1287
 1288impl Default for SelectionHistoryMode {
 1289    fn default() -> Self {
 1290        Self::Normal
 1291    }
 1292}
 1293
 1294#[derive(Debug)]
 1295/// SelectionEffects controls the side-effects of updating the selection.
 1296///
 1297/// The default behaviour does "what you mostly want":
 1298/// - it pushes to the nav history if the cursor moved by >10 lines
 1299/// - it re-triggers completion requests
 1300/// - it scrolls to fit
 1301///
 1302/// You might want to modify these behaviours. For example when doing a "jump"
 1303/// like go to definition, we always want to add to nav history; but when scrolling
 1304/// in vim mode we never do.
 1305///
 1306/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1307/// move.
 1308pub struct SelectionEffects {
 1309    nav_history: Option<bool>,
 1310    completions: bool,
 1311    scroll: Option<Autoscroll>,
 1312}
 1313
 1314impl Default for SelectionEffects {
 1315    fn default() -> Self {
 1316        Self {
 1317            nav_history: None,
 1318            completions: true,
 1319            scroll: Some(Autoscroll::fit()),
 1320        }
 1321    }
 1322}
 1323impl SelectionEffects {
 1324    pub fn scroll(scroll: Autoscroll) -> Self {
 1325        Self {
 1326            scroll: Some(scroll),
 1327            ..Default::default()
 1328        }
 1329    }
 1330
 1331    pub fn no_scroll() -> Self {
 1332        Self {
 1333            scroll: None,
 1334            ..Default::default()
 1335        }
 1336    }
 1337
 1338    pub fn completions(self, completions: bool) -> Self {
 1339        Self {
 1340            completions,
 1341            ..self
 1342        }
 1343    }
 1344
 1345    pub fn nav_history(self, nav_history: bool) -> Self {
 1346        Self {
 1347            nav_history: Some(nav_history),
 1348            ..self
 1349        }
 1350    }
 1351}
 1352
 1353struct DeferredSelectionEffectsState {
 1354    changed: bool,
 1355    effects: SelectionEffects,
 1356    old_cursor_position: Anchor,
 1357    history_entry: SelectionHistoryEntry,
 1358}
 1359
 1360#[derive(Default)]
 1361struct SelectionHistory {
 1362    #[allow(clippy::type_complexity)]
 1363    selections_by_transaction:
 1364        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1365    mode: SelectionHistoryMode,
 1366    undo_stack: VecDeque<SelectionHistoryEntry>,
 1367    redo_stack: VecDeque<SelectionHistoryEntry>,
 1368}
 1369
 1370impl SelectionHistory {
 1371    #[track_caller]
 1372    fn insert_transaction(
 1373        &mut self,
 1374        transaction_id: TransactionId,
 1375        selections: Arc<[Selection<Anchor>]>,
 1376    ) {
 1377        if selections.is_empty() {
 1378            log::error!(
 1379                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1380                std::panic::Location::caller()
 1381            );
 1382            return;
 1383        }
 1384        self.selections_by_transaction
 1385            .insert(transaction_id, (selections, None));
 1386    }
 1387
 1388    #[allow(clippy::type_complexity)]
 1389    fn transaction(
 1390        &self,
 1391        transaction_id: TransactionId,
 1392    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1393        self.selections_by_transaction.get(&transaction_id)
 1394    }
 1395
 1396    #[allow(clippy::type_complexity)]
 1397    fn transaction_mut(
 1398        &mut self,
 1399        transaction_id: TransactionId,
 1400    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1401        self.selections_by_transaction.get_mut(&transaction_id)
 1402    }
 1403
 1404    fn push(&mut self, entry: SelectionHistoryEntry) {
 1405        if !entry.selections.is_empty() {
 1406            match self.mode {
 1407                SelectionHistoryMode::Normal => {
 1408                    self.push_undo(entry);
 1409                    self.redo_stack.clear();
 1410                }
 1411                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1412                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1413                SelectionHistoryMode::Skipping => {}
 1414            }
 1415        }
 1416    }
 1417
 1418    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1419        if self
 1420            .undo_stack
 1421            .back()
 1422            .map_or(true, |e| e.selections != entry.selections)
 1423        {
 1424            self.undo_stack.push_back(entry);
 1425            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1426                self.undo_stack.pop_front();
 1427            }
 1428        }
 1429    }
 1430
 1431    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1432        if self
 1433            .redo_stack
 1434            .back()
 1435            .map_or(true, |e| e.selections != entry.selections)
 1436        {
 1437            self.redo_stack.push_back(entry);
 1438            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1439                self.redo_stack.pop_front();
 1440            }
 1441        }
 1442    }
 1443}
 1444
 1445#[derive(Clone, Copy)]
 1446pub struct RowHighlightOptions {
 1447    pub autoscroll: bool,
 1448    pub include_gutter: bool,
 1449}
 1450
 1451impl Default for RowHighlightOptions {
 1452    fn default() -> Self {
 1453        Self {
 1454            autoscroll: Default::default(),
 1455            include_gutter: true,
 1456        }
 1457    }
 1458}
 1459
 1460struct RowHighlight {
 1461    index: usize,
 1462    range: Range<Anchor>,
 1463    color: Hsla,
 1464    options: RowHighlightOptions,
 1465    type_id: TypeId,
 1466}
 1467
 1468#[derive(Clone, Debug)]
 1469struct AddSelectionsState {
 1470    groups: Vec<AddSelectionsGroup>,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsGroup {
 1475    above: bool,
 1476    stack: Vec<usize>,
 1477}
 1478
 1479#[derive(Clone)]
 1480struct SelectNextState {
 1481    query: AhoCorasick,
 1482    wordwise: bool,
 1483    done: bool,
 1484}
 1485
 1486impl std::fmt::Debug for SelectNextState {
 1487    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1488        f.debug_struct(std::any::type_name::<Self>())
 1489            .field("wordwise", &self.wordwise)
 1490            .field("done", &self.done)
 1491            .finish()
 1492    }
 1493}
 1494
 1495#[derive(Debug)]
 1496struct AutocloseRegion {
 1497    selection_id: usize,
 1498    range: Range<Anchor>,
 1499    pair: BracketPair,
 1500}
 1501
 1502#[derive(Debug)]
 1503struct SnippetState {
 1504    ranges: Vec<Vec<Range<Anchor>>>,
 1505    active_index: usize,
 1506    choices: Vec<Option<Vec<String>>>,
 1507}
 1508
 1509#[doc(hidden)]
 1510pub struct RenameState {
 1511    pub range: Range<Anchor>,
 1512    pub old_name: Arc<str>,
 1513    pub editor: Entity<Editor>,
 1514    block_id: CustomBlockId,
 1515}
 1516
 1517struct InvalidationStack<T>(Vec<T>);
 1518
 1519struct RegisteredInlineCompletionProvider {
 1520    provider: Arc<dyn InlineCompletionProviderHandle>,
 1521    _subscription: Subscription,
 1522}
 1523
 1524#[derive(Debug, PartialEq, Eq)]
 1525pub struct ActiveDiagnosticGroup {
 1526    pub active_range: Range<Anchor>,
 1527    pub active_message: String,
 1528    pub group_id: usize,
 1529    pub blocks: HashSet<CustomBlockId>,
 1530}
 1531
 1532#[derive(Debug, PartialEq, Eq)]
 1533
 1534pub(crate) enum ActiveDiagnostic {
 1535    None,
 1536    All,
 1537    Group(ActiveDiagnosticGroup),
 1538}
 1539
 1540#[derive(Serialize, Deserialize, Clone, Debug)]
 1541pub struct ClipboardSelection {
 1542    /// The number of bytes in this selection.
 1543    pub len: usize,
 1544    /// Whether this was a full-line selection.
 1545    pub is_entire_line: bool,
 1546    /// The indentation of the first line when this content was originally copied.
 1547    pub first_line_indent: u32,
 1548}
 1549
 1550// selections, scroll behavior, was newest selection reversed
 1551type SelectSyntaxNodeHistoryState = (
 1552    Box<[Selection<usize>]>,
 1553    SelectSyntaxNodeScrollBehavior,
 1554    bool,
 1555);
 1556
 1557#[derive(Default)]
 1558struct SelectSyntaxNodeHistory {
 1559    stack: Vec<SelectSyntaxNodeHistoryState>,
 1560    // disable temporarily to allow changing selections without losing the stack
 1561    pub disable_clearing: bool,
 1562}
 1563
 1564impl SelectSyntaxNodeHistory {
 1565    pub fn try_clear(&mut self) {
 1566        if !self.disable_clearing {
 1567            self.stack.clear();
 1568        }
 1569    }
 1570
 1571    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1572        self.stack.push(selection);
 1573    }
 1574
 1575    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1576        self.stack.pop()
 1577    }
 1578}
 1579
 1580enum SelectSyntaxNodeScrollBehavior {
 1581    CursorTop,
 1582    FitSelection,
 1583    CursorBottom,
 1584}
 1585
 1586#[derive(Debug)]
 1587pub(crate) struct NavigationData {
 1588    cursor_anchor: Anchor,
 1589    cursor_position: Point,
 1590    scroll_anchor: ScrollAnchor,
 1591    scroll_top_row: u32,
 1592}
 1593
 1594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1595pub enum GotoDefinitionKind {
 1596    Symbol,
 1597    Declaration,
 1598    Type,
 1599    Implementation,
 1600}
 1601
 1602#[derive(Debug, Clone)]
 1603enum InlayHintRefreshReason {
 1604    ModifiersChanged(bool),
 1605    Toggle(bool),
 1606    SettingsChange(InlayHintSettings),
 1607    NewLinesShown,
 1608    BufferEdited(HashSet<Arc<Language>>),
 1609    RefreshRequested,
 1610    ExcerptsRemoved(Vec<ExcerptId>),
 1611}
 1612
 1613impl InlayHintRefreshReason {
 1614    fn description(&self) -> &'static str {
 1615        match self {
 1616            Self::ModifiersChanged(_) => "modifiers changed",
 1617            Self::Toggle(_) => "toggle",
 1618            Self::SettingsChange(_) => "settings change",
 1619            Self::NewLinesShown => "new lines shown",
 1620            Self::BufferEdited(_) => "buffer edited",
 1621            Self::RefreshRequested => "refresh requested",
 1622            Self::ExcerptsRemoved(_) => "excerpts removed",
 1623        }
 1624    }
 1625}
 1626
 1627pub enum FormatTarget {
 1628    Buffers(HashSet<Entity<Buffer>>),
 1629    Ranges(Vec<Range<MultiBufferPoint>>),
 1630}
 1631
 1632pub(crate) struct FocusedBlock {
 1633    id: BlockId,
 1634    focus_handle: WeakFocusHandle,
 1635}
 1636
 1637#[derive(Clone)]
 1638enum JumpData {
 1639    MultiBufferRow {
 1640        row: MultiBufferRow,
 1641        line_offset_from_top: u32,
 1642    },
 1643    MultiBufferPoint {
 1644        excerpt_id: ExcerptId,
 1645        position: Point,
 1646        anchor: text::Anchor,
 1647        line_offset_from_top: u32,
 1648    },
 1649}
 1650
 1651pub enum MultibufferSelectionMode {
 1652    First,
 1653    All,
 1654}
 1655
 1656#[derive(Clone, Copy, Debug, Default)]
 1657pub struct RewrapOptions {
 1658    pub override_language_settings: bool,
 1659    pub preserve_existing_whitespace: bool,
 1660}
 1661
 1662impl Editor {
 1663    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1664        let buffer = cx.new(|cx| Buffer::local("", cx));
 1665        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1666        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1667    }
 1668
 1669    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::full(), buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn auto_height(
 1676        min_lines: usize,
 1677        max_lines: usize,
 1678        window: &mut Window,
 1679        cx: &mut Context<Self>,
 1680    ) -> Self {
 1681        let buffer = cx.new(|cx| Buffer::local("", cx));
 1682        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1683        Self::new(
 1684            EditorMode::AutoHeight {
 1685                min_lines,
 1686                max_lines: Some(max_lines),
 1687            },
 1688            buffer,
 1689            None,
 1690            window,
 1691            cx,
 1692        )
 1693    }
 1694
 1695    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1696    /// The editor grows as tall as needed to fit its content.
 1697    pub fn auto_height_unbounded(
 1698        min_lines: usize,
 1699        window: &mut Window,
 1700        cx: &mut Context<Self>,
 1701    ) -> Self {
 1702        let buffer = cx.new(|cx| Buffer::local("", cx));
 1703        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1704        Self::new(
 1705            EditorMode::AutoHeight {
 1706                min_lines,
 1707                max_lines: None,
 1708            },
 1709            buffer,
 1710            None,
 1711            window,
 1712            cx,
 1713        )
 1714    }
 1715
 1716    pub fn for_buffer(
 1717        buffer: Entity<Buffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1723        Self::new(EditorMode::full(), buffer, project, window, cx)
 1724    }
 1725
 1726    pub fn for_multibuffer(
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Self::new(EditorMode::full(), buffer, project, window, cx)
 1733    }
 1734
 1735    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1736        let mut clone = Self::new(
 1737            self.mode.clone(),
 1738            self.buffer.clone(),
 1739            self.project.clone(),
 1740            window,
 1741            cx,
 1742        );
 1743        self.display_map.update(cx, |display_map, cx| {
 1744            let snapshot = display_map.snapshot(cx);
 1745            clone.display_map.update(cx, |display_map, cx| {
 1746                display_map.set_state(&snapshot, cx);
 1747            });
 1748        });
 1749        clone.folds_did_change(cx);
 1750        clone.selections.clone_state(&self.selections);
 1751        clone.scroll_manager.clone_state(&self.scroll_manager);
 1752        clone.searchable = self.searchable;
 1753        clone.read_only = self.read_only;
 1754        clone
 1755    }
 1756
 1757    pub fn new(
 1758        mode: EditorMode,
 1759        buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        window: &mut Window,
 1762        cx: &mut Context<Self>,
 1763    ) -> Self {
 1764        Editor::new_internal(mode, buffer, project, None, window, cx)
 1765    }
 1766
 1767    fn new_internal(
 1768        mode: EditorMode,
 1769        buffer: Entity<MultiBuffer>,
 1770        project: Option<Entity<Project>>,
 1771        display_map: Option<Entity<DisplayMap>>,
 1772        window: &mut Window,
 1773        cx: &mut Context<Self>,
 1774    ) -> Self {
 1775        debug_assert!(
 1776            display_map.is_none() || mode.is_minimap(),
 1777            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1778        );
 1779
 1780        let full_mode = mode.is_full();
 1781        let is_minimap = mode.is_minimap();
 1782        let diagnostics_max_severity = if full_mode {
 1783            EditorSettings::get_global(cx)
 1784                .diagnostics_max_severity
 1785                .unwrap_or(DiagnosticSeverity::Hint)
 1786        } else {
 1787            DiagnosticSeverity::Off
 1788        };
 1789        let style = window.text_style();
 1790        let font_size = style.font_size.to_pixels(window.rem_size());
 1791        let editor = cx.entity().downgrade();
 1792        let fold_placeholder = FoldPlaceholder {
 1793            constrain_width: true,
 1794            render: Arc::new(move |fold_id, fold_range, cx| {
 1795                let editor = editor.clone();
 1796                div()
 1797                    .id(fold_id)
 1798                    .bg(cx.theme().colors().ghost_element_background)
 1799                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1800                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1801                    .rounded_xs()
 1802                    .size_full()
 1803                    .cursor_pointer()
 1804                    .child("")
 1805                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1806                    .on_click(move |_, _window, cx| {
 1807                        editor
 1808                            .update(cx, |editor, cx| {
 1809                                editor.unfold_ranges(
 1810                                    &[fold_range.start..fold_range.end],
 1811                                    true,
 1812                                    false,
 1813                                    cx,
 1814                                );
 1815                                cx.stop_propagation();
 1816                            })
 1817                            .ok();
 1818                    })
 1819                    .into_any()
 1820            }),
 1821            merge_adjacent: true,
 1822            ..FoldPlaceholder::default()
 1823        };
 1824        let display_map = display_map.unwrap_or_else(|| {
 1825            cx.new(|cx| {
 1826                DisplayMap::new(
 1827                    buffer.clone(),
 1828                    style.font(),
 1829                    font_size,
 1830                    None,
 1831                    FILE_HEADER_HEIGHT,
 1832                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1833                    fold_placeholder,
 1834                    diagnostics_max_severity,
 1835                    cx,
 1836                )
 1837            })
 1838        });
 1839
 1840        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1841
 1842        let blink_manager = cx.new(|cx| {
 1843            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1844            if is_minimap {
 1845                blink_manager.disable(cx);
 1846            }
 1847            blink_manager
 1848        });
 1849
 1850        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1851            .then(|| language_settings::SoftWrap::None);
 1852
 1853        let mut project_subscriptions = Vec::new();
 1854        if full_mode {
 1855            if let Some(project) = project.as_ref() {
 1856                project_subscriptions.push(cx.subscribe_in(
 1857                    project,
 1858                    window,
 1859                    |editor, _, event, window, cx| match event {
 1860                        project::Event::RefreshCodeLens => {
 1861                            // we always query lens with actions, without storing them, always refreshing them
 1862                        }
 1863                        project::Event::RefreshInlayHints => {
 1864                            editor
 1865                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                        }
 1867                        project::Event::LanguageServerAdded(..)
 1868                        | project::Event::LanguageServerRemoved(..) => {
 1869                            if editor.tasks_update_task.is_none() {
 1870                                editor.tasks_update_task =
 1871                                    Some(editor.refresh_runnables(window, cx));
 1872                            }
 1873                            editor.update_lsp_data(true, None, window, cx);
 1874                        }
 1875                        project::Event::SnippetEdit(id, snippet_edits) => {
 1876                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                                let focus_handle = editor.focus_handle(cx);
 1878                                if focus_handle.is_focused(window) {
 1879                                    let snapshot = buffer.read(cx).snapshot();
 1880                                    for (range, snippet) in snippet_edits {
 1881                                        let editor_range =
 1882                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                        editor
 1884                                            .insert_snippet(
 1885                                                &[editor_range],
 1886                                                snippet.clone(),
 1887                                                window,
 1888                                                cx,
 1889                                            )
 1890                                            .ok();
 1891                                    }
 1892                                }
 1893                            }
 1894                        }
 1895                        _ => {}
 1896                    },
 1897                ));
 1898                if let Some(task_inventory) = project
 1899                    .read(cx)
 1900                    .task_store()
 1901                    .read(cx)
 1902                    .task_inventory()
 1903                    .cloned()
 1904                {
 1905                    project_subscriptions.push(cx.observe_in(
 1906                        &task_inventory,
 1907                        window,
 1908                        |editor, _, window, cx| {
 1909                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1910                        },
 1911                    ));
 1912                };
 1913
 1914                project_subscriptions.push(cx.subscribe_in(
 1915                    &project.read(cx).breakpoint_store(),
 1916                    window,
 1917                    |editor, _, event, window, cx| match event {
 1918                        BreakpointStoreEvent::ClearDebugLines => {
 1919                            editor.clear_row_highlights::<ActiveDebugLine>();
 1920                            editor.refresh_inline_values(cx);
 1921                        }
 1922                        BreakpointStoreEvent::SetDebugLine => {
 1923                            if editor.go_to_active_debug_line(window, cx) {
 1924                                cx.stop_propagation();
 1925                            }
 1926
 1927                            editor.refresh_inline_values(cx);
 1928                        }
 1929                        _ => {}
 1930                    },
 1931                ));
 1932                let git_store = project.read(cx).git_store().clone();
 1933                let project = project.clone();
 1934                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1935                    match event {
 1936                        GitStoreEvent::RepositoryUpdated(
 1937                            _,
 1938                            RepositoryEvent::Updated {
 1939                                new_instance: true, ..
 1940                            },
 1941                            _,
 1942                        ) => {
 1943                            this.load_diff_task = Some(
 1944                                update_uncommitted_diff_for_buffer(
 1945                                    cx.entity(),
 1946                                    &project,
 1947                                    this.buffer.read(cx).all_buffers(),
 1948                                    this.buffer.clone(),
 1949                                    cx,
 1950                                )
 1951                                .shared(),
 1952                            );
 1953                        }
 1954                        _ => {}
 1955                    }
 1956                }));
 1957            }
 1958        }
 1959
 1960        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1961
 1962        let inlay_hint_settings =
 1963            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1964        let focus_handle = cx.focus_handle();
 1965        if !is_minimap {
 1966            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1967                .detach();
 1968            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1969                .detach();
 1970            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1971                .detach();
 1972            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1973                .detach();
 1974            cx.observe_pending_input(window, Self::observe_pending_input)
 1975                .detach();
 1976        }
 1977
 1978        let show_indent_guides = if matches!(
 1979            mode,
 1980            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1981        ) {
 1982            Some(false)
 1983        } else {
 1984            None
 1985        };
 1986
 1987        let breakpoint_store = match (&mode, project.as_ref()) {
 1988            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1989            _ => None,
 1990        };
 1991
 1992        let mut code_action_providers = Vec::new();
 1993        let mut load_uncommitted_diff = None;
 1994        if let Some(project) = project.clone() {
 1995            load_uncommitted_diff = Some(
 1996                update_uncommitted_diff_for_buffer(
 1997                    cx.entity(),
 1998                    &project,
 1999                    buffer.read(cx).all_buffers(),
 2000                    buffer.clone(),
 2001                    cx,
 2002                )
 2003                .shared(),
 2004            );
 2005            code_action_providers.push(Rc::new(project) as Rc<_>);
 2006        }
 2007
 2008        let mut editor = Self {
 2009            focus_handle,
 2010            show_cursor_when_unfocused: false,
 2011            last_focused_descendant: None,
 2012            buffer: buffer.clone(),
 2013            display_map: display_map.clone(),
 2014            selections,
 2015            scroll_manager: ScrollManager::new(cx),
 2016            columnar_selection_state: None,
 2017            add_selections_state: None,
 2018            select_next_state: None,
 2019            select_prev_state: None,
 2020            selection_history: SelectionHistory::default(),
 2021            defer_selection_effects: false,
 2022            deferred_selection_effects_state: None,
 2023            autoclose_regions: Vec::new(),
 2024            snippet_stack: InvalidationStack::default(),
 2025            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2026            ime_transaction: None,
 2027            active_diagnostics: ActiveDiagnostic::None,
 2028            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2029            inline_diagnostics_update: Task::ready(()),
 2030            inline_diagnostics: Vec::new(),
 2031            soft_wrap_mode_override,
 2032            diagnostics_max_severity,
 2033            hard_wrap: None,
 2034            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2035            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2036            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2037            project,
 2038            blink_manager: blink_manager.clone(),
 2039            show_local_selections: true,
 2040            show_scrollbars: ScrollbarAxes {
 2041                horizontal: full_mode,
 2042                vertical: full_mode,
 2043            },
 2044            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2045            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2046            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2047            show_gutter: full_mode,
 2048            show_line_numbers: (!full_mode).then_some(false),
 2049            use_relative_line_numbers: None,
 2050            disable_expand_excerpt_buttons: !full_mode,
 2051            show_git_diff_gutter: None,
 2052            show_code_actions: None,
 2053            show_runnables: None,
 2054            show_breakpoints: None,
 2055            show_wrap_guides: None,
 2056            show_indent_guides,
 2057            placeholder_text: None,
 2058            highlight_order: 0,
 2059            highlighted_rows: HashMap::default(),
 2060            background_highlights: TreeMap::default(),
 2061            gutter_highlights: TreeMap::default(),
 2062            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2063            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2064            nav_history: None,
 2065            context_menu: RefCell::new(None),
 2066            context_menu_options: None,
 2067            mouse_context_menu: None,
 2068            completion_tasks: Vec::new(),
 2069            inline_blame_popover: None,
 2070            inline_blame_popover_show_task: None,
 2071            signature_help_state: SignatureHelpState::default(),
 2072            auto_signature_help: None,
 2073            find_all_references_task_sources: Vec::new(),
 2074            next_completion_id: 0,
 2075            next_inlay_id: 0,
 2076            code_action_providers,
 2077            available_code_actions: None,
 2078            code_actions_task: None,
 2079            quick_selection_highlight_task: None,
 2080            debounced_selection_highlight_task: None,
 2081            document_highlights_task: None,
 2082            linked_editing_range_task: None,
 2083            pending_rename: None,
 2084            searchable: !is_minimap,
 2085            cursor_shape: EditorSettings::get_global(cx)
 2086                .cursor_shape
 2087                .unwrap_or_default(),
 2088            current_line_highlight: None,
 2089            autoindent_mode: Some(AutoindentMode::EachLine),
 2090            collapse_matches: false,
 2091            workspace: None,
 2092            input_enabled: !is_minimap,
 2093            use_modal_editing: full_mode,
 2094            read_only: is_minimap,
 2095            use_autoclose: true,
 2096            use_auto_surround: true,
 2097            auto_replace_emoji_shortcode: false,
 2098            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2099            leader_id: None,
 2100            remote_id: None,
 2101            hover_state: HoverState::default(),
 2102            pending_mouse_down: None,
 2103            hovered_link_state: None,
 2104            edit_prediction_provider: None,
 2105            active_inline_completion: None,
 2106            stale_inline_completion_in_menu: None,
 2107            edit_prediction_preview: EditPredictionPreview::Inactive {
 2108                released_too_fast: false,
 2109            },
 2110            inline_diagnostics_enabled: full_mode,
 2111            diagnostics_enabled: full_mode,
 2112            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2113            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2114            gutter_hovered: false,
 2115            pixel_position_of_newest_cursor: None,
 2116            last_bounds: None,
 2117            last_position_map: None,
 2118            expect_bounds_change: None,
 2119            gutter_dimensions: GutterDimensions::default(),
 2120            style: None,
 2121            show_cursor_names: false,
 2122            hovered_cursors: HashMap::default(),
 2123            next_editor_action_id: EditorActionId::default(),
 2124            editor_actions: Rc::default(),
 2125            inline_completions_hidden_for_vim_mode: false,
 2126            show_inline_completions_override: None,
 2127            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2128            edit_prediction_settings: EditPredictionSettings::Disabled,
 2129            edit_prediction_indent_conflict: false,
 2130            edit_prediction_requires_modifier_in_indent_conflict: true,
 2131            custom_context_menu: None,
 2132            show_git_blame_gutter: false,
 2133            show_git_blame_inline: false,
 2134            show_selection_menu: None,
 2135            show_git_blame_inline_delay_task: None,
 2136            git_blame_inline_enabled: full_mode
 2137                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2138            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2139            serialize_dirty_buffers: !is_minimap
 2140                && ProjectSettings::get_global(cx)
 2141                    .session
 2142                    .restore_unsaved_buffers,
 2143            blame: None,
 2144            blame_subscription: None,
 2145            tasks: BTreeMap::default(),
 2146
 2147            breakpoint_store,
 2148            gutter_breakpoint_indicator: (None, None),
 2149            hovered_diff_hunk_row: None,
 2150            _subscriptions: (!is_minimap)
 2151                .then(|| {
 2152                    vec![
 2153                        cx.observe(&buffer, Self::on_buffer_changed),
 2154                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2155                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2156                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2157                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2158                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2159                        cx.observe_window_activation(window, |editor, window, cx| {
 2160                            let active = window.is_window_active();
 2161                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2162                                if active {
 2163                                    blink_manager.enable(cx);
 2164                                } else {
 2165                                    blink_manager.disable(cx);
 2166                                }
 2167                            });
 2168                            if active {
 2169                                editor.show_mouse_cursor(cx);
 2170                            }
 2171                        }),
 2172                    ]
 2173                })
 2174                .unwrap_or_default(),
 2175            tasks_update_task: None,
 2176            pull_diagnostics_task: Task::ready(()),
 2177            colors: None,
 2178            next_color_inlay_id: 0,
 2179            linked_edit_ranges: Default::default(),
 2180            in_project_search: false,
 2181            previous_search_ranges: None,
 2182            breadcrumb_header: None,
 2183            focused_block: None,
 2184            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2185            addons: HashMap::default(),
 2186            registered_buffers: HashMap::default(),
 2187            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2188            selection_mark_mode: false,
 2189            toggle_fold_multiple_buffers: Task::ready(()),
 2190            serialize_selections: Task::ready(()),
 2191            serialize_folds: Task::ready(()),
 2192            text_style_refinement: None,
 2193            load_diff_task: load_uncommitted_diff,
 2194            temporary_diff_override: false,
 2195            mouse_cursor_hidden: false,
 2196            minimap: None,
 2197            hide_mouse_mode: EditorSettings::get_global(cx)
 2198                .hide_mouse
 2199                .unwrap_or_default(),
 2200            change_list: ChangeList::new(),
 2201            mode,
 2202            selection_drag_state: SelectionDragState::None,
 2203            folding_newlines: Task::ready(()),
 2204        };
 2205
 2206        if is_minimap {
 2207            return editor;
 2208        }
 2209
 2210        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2211            editor
 2212                ._subscriptions
 2213                .push(cx.observe(breakpoints, |_, _, cx| {
 2214                    cx.notify();
 2215                }));
 2216        }
 2217        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2218        editor._subscriptions.extend(project_subscriptions);
 2219
 2220        editor._subscriptions.push(cx.subscribe_in(
 2221            &cx.entity(),
 2222            window,
 2223            |editor, _, e: &EditorEvent, window, cx| match e {
 2224                EditorEvent::ScrollPositionChanged { local, .. } => {
 2225                    if *local {
 2226                        let new_anchor = editor.scroll_manager.anchor();
 2227                        let snapshot = editor.snapshot(window, cx);
 2228                        editor.update_restoration_data(cx, move |data| {
 2229                            data.scroll_position = (
 2230                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2231                                new_anchor.offset,
 2232                            );
 2233                        });
 2234                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2235                        editor.inline_blame_popover.take();
 2236                    }
 2237                }
 2238                EditorEvent::Edited { .. } => {
 2239                    if !vim_enabled(cx) {
 2240                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2241                        let pop_state = editor
 2242                            .change_list
 2243                            .last()
 2244                            .map(|previous| {
 2245                                previous.len() == selections.len()
 2246                                    && previous.iter().enumerate().all(|(ix, p)| {
 2247                                        p.to_display_point(&map).row()
 2248                                            == selections[ix].head().row()
 2249                                    })
 2250                            })
 2251                            .unwrap_or(false);
 2252                        let new_positions = selections
 2253                            .into_iter()
 2254                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2255                            .collect();
 2256                        editor
 2257                            .change_list
 2258                            .push_to_change_list(pop_state, new_positions);
 2259                    }
 2260                }
 2261                _ => (),
 2262            },
 2263        ));
 2264
 2265        if let Some(dap_store) = editor
 2266            .project
 2267            .as_ref()
 2268            .map(|project| project.read(cx).dap_store())
 2269        {
 2270            let weak_editor = cx.weak_entity();
 2271
 2272            editor
 2273                ._subscriptions
 2274                .push(
 2275                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2276                        let session_entity = cx.entity();
 2277                        weak_editor
 2278                            .update(cx, |editor, cx| {
 2279                                editor._subscriptions.push(
 2280                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2281                                );
 2282                            })
 2283                            .ok();
 2284                    }),
 2285                );
 2286
 2287            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2288                editor
 2289                    ._subscriptions
 2290                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2291            }
 2292        }
 2293
 2294        // skip adding the initial selection to selection history
 2295        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2296        editor.end_selection(window, cx);
 2297        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2298
 2299        editor.scroll_manager.show_scrollbars(window, cx);
 2300        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2301
 2302        if full_mode {
 2303            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2304            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2305
 2306            if editor.git_blame_inline_enabled {
 2307                editor.start_git_blame_inline(false, window, cx);
 2308            }
 2309
 2310            editor.go_to_active_debug_line(window, cx);
 2311
 2312            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2313                if let Some(project) = editor.project.as_ref() {
 2314                    let handle = project.update(cx, |project, cx| {
 2315                        project.register_buffer_with_language_servers(&buffer, cx)
 2316                    });
 2317                    editor
 2318                        .registered_buffers
 2319                        .insert(buffer.read(cx).remote_id(), handle);
 2320                }
 2321            }
 2322
 2323            editor.minimap =
 2324                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2325            editor.colors = Some(LspColorData::new(cx));
 2326            editor.update_lsp_data(false, None, window, cx);
 2327        }
 2328
 2329        if editor.mode.is_full() {
 2330            editor.report_editor_event("Editor Opened", None, cx);
 2331        }
 2332
 2333        editor
 2334    }
 2335
 2336    pub fn deploy_mouse_context_menu(
 2337        &mut self,
 2338        position: gpui::Point<Pixels>,
 2339        context_menu: Entity<ContextMenu>,
 2340        window: &mut Window,
 2341        cx: &mut Context<Self>,
 2342    ) {
 2343        self.mouse_context_menu = Some(MouseContextMenu::new(
 2344            self,
 2345            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2346            context_menu,
 2347            window,
 2348            cx,
 2349        ));
 2350    }
 2351
 2352    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2353        self.mouse_context_menu
 2354            .as_ref()
 2355            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2356    }
 2357
 2358    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2359        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2360    }
 2361
 2362    fn key_context_internal(
 2363        &self,
 2364        has_active_edit_prediction: bool,
 2365        window: &Window,
 2366        cx: &App,
 2367    ) -> KeyContext {
 2368        let mut key_context = KeyContext::new_with_defaults();
 2369        key_context.add("Editor");
 2370        let mode = match self.mode {
 2371            EditorMode::SingleLine { .. } => "single_line",
 2372            EditorMode::AutoHeight { .. } => "auto_height",
 2373            EditorMode::Minimap { .. } => "minimap",
 2374            EditorMode::Full { .. } => "full",
 2375        };
 2376
 2377        if EditorSettings::jupyter_enabled(cx) {
 2378            key_context.add("jupyter");
 2379        }
 2380
 2381        key_context.set("mode", mode);
 2382        if self.pending_rename.is_some() {
 2383            key_context.add("renaming");
 2384        }
 2385
 2386        match self.context_menu.borrow().as_ref() {
 2387            Some(CodeContextMenu::Completions(menu)) => {
 2388                if menu.visible() {
 2389                    key_context.add("menu");
 2390                    key_context.add("showing_completions");
 2391                }
 2392            }
 2393            Some(CodeContextMenu::CodeActions(menu)) => {
 2394                if menu.visible() {
 2395                    key_context.add("menu");
 2396                    key_context.add("showing_code_actions")
 2397                }
 2398            }
 2399            None => {}
 2400        }
 2401
 2402        if self.signature_help_state.has_multiple_signatures() {
 2403            key_context.add("showing_signature_help");
 2404        }
 2405
 2406        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2407        if !self.focus_handle(cx).contains_focused(window, cx)
 2408            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2409        {
 2410            for addon in self.addons.values() {
 2411                addon.extend_key_context(&mut key_context, cx)
 2412            }
 2413        }
 2414
 2415        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2416            if let Some(extension) = singleton_buffer
 2417                .read(cx)
 2418                .file()
 2419                .and_then(|file| file.path().extension()?.to_str())
 2420            {
 2421                key_context.set("extension", extension.to_string());
 2422            }
 2423        } else {
 2424            key_context.add("multibuffer");
 2425        }
 2426
 2427        if has_active_edit_prediction {
 2428            if self.edit_prediction_in_conflict() {
 2429                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2430            } else {
 2431                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2432                key_context.add("copilot_suggestion");
 2433            }
 2434        }
 2435
 2436        if self.selection_mark_mode {
 2437            key_context.add("selection_mode");
 2438        }
 2439
 2440        key_context
 2441    }
 2442
 2443    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2444        if self.mouse_cursor_hidden {
 2445            self.mouse_cursor_hidden = false;
 2446            cx.notify();
 2447        }
 2448    }
 2449
 2450    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2451        let hide_mouse_cursor = match origin {
 2452            HideMouseCursorOrigin::TypingAction => {
 2453                matches!(
 2454                    self.hide_mouse_mode,
 2455                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2456                )
 2457            }
 2458            HideMouseCursorOrigin::MovementAction => {
 2459                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2460            }
 2461        };
 2462        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2463            self.mouse_cursor_hidden = hide_mouse_cursor;
 2464            cx.notify();
 2465        }
 2466    }
 2467
 2468    pub fn edit_prediction_in_conflict(&self) -> bool {
 2469        if !self.show_edit_predictions_in_menu() {
 2470            return false;
 2471        }
 2472
 2473        let showing_completions = self
 2474            .context_menu
 2475            .borrow()
 2476            .as_ref()
 2477            .map_or(false, |context| {
 2478                matches!(context, CodeContextMenu::Completions(_))
 2479            });
 2480
 2481        showing_completions
 2482            || self.edit_prediction_requires_modifier()
 2483            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2484            // bindings to insert tab characters.
 2485            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2486    }
 2487
 2488    pub fn accept_edit_prediction_keybind(
 2489        &self,
 2490        accept_partial: bool,
 2491        window: &Window,
 2492        cx: &App,
 2493    ) -> AcceptEditPredictionBinding {
 2494        let key_context = self.key_context_internal(true, window, cx);
 2495        let in_conflict = self.edit_prediction_in_conflict();
 2496
 2497        let bindings = if accept_partial {
 2498            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2499        } else {
 2500            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2501        };
 2502
 2503        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2504        // just the first one.
 2505        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2506            !in_conflict
 2507                || binding
 2508                    .keystrokes()
 2509                    .first()
 2510                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2511        }))
 2512    }
 2513
 2514    pub fn new_file(
 2515        workspace: &mut Workspace,
 2516        _: &workspace::NewFile,
 2517        window: &mut Window,
 2518        cx: &mut Context<Workspace>,
 2519    ) {
 2520        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2521            "Failed to create buffer",
 2522            window,
 2523            cx,
 2524            |e, _, _| match e.error_code() {
 2525                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2526                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2527                e.error_tag("required").unwrap_or("the latest version")
 2528            )),
 2529                _ => None,
 2530            },
 2531        );
 2532    }
 2533
 2534    pub fn new_in_workspace(
 2535        workspace: &mut Workspace,
 2536        window: &mut Window,
 2537        cx: &mut Context<Workspace>,
 2538    ) -> Task<Result<Entity<Editor>>> {
 2539        let project = workspace.project().clone();
 2540        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2541
 2542        cx.spawn_in(window, async move |workspace, cx| {
 2543            let buffer = create.await?;
 2544            workspace.update_in(cx, |workspace, window, cx| {
 2545                let editor =
 2546                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2547                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2548                editor
 2549            })
 2550        })
 2551    }
 2552
 2553    fn new_file_vertical(
 2554        workspace: &mut Workspace,
 2555        _: &workspace::NewFileSplitVertical,
 2556        window: &mut Window,
 2557        cx: &mut Context<Workspace>,
 2558    ) {
 2559        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2560    }
 2561
 2562    fn new_file_horizontal(
 2563        workspace: &mut Workspace,
 2564        _: &workspace::NewFileSplitHorizontal,
 2565        window: &mut Window,
 2566        cx: &mut Context<Workspace>,
 2567    ) {
 2568        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2569    }
 2570
 2571    fn new_file_in_direction(
 2572        workspace: &mut Workspace,
 2573        direction: SplitDirection,
 2574        window: &mut Window,
 2575        cx: &mut Context<Workspace>,
 2576    ) {
 2577        let project = workspace.project().clone();
 2578        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2579
 2580        cx.spawn_in(window, async move |workspace, cx| {
 2581            let buffer = create.await?;
 2582            workspace.update_in(cx, move |workspace, window, cx| {
 2583                workspace.split_item(
 2584                    direction,
 2585                    Box::new(
 2586                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2587                    ),
 2588                    window,
 2589                    cx,
 2590                )
 2591            })?;
 2592            anyhow::Ok(())
 2593        })
 2594        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2595            match e.error_code() {
 2596                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2597                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2598                e.error_tag("required").unwrap_or("the latest version")
 2599            )),
 2600                _ => None,
 2601            }
 2602        });
 2603    }
 2604
 2605    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2606        self.leader_id
 2607    }
 2608
 2609    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2610        &self.buffer
 2611    }
 2612
 2613    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2614        self.workspace.as_ref()?.0.upgrade()
 2615    }
 2616
 2617    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2618        self.buffer().read(cx).title(cx)
 2619    }
 2620
 2621    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2622        let git_blame_gutter_max_author_length = self
 2623            .render_git_blame_gutter(cx)
 2624            .then(|| {
 2625                if let Some(blame) = self.blame.as_ref() {
 2626                    let max_author_length =
 2627                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2628                    Some(max_author_length)
 2629                } else {
 2630                    None
 2631                }
 2632            })
 2633            .flatten();
 2634
 2635        EditorSnapshot {
 2636            mode: self.mode.clone(),
 2637            show_gutter: self.show_gutter,
 2638            show_line_numbers: self.show_line_numbers,
 2639            show_git_diff_gutter: self.show_git_diff_gutter,
 2640            show_code_actions: self.show_code_actions,
 2641            show_runnables: self.show_runnables,
 2642            show_breakpoints: self.show_breakpoints,
 2643            git_blame_gutter_max_author_length,
 2644            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2645            scroll_anchor: self.scroll_manager.anchor(),
 2646            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2647            placeholder_text: self.placeholder_text.clone(),
 2648            is_focused: self.focus_handle.is_focused(window),
 2649            current_line_highlight: self
 2650                .current_line_highlight
 2651                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2652            gutter_hovered: self.gutter_hovered,
 2653        }
 2654    }
 2655
 2656    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2657        self.buffer.read(cx).language_at(point, cx)
 2658    }
 2659
 2660    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2661        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2662    }
 2663
 2664    pub fn active_excerpt(
 2665        &self,
 2666        cx: &App,
 2667    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2668        self.buffer
 2669            .read(cx)
 2670            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2671    }
 2672
 2673    pub fn mode(&self) -> &EditorMode {
 2674        &self.mode
 2675    }
 2676
 2677    pub fn set_mode(&mut self, mode: EditorMode) {
 2678        self.mode = mode;
 2679    }
 2680
 2681    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2682        self.collaboration_hub.as_deref()
 2683    }
 2684
 2685    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2686        self.collaboration_hub = Some(hub);
 2687    }
 2688
 2689    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2690        self.in_project_search = in_project_search;
 2691    }
 2692
 2693    pub fn set_custom_context_menu(
 2694        &mut self,
 2695        f: impl 'static
 2696        + Fn(
 2697            &mut Self,
 2698            DisplayPoint,
 2699            &mut Window,
 2700            &mut Context<Self>,
 2701        ) -> Option<Entity<ui::ContextMenu>>,
 2702    ) {
 2703        self.custom_context_menu = Some(Box::new(f))
 2704    }
 2705
 2706    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2707        self.completion_provider = provider;
 2708    }
 2709
 2710    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2711        self.semantics_provider.clone()
 2712    }
 2713
 2714    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2715        self.semantics_provider = provider;
 2716    }
 2717
 2718    pub fn set_edit_prediction_provider<T>(
 2719        &mut self,
 2720        provider: Option<Entity<T>>,
 2721        window: &mut Window,
 2722        cx: &mut Context<Self>,
 2723    ) where
 2724        T: EditPredictionProvider,
 2725    {
 2726        self.edit_prediction_provider =
 2727            provider.map(|provider| RegisteredInlineCompletionProvider {
 2728                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2729                    if this.focus_handle.is_focused(window) {
 2730                        this.update_visible_inline_completion(window, cx);
 2731                    }
 2732                }),
 2733                provider: Arc::new(provider),
 2734            });
 2735        self.update_edit_prediction_settings(cx);
 2736        self.refresh_inline_completion(false, false, window, cx);
 2737    }
 2738
 2739    pub fn placeholder_text(&self) -> Option<&str> {
 2740        self.placeholder_text.as_deref()
 2741    }
 2742
 2743    pub fn set_placeholder_text(
 2744        &mut self,
 2745        placeholder_text: impl Into<Arc<str>>,
 2746        cx: &mut Context<Self>,
 2747    ) {
 2748        let placeholder_text = Some(placeholder_text.into());
 2749        if self.placeholder_text != placeholder_text {
 2750            self.placeholder_text = placeholder_text;
 2751            cx.notify();
 2752        }
 2753    }
 2754
 2755    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2756        self.cursor_shape = cursor_shape;
 2757
 2758        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2759        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2760
 2761        cx.notify();
 2762    }
 2763
 2764    pub fn set_current_line_highlight(
 2765        &mut self,
 2766        current_line_highlight: Option<CurrentLineHighlight>,
 2767    ) {
 2768        self.current_line_highlight = current_line_highlight;
 2769    }
 2770
 2771    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2772        self.collapse_matches = collapse_matches;
 2773    }
 2774
 2775    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2776        let buffers = self.buffer.read(cx).all_buffers();
 2777        let Some(project) = self.project.as_ref() else {
 2778            return;
 2779        };
 2780        project.update(cx, |project, cx| {
 2781            for buffer in buffers {
 2782                self.registered_buffers
 2783                    .entry(buffer.read(cx).remote_id())
 2784                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2785            }
 2786        })
 2787    }
 2788
 2789    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2790        if self.collapse_matches {
 2791            return range.start..range.start;
 2792        }
 2793        range.clone()
 2794    }
 2795
 2796    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2797        if self.display_map.read(cx).clip_at_line_ends != clip {
 2798            self.display_map
 2799                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2800        }
 2801    }
 2802
 2803    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2804        self.input_enabled = input_enabled;
 2805    }
 2806
 2807    pub fn set_inline_completions_hidden_for_vim_mode(
 2808        &mut self,
 2809        hidden: bool,
 2810        window: &mut Window,
 2811        cx: &mut Context<Self>,
 2812    ) {
 2813        if hidden != self.inline_completions_hidden_for_vim_mode {
 2814            self.inline_completions_hidden_for_vim_mode = hidden;
 2815            if hidden {
 2816                self.update_visible_inline_completion(window, cx);
 2817            } else {
 2818                self.refresh_inline_completion(true, false, window, cx);
 2819            }
 2820        }
 2821    }
 2822
 2823    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2824        self.menu_inline_completions_policy = value;
 2825    }
 2826
 2827    pub fn set_autoindent(&mut self, autoindent: bool) {
 2828        if autoindent {
 2829            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2830        } else {
 2831            self.autoindent_mode = None;
 2832        }
 2833    }
 2834
 2835    pub fn read_only(&self, cx: &App) -> bool {
 2836        self.read_only || self.buffer.read(cx).read_only()
 2837    }
 2838
 2839    pub fn set_read_only(&mut self, read_only: bool) {
 2840        self.read_only = read_only;
 2841    }
 2842
 2843    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2844        self.use_autoclose = autoclose;
 2845    }
 2846
 2847    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2848        self.use_auto_surround = auto_surround;
 2849    }
 2850
 2851    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2852        self.auto_replace_emoji_shortcode = auto_replace;
 2853    }
 2854
 2855    pub fn toggle_edit_predictions(
 2856        &mut self,
 2857        _: &ToggleEditPrediction,
 2858        window: &mut Window,
 2859        cx: &mut Context<Self>,
 2860    ) {
 2861        if self.show_inline_completions_override.is_some() {
 2862            self.set_show_edit_predictions(None, window, cx);
 2863        } else {
 2864            let show_edit_predictions = !self.edit_predictions_enabled();
 2865            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2866        }
 2867    }
 2868
 2869    pub fn set_show_edit_predictions(
 2870        &mut self,
 2871        show_edit_predictions: Option<bool>,
 2872        window: &mut Window,
 2873        cx: &mut Context<Self>,
 2874    ) {
 2875        self.show_inline_completions_override = show_edit_predictions;
 2876        self.update_edit_prediction_settings(cx);
 2877
 2878        if let Some(false) = show_edit_predictions {
 2879            self.discard_inline_completion(false, cx);
 2880        } else {
 2881            self.refresh_inline_completion(false, true, window, cx);
 2882        }
 2883    }
 2884
 2885    fn inline_completions_disabled_in_scope(
 2886        &self,
 2887        buffer: &Entity<Buffer>,
 2888        buffer_position: language::Anchor,
 2889        cx: &App,
 2890    ) -> bool {
 2891        let snapshot = buffer.read(cx).snapshot();
 2892        let settings = snapshot.settings_at(buffer_position, cx);
 2893
 2894        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2895            return false;
 2896        };
 2897
 2898        scope.override_name().map_or(false, |scope_name| {
 2899            settings
 2900                .edit_predictions_disabled_in
 2901                .iter()
 2902                .any(|s| s == scope_name)
 2903        })
 2904    }
 2905
 2906    pub fn set_use_modal_editing(&mut self, to: bool) {
 2907        self.use_modal_editing = to;
 2908    }
 2909
 2910    pub fn use_modal_editing(&self) -> bool {
 2911        self.use_modal_editing
 2912    }
 2913
 2914    fn selections_did_change(
 2915        &mut self,
 2916        local: bool,
 2917        old_cursor_position: &Anchor,
 2918        effects: SelectionEffects,
 2919        window: &mut Window,
 2920        cx: &mut Context<Self>,
 2921    ) {
 2922        window.invalidate_character_coordinates();
 2923
 2924        // Copy selections to primary selection buffer
 2925        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2926        if local {
 2927            let selections = self.selections.all::<usize>(cx);
 2928            let buffer_handle = self.buffer.read(cx).read(cx);
 2929
 2930            let mut text = String::new();
 2931            for (index, selection) in selections.iter().enumerate() {
 2932                let text_for_selection = buffer_handle
 2933                    .text_for_range(selection.start..selection.end)
 2934                    .collect::<String>();
 2935
 2936                text.push_str(&text_for_selection);
 2937                if index != selections.len() - 1 {
 2938                    text.push('\n');
 2939                }
 2940            }
 2941
 2942            if !text.is_empty() {
 2943                cx.write_to_primary(ClipboardItem::new_string(text));
 2944            }
 2945        }
 2946
 2947        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2948            self.buffer.update(cx, |buffer, cx| {
 2949                buffer.set_active_selections(
 2950                    &self.selections.disjoint_anchors(),
 2951                    self.selections.line_mode,
 2952                    self.cursor_shape,
 2953                    cx,
 2954                )
 2955            });
 2956        }
 2957        let display_map = self
 2958            .display_map
 2959            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2960        let buffer = &display_map.buffer_snapshot;
 2961        if self.selections.count() == 1 {
 2962            self.add_selections_state = None;
 2963        }
 2964        self.select_next_state = None;
 2965        self.select_prev_state = None;
 2966        self.select_syntax_node_history.try_clear();
 2967        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2968        self.snippet_stack
 2969            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2970        self.take_rename(false, window, cx);
 2971
 2972        let newest_selection = self.selections.newest_anchor();
 2973        let new_cursor_position = newest_selection.head();
 2974        let selection_start = newest_selection.start;
 2975
 2976        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2977            self.push_to_nav_history(
 2978                *old_cursor_position,
 2979                Some(new_cursor_position.to_point(buffer)),
 2980                false,
 2981                effects.nav_history == Some(true),
 2982                cx,
 2983            );
 2984        }
 2985
 2986        if local {
 2987            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2988                if !self.registered_buffers.contains_key(&buffer_id) {
 2989                    if let Some(project) = self.project.as_ref() {
 2990                        project.update(cx, |project, cx| {
 2991                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2992                                return;
 2993                            };
 2994                            self.registered_buffers.insert(
 2995                                buffer_id,
 2996                                project.register_buffer_with_language_servers(&buffer, cx),
 2997                            );
 2998                        })
 2999                    }
 3000                }
 3001            }
 3002
 3003            let mut context_menu = self.context_menu.borrow_mut();
 3004            let completion_menu = match context_menu.as_ref() {
 3005                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3006                Some(CodeContextMenu::CodeActions(_)) => {
 3007                    *context_menu = None;
 3008                    None
 3009                }
 3010                None => None,
 3011            };
 3012            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3013            drop(context_menu);
 3014
 3015            if effects.completions {
 3016                if let Some(completion_position) = completion_position {
 3017                    let start_offset = selection_start.to_offset(buffer);
 3018                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3019                    let continue_showing = if position_matches {
 3020                        if self.snippet_stack.is_empty() {
 3021                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3022                        } else {
 3023                            // Snippet choices can be shown even when the cursor is in whitespace.
 3024                            // Dismissing the menu with actions like backspace is handled by
 3025                            // invalidation regions.
 3026                            true
 3027                        }
 3028                    } else {
 3029                        false
 3030                    };
 3031
 3032                    if continue_showing {
 3033                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3034                    } else {
 3035                        self.hide_context_menu(window, cx);
 3036                    }
 3037                }
 3038            }
 3039
 3040            hide_hover(self, cx);
 3041
 3042            if old_cursor_position.to_display_point(&display_map).row()
 3043                != new_cursor_position.to_display_point(&display_map).row()
 3044            {
 3045                self.available_code_actions.take();
 3046            }
 3047            self.refresh_code_actions(window, cx);
 3048            self.refresh_document_highlights(cx);
 3049            self.refresh_selected_text_highlights(false, window, cx);
 3050            refresh_matching_bracket_highlights(self, window, cx);
 3051            self.update_visible_inline_completion(window, cx);
 3052            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3053            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3054            self.inline_blame_popover.take();
 3055            if self.git_blame_inline_enabled {
 3056                self.start_inline_blame_timer(window, cx);
 3057            }
 3058        }
 3059
 3060        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3061        cx.emit(EditorEvent::SelectionsChanged { local });
 3062
 3063        let selections = &self.selections.disjoint;
 3064        if selections.len() == 1 {
 3065            cx.emit(SearchEvent::ActiveMatchChanged)
 3066        }
 3067        if local {
 3068            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3069                let inmemory_selections = selections
 3070                    .iter()
 3071                    .map(|s| {
 3072                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3073                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3074                    })
 3075                    .collect();
 3076                self.update_restoration_data(cx, |data| {
 3077                    data.selections = inmemory_selections;
 3078                });
 3079
 3080                if WorkspaceSettings::get(None, cx).restore_on_startup
 3081                    != RestoreOnStartupBehavior::None
 3082                {
 3083                    if let Some(workspace_id) =
 3084                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3085                    {
 3086                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3087                        let selections = selections.clone();
 3088                        let background_executor = cx.background_executor().clone();
 3089                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3090                        self.serialize_selections = cx.background_spawn(async move {
 3091                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3092                            let db_selections = selections
 3093                                .iter()
 3094                                .map(|selection| {
 3095                                    (
 3096                                        selection.start.to_offset(&snapshot),
 3097                                        selection.end.to_offset(&snapshot),
 3098                                    )
 3099                                })
 3100                                .collect();
 3101
 3102                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3103                                .await
 3104                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3105                                .log_err();
 3106                        });
 3107                    }
 3108                }
 3109            }
 3110        }
 3111
 3112        cx.notify();
 3113    }
 3114
 3115    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3116        use text::ToOffset as _;
 3117        use text::ToPoint as _;
 3118
 3119        if self.mode.is_minimap()
 3120            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3121        {
 3122            return;
 3123        }
 3124
 3125        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3126            return;
 3127        };
 3128
 3129        let snapshot = singleton.read(cx).snapshot();
 3130        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3131            let display_snapshot = display_map.snapshot(cx);
 3132
 3133            display_snapshot
 3134                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3135                .map(|fold| {
 3136                    fold.range.start.text_anchor.to_point(&snapshot)
 3137                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3138                })
 3139                .collect()
 3140        });
 3141        self.update_restoration_data(cx, |data| {
 3142            data.folds = inmemory_folds;
 3143        });
 3144
 3145        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3146            return;
 3147        };
 3148        let background_executor = cx.background_executor().clone();
 3149        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3150        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3151            display_map
 3152                .snapshot(cx)
 3153                .folds_in_range(0..snapshot.len())
 3154                .map(|fold| {
 3155                    (
 3156                        fold.range.start.text_anchor.to_offset(&snapshot),
 3157                        fold.range.end.text_anchor.to_offset(&snapshot),
 3158                    )
 3159                })
 3160                .collect()
 3161        });
 3162        self.serialize_folds = cx.background_spawn(async move {
 3163            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3164            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3165                .await
 3166                .with_context(|| {
 3167                    format!(
 3168                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3169                    )
 3170                })
 3171                .log_err();
 3172        });
 3173    }
 3174
 3175    pub fn sync_selections(
 3176        &mut self,
 3177        other: Entity<Editor>,
 3178        cx: &mut Context<Self>,
 3179    ) -> gpui::Subscription {
 3180        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3181        self.selections.change_with(cx, |selections| {
 3182            selections.select_anchors(other_selections);
 3183        });
 3184
 3185        let other_subscription =
 3186            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3187                EditorEvent::SelectionsChanged { local: true } => {
 3188                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3189                    if other_selections.is_empty() {
 3190                        return;
 3191                    }
 3192                    this.selections.change_with(cx, |selections| {
 3193                        selections.select_anchors(other_selections);
 3194                    });
 3195                }
 3196                _ => {}
 3197            });
 3198
 3199        let this_subscription =
 3200            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3201                EditorEvent::SelectionsChanged { local: true } => {
 3202                    let these_selections = this.selections.disjoint.to_vec();
 3203                    if these_selections.is_empty() {
 3204                        return;
 3205                    }
 3206                    other.update(cx, |other_editor, cx| {
 3207                        other_editor.selections.change_with(cx, |selections| {
 3208                            selections.select_anchors(these_selections);
 3209                        })
 3210                    });
 3211                }
 3212                _ => {}
 3213            });
 3214
 3215        Subscription::join(other_subscription, this_subscription)
 3216    }
 3217
 3218    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3219    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3220    /// effects of selection change occur at the end of the transaction.
 3221    pub fn change_selections<R>(
 3222        &mut self,
 3223        effects: SelectionEffects,
 3224        window: &mut Window,
 3225        cx: &mut Context<Self>,
 3226        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3227    ) -> R {
 3228        if let Some(state) = &mut self.deferred_selection_effects_state {
 3229            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3230            state.effects.completions = effects.completions;
 3231            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3232            let (changed, result) = self.selections.change_with(cx, change);
 3233            state.changed |= changed;
 3234            return result;
 3235        }
 3236        let mut state = DeferredSelectionEffectsState {
 3237            changed: false,
 3238            effects,
 3239            old_cursor_position: self.selections.newest_anchor().head(),
 3240            history_entry: SelectionHistoryEntry {
 3241                selections: self.selections.disjoint_anchors(),
 3242                select_next_state: self.select_next_state.clone(),
 3243                select_prev_state: self.select_prev_state.clone(),
 3244                add_selections_state: self.add_selections_state.clone(),
 3245            },
 3246        };
 3247        let (changed, result) = self.selections.change_with(cx, change);
 3248        state.changed = state.changed || changed;
 3249        if self.defer_selection_effects {
 3250            self.deferred_selection_effects_state = Some(state);
 3251        } else {
 3252            self.apply_selection_effects(state, window, cx);
 3253        }
 3254        result
 3255    }
 3256
 3257    /// Defers the effects of selection change, so that the effects of multiple calls to
 3258    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3259    /// to selection history and the state of popovers based on selection position aren't
 3260    /// erroneously updated.
 3261    pub fn with_selection_effects_deferred<R>(
 3262        &mut self,
 3263        window: &mut Window,
 3264        cx: &mut Context<Self>,
 3265        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3266    ) -> R {
 3267        let already_deferred = self.defer_selection_effects;
 3268        self.defer_selection_effects = true;
 3269        let result = update(self, window, cx);
 3270        if !already_deferred {
 3271            self.defer_selection_effects = false;
 3272            if let Some(state) = self.deferred_selection_effects_state.take() {
 3273                self.apply_selection_effects(state, window, cx);
 3274            }
 3275        }
 3276        result
 3277    }
 3278
 3279    fn apply_selection_effects(
 3280        &mut self,
 3281        state: DeferredSelectionEffectsState,
 3282        window: &mut Window,
 3283        cx: &mut Context<Self>,
 3284    ) {
 3285        if state.changed {
 3286            self.selection_history.push(state.history_entry);
 3287
 3288            if let Some(autoscroll) = state.effects.scroll {
 3289                self.request_autoscroll(autoscroll, cx);
 3290            }
 3291
 3292            let old_cursor_position = &state.old_cursor_position;
 3293
 3294            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3295
 3296            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3297                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3298            }
 3299        }
 3300    }
 3301
 3302    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3303    where
 3304        I: IntoIterator<Item = (Range<S>, T)>,
 3305        S: ToOffset,
 3306        T: Into<Arc<str>>,
 3307    {
 3308        if self.read_only(cx) {
 3309            return;
 3310        }
 3311
 3312        self.buffer
 3313            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3314    }
 3315
 3316    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3317    where
 3318        I: IntoIterator<Item = (Range<S>, T)>,
 3319        S: ToOffset,
 3320        T: Into<Arc<str>>,
 3321    {
 3322        if self.read_only(cx) {
 3323            return;
 3324        }
 3325
 3326        self.buffer.update(cx, |buffer, cx| {
 3327            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3328        });
 3329    }
 3330
 3331    pub fn edit_with_block_indent<I, S, T>(
 3332        &mut self,
 3333        edits: I,
 3334        original_indent_columns: Vec<Option<u32>>,
 3335        cx: &mut Context<Self>,
 3336    ) where
 3337        I: IntoIterator<Item = (Range<S>, T)>,
 3338        S: ToOffset,
 3339        T: Into<Arc<str>>,
 3340    {
 3341        if self.read_only(cx) {
 3342            return;
 3343        }
 3344
 3345        self.buffer.update(cx, |buffer, cx| {
 3346            buffer.edit(
 3347                edits,
 3348                Some(AutoindentMode::Block {
 3349                    original_indent_columns,
 3350                }),
 3351                cx,
 3352            )
 3353        });
 3354    }
 3355
 3356    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3357        self.hide_context_menu(window, cx);
 3358
 3359        match phase {
 3360            SelectPhase::Begin {
 3361                position,
 3362                add,
 3363                click_count,
 3364            } => self.begin_selection(position, add, click_count, window, cx),
 3365            SelectPhase::BeginColumnar {
 3366                position,
 3367                goal_column,
 3368                reset,
 3369                mode,
 3370            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3371            SelectPhase::Extend {
 3372                position,
 3373                click_count,
 3374            } => self.extend_selection(position, click_count, window, cx),
 3375            SelectPhase::Update {
 3376                position,
 3377                goal_column,
 3378                scroll_delta,
 3379            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3380            SelectPhase::End => self.end_selection(window, cx),
 3381        }
 3382    }
 3383
 3384    fn extend_selection(
 3385        &mut self,
 3386        position: DisplayPoint,
 3387        click_count: usize,
 3388        window: &mut Window,
 3389        cx: &mut Context<Self>,
 3390    ) {
 3391        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3392        let tail = self.selections.newest::<usize>(cx).tail();
 3393        self.begin_selection(position, false, click_count, window, cx);
 3394
 3395        let position = position.to_offset(&display_map, Bias::Left);
 3396        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3397
 3398        let mut pending_selection = self
 3399            .selections
 3400            .pending_anchor()
 3401            .expect("extend_selection not called with pending selection");
 3402        if position >= tail {
 3403            pending_selection.start = tail_anchor;
 3404        } else {
 3405            pending_selection.end = tail_anchor;
 3406            pending_selection.reversed = true;
 3407        }
 3408
 3409        let mut pending_mode = self.selections.pending_mode().unwrap();
 3410        match &mut pending_mode {
 3411            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3412            _ => {}
 3413        }
 3414
 3415        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3416            SelectionEffects::scroll(Autoscroll::fit())
 3417        } else {
 3418            SelectionEffects::no_scroll()
 3419        };
 3420
 3421        self.change_selections(effects, window, cx, |s| {
 3422            s.set_pending(pending_selection, pending_mode)
 3423        });
 3424    }
 3425
 3426    fn begin_selection(
 3427        &mut self,
 3428        position: DisplayPoint,
 3429        add: bool,
 3430        click_count: usize,
 3431        window: &mut Window,
 3432        cx: &mut Context<Self>,
 3433    ) {
 3434        if !self.focus_handle.is_focused(window) {
 3435            self.last_focused_descendant = None;
 3436            window.focus(&self.focus_handle);
 3437        }
 3438
 3439        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3440        let buffer = &display_map.buffer_snapshot;
 3441        let position = display_map.clip_point(position, Bias::Left);
 3442
 3443        let start;
 3444        let end;
 3445        let mode;
 3446        let mut auto_scroll;
 3447        match click_count {
 3448            1 => {
 3449                start = buffer.anchor_before(position.to_point(&display_map));
 3450                end = start;
 3451                mode = SelectMode::Character;
 3452                auto_scroll = true;
 3453            }
 3454            2 => {
 3455                let position = display_map
 3456                    .clip_point(position, Bias::Left)
 3457                    .to_offset(&display_map, Bias::Left);
 3458                let (range, _) = buffer.surrounding_word(position, false);
 3459                start = buffer.anchor_before(range.start);
 3460                end = buffer.anchor_before(range.end);
 3461                mode = SelectMode::Word(start..end);
 3462                auto_scroll = true;
 3463            }
 3464            3 => {
 3465                let position = display_map
 3466                    .clip_point(position, Bias::Left)
 3467                    .to_point(&display_map);
 3468                let line_start = display_map.prev_line_boundary(position).0;
 3469                let next_line_start = buffer.clip_point(
 3470                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3471                    Bias::Left,
 3472                );
 3473                start = buffer.anchor_before(line_start);
 3474                end = buffer.anchor_before(next_line_start);
 3475                mode = SelectMode::Line(start..end);
 3476                auto_scroll = true;
 3477            }
 3478            _ => {
 3479                start = buffer.anchor_before(0);
 3480                end = buffer.anchor_before(buffer.len());
 3481                mode = SelectMode::All;
 3482                auto_scroll = false;
 3483            }
 3484        }
 3485        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3486
 3487        let point_to_delete: Option<usize> = {
 3488            let selected_points: Vec<Selection<Point>> =
 3489                self.selections.disjoint_in_range(start..end, cx);
 3490
 3491            if !add || click_count > 1 {
 3492                None
 3493            } else if !selected_points.is_empty() {
 3494                Some(selected_points[0].id)
 3495            } else {
 3496                let clicked_point_already_selected =
 3497                    self.selections.disjoint.iter().find(|selection| {
 3498                        selection.start.to_point(buffer) == start.to_point(buffer)
 3499                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3500                    });
 3501
 3502                clicked_point_already_selected.map(|selection| selection.id)
 3503            }
 3504        };
 3505
 3506        let selections_count = self.selections.count();
 3507        let effects = if auto_scroll {
 3508            SelectionEffects::default()
 3509        } else {
 3510            SelectionEffects::no_scroll()
 3511        };
 3512
 3513        self.change_selections(effects, window, cx, |s| {
 3514            if let Some(point_to_delete) = point_to_delete {
 3515                s.delete(point_to_delete);
 3516
 3517                if selections_count == 1 {
 3518                    s.set_pending_anchor_range(start..end, mode);
 3519                }
 3520            } else {
 3521                if !add {
 3522                    s.clear_disjoint();
 3523                }
 3524
 3525                s.set_pending_anchor_range(start..end, mode);
 3526            }
 3527        });
 3528    }
 3529
 3530    fn begin_columnar_selection(
 3531        &mut self,
 3532        position: DisplayPoint,
 3533        goal_column: u32,
 3534        reset: bool,
 3535        mode: ColumnarMode,
 3536        window: &mut Window,
 3537        cx: &mut Context<Self>,
 3538    ) {
 3539        if !self.focus_handle.is_focused(window) {
 3540            self.last_focused_descendant = None;
 3541            window.focus(&self.focus_handle);
 3542        }
 3543
 3544        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3545
 3546        if reset {
 3547            let pointer_position = display_map
 3548                .buffer_snapshot
 3549                .anchor_before(position.to_point(&display_map));
 3550
 3551            self.change_selections(
 3552                SelectionEffects::scroll(Autoscroll::newest()),
 3553                window,
 3554                cx,
 3555                |s| {
 3556                    s.clear_disjoint();
 3557                    s.set_pending_anchor_range(
 3558                        pointer_position..pointer_position,
 3559                        SelectMode::Character,
 3560                    );
 3561                },
 3562            );
 3563        };
 3564
 3565        let tail = self.selections.newest::<Point>(cx).tail();
 3566        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3567        self.columnar_selection_state = match mode {
 3568            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3569                selection_tail: selection_anchor,
 3570                display_point: if reset {
 3571                    if position.column() != goal_column {
 3572                        Some(DisplayPoint::new(position.row(), goal_column))
 3573                    } else {
 3574                        None
 3575                    }
 3576                } else {
 3577                    None
 3578                },
 3579            }),
 3580            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3581                selection_tail: selection_anchor,
 3582            }),
 3583        };
 3584
 3585        if !reset {
 3586            self.select_columns(position, goal_column, &display_map, window, cx);
 3587        }
 3588    }
 3589
 3590    fn update_selection(
 3591        &mut self,
 3592        position: DisplayPoint,
 3593        goal_column: u32,
 3594        scroll_delta: gpui::Point<f32>,
 3595        window: &mut Window,
 3596        cx: &mut Context<Self>,
 3597    ) {
 3598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3599
 3600        if self.columnar_selection_state.is_some() {
 3601            self.select_columns(position, goal_column, &display_map, window, cx);
 3602        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3603            let buffer = &display_map.buffer_snapshot;
 3604            let head;
 3605            let tail;
 3606            let mode = self.selections.pending_mode().unwrap();
 3607            match &mode {
 3608                SelectMode::Character => {
 3609                    head = position.to_point(&display_map);
 3610                    tail = pending.tail().to_point(buffer);
 3611                }
 3612                SelectMode::Word(original_range) => {
 3613                    let offset = display_map
 3614                        .clip_point(position, Bias::Left)
 3615                        .to_offset(&display_map, Bias::Left);
 3616                    let original_range = original_range.to_offset(buffer);
 3617
 3618                    let head_offset = if buffer.is_inside_word(offset, false)
 3619                        || original_range.contains(&offset)
 3620                    {
 3621                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3622                        if word_range.start < original_range.start {
 3623                            word_range.start
 3624                        } else {
 3625                            word_range.end
 3626                        }
 3627                    } else {
 3628                        offset
 3629                    };
 3630
 3631                    head = head_offset.to_point(buffer);
 3632                    if head_offset <= original_range.start {
 3633                        tail = original_range.end.to_point(buffer);
 3634                    } else {
 3635                        tail = original_range.start.to_point(buffer);
 3636                    }
 3637                }
 3638                SelectMode::Line(original_range) => {
 3639                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3640
 3641                    let position = display_map
 3642                        .clip_point(position, Bias::Left)
 3643                        .to_point(&display_map);
 3644                    let line_start = display_map.prev_line_boundary(position).0;
 3645                    let next_line_start = buffer.clip_point(
 3646                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3647                        Bias::Left,
 3648                    );
 3649
 3650                    if line_start < original_range.start {
 3651                        head = line_start
 3652                    } else {
 3653                        head = next_line_start
 3654                    }
 3655
 3656                    if head <= original_range.start {
 3657                        tail = original_range.end;
 3658                    } else {
 3659                        tail = original_range.start;
 3660                    }
 3661                }
 3662                SelectMode::All => {
 3663                    return;
 3664                }
 3665            };
 3666
 3667            if head < tail {
 3668                pending.start = buffer.anchor_before(head);
 3669                pending.end = buffer.anchor_before(tail);
 3670                pending.reversed = true;
 3671            } else {
 3672                pending.start = buffer.anchor_before(tail);
 3673                pending.end = buffer.anchor_before(head);
 3674                pending.reversed = false;
 3675            }
 3676
 3677            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3678                s.set_pending(pending, mode);
 3679            });
 3680        } else {
 3681            log::error!("update_selection dispatched with no pending selection");
 3682            return;
 3683        }
 3684
 3685        self.apply_scroll_delta(scroll_delta, window, cx);
 3686        cx.notify();
 3687    }
 3688
 3689    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3690        self.columnar_selection_state.take();
 3691        if self.selections.pending_anchor().is_some() {
 3692            let selections = self.selections.all::<usize>(cx);
 3693            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3694                s.select(selections);
 3695                s.clear_pending();
 3696            });
 3697        }
 3698    }
 3699
 3700    fn select_columns(
 3701        &mut self,
 3702        head: DisplayPoint,
 3703        goal_column: u32,
 3704        display_map: &DisplaySnapshot,
 3705        window: &mut Window,
 3706        cx: &mut Context<Self>,
 3707    ) {
 3708        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3709            return;
 3710        };
 3711
 3712        let tail = match columnar_state {
 3713            ColumnarSelectionState::FromMouse {
 3714                selection_tail,
 3715                display_point,
 3716            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3717            ColumnarSelectionState::FromSelection { selection_tail } => {
 3718                selection_tail.to_display_point(&display_map)
 3719            }
 3720        };
 3721
 3722        let start_row = cmp::min(tail.row(), head.row());
 3723        let end_row = cmp::max(tail.row(), head.row());
 3724        let start_column = cmp::min(tail.column(), goal_column);
 3725        let end_column = cmp::max(tail.column(), goal_column);
 3726        let reversed = start_column < tail.column();
 3727
 3728        let selection_ranges = (start_row.0..=end_row.0)
 3729            .map(DisplayRow)
 3730            .filter_map(|row| {
 3731                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3732                    || start_column <= display_map.line_len(row))
 3733                    && !display_map.is_block_line(row)
 3734                {
 3735                    let start = display_map
 3736                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3737                        .to_point(display_map);
 3738                    let end = display_map
 3739                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3740                        .to_point(display_map);
 3741                    if reversed {
 3742                        Some(end..start)
 3743                    } else {
 3744                        Some(start..end)
 3745                    }
 3746                } else {
 3747                    None
 3748                }
 3749            })
 3750            .collect::<Vec<_>>();
 3751
 3752        let ranges = match columnar_state {
 3753            ColumnarSelectionState::FromMouse { .. } => {
 3754                let mut non_empty_ranges = selection_ranges
 3755                    .iter()
 3756                    .filter(|selection_range| selection_range.start != selection_range.end)
 3757                    .peekable();
 3758                if non_empty_ranges.peek().is_some() {
 3759                    non_empty_ranges.cloned().collect()
 3760                } else {
 3761                    selection_ranges
 3762                }
 3763            }
 3764            _ => selection_ranges,
 3765        };
 3766
 3767        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3768            s.select_ranges(ranges);
 3769        });
 3770        cx.notify();
 3771    }
 3772
 3773    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3774        self.selections
 3775            .all_adjusted(cx)
 3776            .iter()
 3777            .any(|selection| !selection.is_empty())
 3778    }
 3779
 3780    pub fn has_pending_nonempty_selection(&self) -> bool {
 3781        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3782            Some(Selection { start, end, .. }) => start != end,
 3783            None => false,
 3784        };
 3785
 3786        pending_nonempty_selection
 3787            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3788    }
 3789
 3790    pub fn has_pending_selection(&self) -> bool {
 3791        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3792    }
 3793
 3794    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3795        self.selection_mark_mode = false;
 3796        self.selection_drag_state = SelectionDragState::None;
 3797
 3798        if self.clear_expanded_diff_hunks(cx) {
 3799            cx.notify();
 3800            return;
 3801        }
 3802        if self.dismiss_menus_and_popups(true, window, cx) {
 3803            return;
 3804        }
 3805
 3806        if self.mode.is_full()
 3807            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3808        {
 3809            return;
 3810        }
 3811
 3812        cx.propagate();
 3813    }
 3814
 3815    pub fn dismiss_menus_and_popups(
 3816        &mut self,
 3817        is_user_requested: bool,
 3818        window: &mut Window,
 3819        cx: &mut Context<Self>,
 3820    ) -> bool {
 3821        if self.take_rename(false, window, cx).is_some() {
 3822            return true;
 3823        }
 3824
 3825        if hide_hover(self, cx) {
 3826            return true;
 3827        }
 3828
 3829        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3830            return true;
 3831        }
 3832
 3833        if self.hide_context_menu(window, cx).is_some() {
 3834            return true;
 3835        }
 3836
 3837        if self.mouse_context_menu.take().is_some() {
 3838            return true;
 3839        }
 3840
 3841        if is_user_requested && self.discard_inline_completion(true, cx) {
 3842            return true;
 3843        }
 3844
 3845        if self.snippet_stack.pop().is_some() {
 3846            return true;
 3847        }
 3848
 3849        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3850            self.dismiss_diagnostics(cx);
 3851            return true;
 3852        }
 3853
 3854        false
 3855    }
 3856
 3857    fn linked_editing_ranges_for(
 3858        &self,
 3859        selection: Range<text::Anchor>,
 3860        cx: &App,
 3861    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3862        if self.linked_edit_ranges.is_empty() {
 3863            return None;
 3864        }
 3865        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3866            selection.end.buffer_id.and_then(|end_buffer_id| {
 3867                if selection.start.buffer_id != Some(end_buffer_id) {
 3868                    return None;
 3869                }
 3870                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3871                let snapshot = buffer.read(cx).snapshot();
 3872                self.linked_edit_ranges
 3873                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3874                    .map(|ranges| (ranges, snapshot, buffer))
 3875            })?;
 3876        use text::ToOffset as TO;
 3877        // find offset from the start of current range to current cursor position
 3878        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3879
 3880        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3881        let start_difference = start_offset - start_byte_offset;
 3882        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3883        let end_difference = end_offset - start_byte_offset;
 3884        // Current range has associated linked ranges.
 3885        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3886        for range in linked_ranges.iter() {
 3887            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3888            let end_offset = start_offset + end_difference;
 3889            let start_offset = start_offset + start_difference;
 3890            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3891                continue;
 3892            }
 3893            if self.selections.disjoint_anchor_ranges().any(|s| {
 3894                if s.start.buffer_id != selection.start.buffer_id
 3895                    || s.end.buffer_id != selection.end.buffer_id
 3896                {
 3897                    return false;
 3898                }
 3899                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3900                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3901            }) {
 3902                continue;
 3903            }
 3904            let start = buffer_snapshot.anchor_after(start_offset);
 3905            let end = buffer_snapshot.anchor_after(end_offset);
 3906            linked_edits
 3907                .entry(buffer.clone())
 3908                .or_default()
 3909                .push(start..end);
 3910        }
 3911        Some(linked_edits)
 3912    }
 3913
 3914    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3915        let text: Arc<str> = text.into();
 3916
 3917        if self.read_only(cx) {
 3918            return;
 3919        }
 3920
 3921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3922
 3923        let selections = self.selections.all_adjusted(cx);
 3924        let mut bracket_inserted = false;
 3925        let mut edits = Vec::new();
 3926        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3927        let mut new_selections = Vec::with_capacity(selections.len());
 3928        let mut new_autoclose_regions = Vec::new();
 3929        let snapshot = self.buffer.read(cx).read(cx);
 3930        let mut clear_linked_edit_ranges = false;
 3931
 3932        for (selection, autoclose_region) in
 3933            self.selections_with_autoclose_regions(selections, &snapshot)
 3934        {
 3935            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3936                // Determine if the inserted text matches the opening or closing
 3937                // bracket of any of this language's bracket pairs.
 3938                let mut bracket_pair = None;
 3939                let mut is_bracket_pair_start = false;
 3940                let mut is_bracket_pair_end = false;
 3941                if !text.is_empty() {
 3942                    let mut bracket_pair_matching_end = None;
 3943                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3944                    //  and they are removing the character that triggered IME popup.
 3945                    for (pair, enabled) in scope.brackets() {
 3946                        if !pair.close && !pair.surround {
 3947                            continue;
 3948                        }
 3949
 3950                        if enabled && pair.start.ends_with(text.as_ref()) {
 3951                            let prefix_len = pair.start.len() - text.len();
 3952                            let preceding_text_matches_prefix = prefix_len == 0
 3953                                || (selection.start.column >= (prefix_len as u32)
 3954                                    && snapshot.contains_str_at(
 3955                                        Point::new(
 3956                                            selection.start.row,
 3957                                            selection.start.column - (prefix_len as u32),
 3958                                        ),
 3959                                        &pair.start[..prefix_len],
 3960                                    ));
 3961                            if preceding_text_matches_prefix {
 3962                                bracket_pair = Some(pair.clone());
 3963                                is_bracket_pair_start = true;
 3964                                break;
 3965                            }
 3966                        }
 3967                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3968                        {
 3969                            // take first bracket pair matching end, but don't break in case a later bracket
 3970                            // pair matches start
 3971                            bracket_pair_matching_end = Some(pair.clone());
 3972                        }
 3973                    }
 3974                    if let Some(end) = bracket_pair_matching_end
 3975                        && bracket_pair.is_none()
 3976                    {
 3977                        bracket_pair = Some(end);
 3978                        is_bracket_pair_end = true;
 3979                    }
 3980                }
 3981
 3982                if let Some(bracket_pair) = bracket_pair {
 3983                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3984                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3985                    let auto_surround =
 3986                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3987                    if selection.is_empty() {
 3988                        if is_bracket_pair_start {
 3989                            // If the inserted text is a suffix of an opening bracket and the
 3990                            // selection is preceded by the rest of the opening bracket, then
 3991                            // insert the closing bracket.
 3992                            let following_text_allows_autoclose = snapshot
 3993                                .chars_at(selection.start)
 3994                                .next()
 3995                                .map_or(true, |c| scope.should_autoclose_before(c));
 3996
 3997                            let preceding_text_allows_autoclose = selection.start.column == 0
 3998                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3999                                    true,
 4000                                    |c| {
 4001                                        bracket_pair.start != bracket_pair.end
 4002                                            || !snapshot
 4003                                                .char_classifier_at(selection.start)
 4004                                                .is_word(c)
 4005                                    },
 4006                                );
 4007
 4008                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4009                                && bracket_pair.start.len() == 1
 4010                            {
 4011                                let target = bracket_pair.start.chars().next().unwrap();
 4012                                let current_line_count = snapshot
 4013                                    .reversed_chars_at(selection.start)
 4014                                    .take_while(|&c| c != '\n')
 4015                                    .filter(|&c| c == target)
 4016                                    .count();
 4017                                current_line_count % 2 == 1
 4018                            } else {
 4019                                false
 4020                            };
 4021
 4022                            if autoclose
 4023                                && bracket_pair.close
 4024                                && following_text_allows_autoclose
 4025                                && preceding_text_allows_autoclose
 4026                                && !is_closing_quote
 4027                            {
 4028                                let anchor = snapshot.anchor_before(selection.end);
 4029                                new_selections.push((selection.map(|_| anchor), text.len()));
 4030                                new_autoclose_regions.push((
 4031                                    anchor,
 4032                                    text.len(),
 4033                                    selection.id,
 4034                                    bracket_pair.clone(),
 4035                                ));
 4036                                edits.push((
 4037                                    selection.range(),
 4038                                    format!("{}{}", text, bracket_pair.end).into(),
 4039                                ));
 4040                                bracket_inserted = true;
 4041                                continue;
 4042                            }
 4043                        }
 4044
 4045                        if let Some(region) = autoclose_region {
 4046                            // If the selection is followed by an auto-inserted closing bracket,
 4047                            // then don't insert that closing bracket again; just move the selection
 4048                            // past the closing bracket.
 4049                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4050                                && text.as_ref() == region.pair.end.as_str();
 4051                            if should_skip {
 4052                                let anchor = snapshot.anchor_after(selection.end);
 4053                                new_selections
 4054                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4055                                continue;
 4056                            }
 4057                        }
 4058
 4059                        let always_treat_brackets_as_autoclosed = snapshot
 4060                            .language_settings_at(selection.start, cx)
 4061                            .always_treat_brackets_as_autoclosed;
 4062                        if always_treat_brackets_as_autoclosed
 4063                            && is_bracket_pair_end
 4064                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4065                        {
 4066                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4067                            // and the inserted text is a closing bracket and the selection is followed
 4068                            // by the closing bracket then move the selection past the closing bracket.
 4069                            let anchor = snapshot.anchor_after(selection.end);
 4070                            new_selections.push((selection.map(|_| anchor), text.len()));
 4071                            continue;
 4072                        }
 4073                    }
 4074                    // If an opening bracket is 1 character long and is typed while
 4075                    // text is selected, then surround that text with the bracket pair.
 4076                    else if auto_surround
 4077                        && bracket_pair.surround
 4078                        && is_bracket_pair_start
 4079                        && bracket_pair.start.chars().count() == 1
 4080                    {
 4081                        edits.push((selection.start..selection.start, text.clone()));
 4082                        edits.push((
 4083                            selection.end..selection.end,
 4084                            bracket_pair.end.as_str().into(),
 4085                        ));
 4086                        bracket_inserted = true;
 4087                        new_selections.push((
 4088                            Selection {
 4089                                id: selection.id,
 4090                                start: snapshot.anchor_after(selection.start),
 4091                                end: snapshot.anchor_before(selection.end),
 4092                                reversed: selection.reversed,
 4093                                goal: selection.goal,
 4094                            },
 4095                            0,
 4096                        ));
 4097                        continue;
 4098                    }
 4099                }
 4100            }
 4101
 4102            if self.auto_replace_emoji_shortcode
 4103                && selection.is_empty()
 4104                && text.as_ref().ends_with(':')
 4105            {
 4106                if let Some(possible_emoji_short_code) =
 4107                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4108                {
 4109                    if !possible_emoji_short_code.is_empty() {
 4110                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4111                            let emoji_shortcode_start = Point::new(
 4112                                selection.start.row,
 4113                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4114                            );
 4115
 4116                            // Remove shortcode from buffer
 4117                            edits.push((
 4118                                emoji_shortcode_start..selection.start,
 4119                                "".to_string().into(),
 4120                            ));
 4121                            new_selections.push((
 4122                                Selection {
 4123                                    id: selection.id,
 4124                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4125                                    end: snapshot.anchor_before(selection.start),
 4126                                    reversed: selection.reversed,
 4127                                    goal: selection.goal,
 4128                                },
 4129                                0,
 4130                            ));
 4131
 4132                            // Insert emoji
 4133                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4134                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4135                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4136
 4137                            continue;
 4138                        }
 4139                    }
 4140                }
 4141            }
 4142
 4143            // If not handling any auto-close operation, then just replace the selected
 4144            // text with the given input and move the selection to the end of the
 4145            // newly inserted text.
 4146            let anchor = snapshot.anchor_after(selection.end);
 4147            if !self.linked_edit_ranges.is_empty() {
 4148                let start_anchor = snapshot.anchor_before(selection.start);
 4149
 4150                let is_word_char = text.chars().next().map_or(true, |char| {
 4151                    let classifier = snapshot
 4152                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4153                        .ignore_punctuation(true);
 4154                    classifier.is_word(char)
 4155                });
 4156
 4157                if is_word_char {
 4158                    if let Some(ranges) = self
 4159                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4160                    {
 4161                        for (buffer, edits) in ranges {
 4162                            linked_edits
 4163                                .entry(buffer.clone())
 4164                                .or_default()
 4165                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4166                        }
 4167                    }
 4168                } else {
 4169                    clear_linked_edit_ranges = true;
 4170                }
 4171            }
 4172
 4173            new_selections.push((selection.map(|_| anchor), 0));
 4174            edits.push((selection.start..selection.end, text.clone()));
 4175        }
 4176
 4177        drop(snapshot);
 4178
 4179        self.transact(window, cx, |this, window, cx| {
 4180            if clear_linked_edit_ranges {
 4181                this.linked_edit_ranges.clear();
 4182            }
 4183            let initial_buffer_versions =
 4184                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4185
 4186            this.buffer.update(cx, |buffer, cx| {
 4187                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4188            });
 4189            for (buffer, edits) in linked_edits {
 4190                buffer.update(cx, |buffer, cx| {
 4191                    let snapshot = buffer.snapshot();
 4192                    let edits = edits
 4193                        .into_iter()
 4194                        .map(|(range, text)| {
 4195                            use text::ToPoint as TP;
 4196                            let end_point = TP::to_point(&range.end, &snapshot);
 4197                            let start_point = TP::to_point(&range.start, &snapshot);
 4198                            (start_point..end_point, text)
 4199                        })
 4200                        .sorted_by_key(|(range, _)| range.start);
 4201                    buffer.edit(edits, None, cx);
 4202                })
 4203            }
 4204            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4205            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4206            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4207            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4208                .zip(new_selection_deltas)
 4209                .map(|(selection, delta)| Selection {
 4210                    id: selection.id,
 4211                    start: selection.start + delta,
 4212                    end: selection.end + delta,
 4213                    reversed: selection.reversed,
 4214                    goal: SelectionGoal::None,
 4215                })
 4216                .collect::<Vec<_>>();
 4217
 4218            let mut i = 0;
 4219            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4220                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4221                let start = map.buffer_snapshot.anchor_before(position);
 4222                let end = map.buffer_snapshot.anchor_after(position);
 4223                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4224                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4225                        Ordering::Less => i += 1,
 4226                        Ordering::Greater => break,
 4227                        Ordering::Equal => {
 4228                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4229                                Ordering::Less => i += 1,
 4230                                Ordering::Equal => break,
 4231                                Ordering::Greater => break,
 4232                            }
 4233                        }
 4234                    }
 4235                }
 4236                this.autoclose_regions.insert(
 4237                    i,
 4238                    AutocloseRegion {
 4239                        selection_id,
 4240                        range: start..end,
 4241                        pair,
 4242                    },
 4243                );
 4244            }
 4245
 4246            let had_active_inline_completion = this.has_active_inline_completion();
 4247            this.change_selections(
 4248                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4249                window,
 4250                cx,
 4251                |s| s.select(new_selections),
 4252            );
 4253
 4254            if !bracket_inserted {
 4255                if let Some(on_type_format_task) =
 4256                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4257                {
 4258                    on_type_format_task.detach_and_log_err(cx);
 4259                }
 4260            }
 4261
 4262            let editor_settings = EditorSettings::get_global(cx);
 4263            if bracket_inserted
 4264                && (editor_settings.auto_signature_help
 4265                    || editor_settings.show_signature_help_after_edits)
 4266            {
 4267                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4268            }
 4269
 4270            let trigger_in_words =
 4271                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4272            if this.hard_wrap.is_some() {
 4273                let latest: Range<Point> = this.selections.newest(cx).range();
 4274                if latest.is_empty()
 4275                    && this
 4276                        .buffer()
 4277                        .read(cx)
 4278                        .snapshot(cx)
 4279                        .line_len(MultiBufferRow(latest.start.row))
 4280                        == latest.start.column
 4281                {
 4282                    this.rewrap_impl(
 4283                        RewrapOptions {
 4284                            override_language_settings: true,
 4285                            preserve_existing_whitespace: true,
 4286                        },
 4287                        cx,
 4288                    )
 4289                }
 4290            }
 4291            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4292            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4293            this.refresh_inline_completion(true, false, window, cx);
 4294            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4295        });
 4296    }
 4297
 4298    fn find_possible_emoji_shortcode_at_position(
 4299        snapshot: &MultiBufferSnapshot,
 4300        position: Point,
 4301    ) -> Option<String> {
 4302        let mut chars = Vec::new();
 4303        let mut found_colon = false;
 4304        for char in snapshot.reversed_chars_at(position).take(100) {
 4305            // Found a possible emoji shortcode in the middle of the buffer
 4306            if found_colon {
 4307                if char.is_whitespace() {
 4308                    chars.reverse();
 4309                    return Some(chars.iter().collect());
 4310                }
 4311                // If the previous character is not a whitespace, we are in the middle of a word
 4312                // and we only want to complete the shortcode if the word is made up of other emojis
 4313                let mut containing_word = String::new();
 4314                for ch in snapshot
 4315                    .reversed_chars_at(position)
 4316                    .skip(chars.len() + 1)
 4317                    .take(100)
 4318                {
 4319                    if ch.is_whitespace() {
 4320                        break;
 4321                    }
 4322                    containing_word.push(ch);
 4323                }
 4324                let containing_word = containing_word.chars().rev().collect::<String>();
 4325                if util::word_consists_of_emojis(containing_word.as_str()) {
 4326                    chars.reverse();
 4327                    return Some(chars.iter().collect());
 4328                }
 4329            }
 4330
 4331            if char.is_whitespace() || !char.is_ascii() {
 4332                return None;
 4333            }
 4334            if char == ':' {
 4335                found_colon = true;
 4336            } else {
 4337                chars.push(char);
 4338            }
 4339        }
 4340        // Found a possible emoji shortcode at the beginning of the buffer
 4341        chars.reverse();
 4342        Some(chars.iter().collect())
 4343    }
 4344
 4345    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4347        self.transact(window, cx, |this, window, cx| {
 4348            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4349                let selections = this.selections.all::<usize>(cx);
 4350                let multi_buffer = this.buffer.read(cx);
 4351                let buffer = multi_buffer.snapshot(cx);
 4352                selections
 4353                    .iter()
 4354                    .map(|selection| {
 4355                        let start_point = selection.start.to_point(&buffer);
 4356                        let mut existing_indent =
 4357                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4358                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4359                        let start = selection.start;
 4360                        let end = selection.end;
 4361                        let selection_is_empty = start == end;
 4362                        let language_scope = buffer.language_scope_at(start);
 4363                        let (
 4364                            comment_delimiter,
 4365                            doc_delimiter,
 4366                            insert_extra_newline,
 4367                            indent_on_newline,
 4368                            indent_on_extra_newline,
 4369                        ) = if let Some(language) = &language_scope {
 4370                            let mut insert_extra_newline =
 4371                                insert_extra_newline_brackets(&buffer, start..end, language)
 4372                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4373
 4374                            // Comment extension on newline is allowed only for cursor selections
 4375                            let comment_delimiter = maybe!({
 4376                                if !selection_is_empty {
 4377                                    return None;
 4378                                }
 4379
 4380                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4381                                    return None;
 4382                                }
 4383
 4384                                let delimiters = language.line_comment_prefixes();
 4385                                let max_len_of_delimiter =
 4386                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4387                                let (snapshot, range) =
 4388                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4389
 4390                                let num_of_whitespaces = snapshot
 4391                                    .chars_for_range(range.clone())
 4392                                    .take_while(|c| c.is_whitespace())
 4393                                    .count();
 4394                                let comment_candidate = snapshot
 4395                                    .chars_for_range(range.clone())
 4396                                    .skip(num_of_whitespaces)
 4397                                    .take(max_len_of_delimiter)
 4398                                    .collect::<String>();
 4399                                let (delimiter, trimmed_len) = delimiters
 4400                                    .iter()
 4401                                    .filter_map(|delimiter| {
 4402                                        let prefix = delimiter.trim_end();
 4403                                        if comment_candidate.starts_with(prefix) {
 4404                                            Some((delimiter, prefix.len()))
 4405                                        } else {
 4406                                            None
 4407                                        }
 4408                                    })
 4409                                    .max_by_key(|(_, len)| *len)?;
 4410
 4411                                if let Some(BlockCommentConfig {
 4412                                    start: block_start, ..
 4413                                }) = language.block_comment()
 4414                                {
 4415                                    let block_start_trimmed = block_start.trim_end();
 4416                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4417                                        let line_content = snapshot
 4418                                            .chars_for_range(range)
 4419                                            .skip(num_of_whitespaces)
 4420                                            .take(block_start_trimmed.len())
 4421                                            .collect::<String>();
 4422
 4423                                        if line_content.starts_with(block_start_trimmed) {
 4424                                            return None;
 4425                                        }
 4426                                    }
 4427                                }
 4428
 4429                                let cursor_is_placed_after_comment_marker =
 4430                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4431                                if cursor_is_placed_after_comment_marker {
 4432                                    Some(delimiter.clone())
 4433                                } else {
 4434                                    None
 4435                                }
 4436                            });
 4437
 4438                            let mut indent_on_newline = IndentSize::spaces(0);
 4439                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4440
 4441                            let doc_delimiter = maybe!({
 4442                                if !selection_is_empty {
 4443                                    return None;
 4444                                }
 4445
 4446                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4447                                    return None;
 4448                                }
 4449
 4450                                let BlockCommentConfig {
 4451                                    start: start_tag,
 4452                                    end: end_tag,
 4453                                    prefix: delimiter,
 4454                                    tab_size: len,
 4455                                } = language.documentation_comment()?;
 4456                                let is_within_block_comment = buffer
 4457                                    .language_scope_at(start_point)
 4458                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4459                                if !is_within_block_comment {
 4460                                    return None;
 4461                                }
 4462
 4463                                let (snapshot, range) =
 4464                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4465
 4466                                let num_of_whitespaces = snapshot
 4467                                    .chars_for_range(range.clone())
 4468                                    .take_while(|c| c.is_whitespace())
 4469                                    .count();
 4470
 4471                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4472                                let column = start_point.column;
 4473                                let cursor_is_after_start_tag = {
 4474                                    let start_tag_len = start_tag.len();
 4475                                    let start_tag_line = snapshot
 4476                                        .chars_for_range(range.clone())
 4477                                        .skip(num_of_whitespaces)
 4478                                        .take(start_tag_len)
 4479                                        .collect::<String>();
 4480                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4481                                        num_of_whitespaces + start_tag_len <= column as usize
 4482                                    } else {
 4483                                        false
 4484                                    }
 4485                                };
 4486
 4487                                let cursor_is_after_delimiter = {
 4488                                    let delimiter_trim = delimiter.trim_end();
 4489                                    let delimiter_line = snapshot
 4490                                        .chars_for_range(range.clone())
 4491                                        .skip(num_of_whitespaces)
 4492                                        .take(delimiter_trim.len())
 4493                                        .collect::<String>();
 4494                                    if delimiter_line.starts_with(delimiter_trim) {
 4495                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4496                                    } else {
 4497                                        false
 4498                                    }
 4499                                };
 4500
 4501                                let cursor_is_before_end_tag_if_exists = {
 4502                                    let mut char_position = 0u32;
 4503                                    let mut end_tag_offset = None;
 4504
 4505                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4506                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4507                                            let chars_before_match =
 4508                                                chunk[..byte_pos].chars().count() as u32;
 4509                                            end_tag_offset =
 4510                                                Some(char_position + chars_before_match);
 4511                                            break 'outer;
 4512                                        }
 4513                                        char_position += chunk.chars().count() as u32;
 4514                                    }
 4515
 4516                                    if let Some(end_tag_offset) = end_tag_offset {
 4517                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4518                                        if cursor_is_after_start_tag {
 4519                                            if cursor_is_before_end_tag {
 4520                                                insert_extra_newline = true;
 4521                                            }
 4522                                            let cursor_is_at_start_of_end_tag =
 4523                                                column == end_tag_offset;
 4524                                            if cursor_is_at_start_of_end_tag {
 4525                                                indent_on_extra_newline.len = *len;
 4526                                            }
 4527                                        }
 4528                                        cursor_is_before_end_tag
 4529                                    } else {
 4530                                        true
 4531                                    }
 4532                                };
 4533
 4534                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4535                                    && cursor_is_before_end_tag_if_exists
 4536                                {
 4537                                    if cursor_is_after_start_tag {
 4538                                        indent_on_newline.len = *len;
 4539                                    }
 4540                                    Some(delimiter.clone())
 4541                                } else {
 4542                                    None
 4543                                }
 4544                            });
 4545
 4546                            (
 4547                                comment_delimiter,
 4548                                doc_delimiter,
 4549                                insert_extra_newline,
 4550                                indent_on_newline,
 4551                                indent_on_extra_newline,
 4552                            )
 4553                        } else {
 4554                            (
 4555                                None,
 4556                                None,
 4557                                false,
 4558                                IndentSize::default(),
 4559                                IndentSize::default(),
 4560                            )
 4561                        };
 4562
 4563                        let prevent_auto_indent = doc_delimiter.is_some();
 4564                        let delimiter = comment_delimiter.or(doc_delimiter);
 4565
 4566                        let capacity_for_delimiter =
 4567                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4568                        let mut new_text = String::with_capacity(
 4569                            1 + capacity_for_delimiter
 4570                                + existing_indent.len as usize
 4571                                + indent_on_newline.len as usize
 4572                                + indent_on_extra_newline.len as usize,
 4573                        );
 4574                        new_text.push('\n');
 4575                        new_text.extend(existing_indent.chars());
 4576                        new_text.extend(indent_on_newline.chars());
 4577
 4578                        if let Some(delimiter) = &delimiter {
 4579                            new_text.push_str(delimiter);
 4580                        }
 4581
 4582                        if insert_extra_newline {
 4583                            new_text.push('\n');
 4584                            new_text.extend(existing_indent.chars());
 4585                            new_text.extend(indent_on_extra_newline.chars());
 4586                        }
 4587
 4588                        let anchor = buffer.anchor_after(end);
 4589                        let new_selection = selection.map(|_| anchor);
 4590                        (
 4591                            ((start..end, new_text), prevent_auto_indent),
 4592                            (insert_extra_newline, new_selection),
 4593                        )
 4594                    })
 4595                    .unzip()
 4596            };
 4597
 4598            let mut auto_indent_edits = Vec::new();
 4599            let mut edits = Vec::new();
 4600            for (edit, prevent_auto_indent) in edits_with_flags {
 4601                if prevent_auto_indent {
 4602                    edits.push(edit);
 4603                } else {
 4604                    auto_indent_edits.push(edit);
 4605                }
 4606            }
 4607            if !edits.is_empty() {
 4608                this.edit(edits, cx);
 4609            }
 4610            if !auto_indent_edits.is_empty() {
 4611                this.edit_with_autoindent(auto_indent_edits, cx);
 4612            }
 4613
 4614            let buffer = this.buffer.read(cx).snapshot(cx);
 4615            let new_selections = selection_info
 4616                .into_iter()
 4617                .map(|(extra_newline_inserted, new_selection)| {
 4618                    let mut cursor = new_selection.end.to_point(&buffer);
 4619                    if extra_newline_inserted {
 4620                        cursor.row -= 1;
 4621                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4622                    }
 4623                    new_selection.map(|_| cursor)
 4624                })
 4625                .collect();
 4626
 4627            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4628            this.refresh_inline_completion(true, false, window, cx);
 4629        });
 4630    }
 4631
 4632    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4634
 4635        let buffer = self.buffer.read(cx);
 4636        let snapshot = buffer.snapshot(cx);
 4637
 4638        let mut edits = Vec::new();
 4639        let mut rows = Vec::new();
 4640
 4641        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4642            let cursor = selection.head();
 4643            let row = cursor.row;
 4644
 4645            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4646
 4647            let newline = "\n".to_string();
 4648            edits.push((start_of_line..start_of_line, newline));
 4649
 4650            rows.push(row + rows_inserted as u32);
 4651        }
 4652
 4653        self.transact(window, cx, |editor, window, cx| {
 4654            editor.edit(edits, cx);
 4655
 4656            editor.change_selections(Default::default(), window, cx, |s| {
 4657                let mut index = 0;
 4658                s.move_cursors_with(|map, _, _| {
 4659                    let row = rows[index];
 4660                    index += 1;
 4661
 4662                    let point = Point::new(row, 0);
 4663                    let boundary = map.next_line_boundary(point).1;
 4664                    let clipped = map.clip_point(boundary, Bias::Left);
 4665
 4666                    (clipped, SelectionGoal::None)
 4667                });
 4668            });
 4669
 4670            let mut indent_edits = Vec::new();
 4671            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4672            for row in rows {
 4673                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4674                for (row, indent) in indents {
 4675                    if indent.len == 0 {
 4676                        continue;
 4677                    }
 4678
 4679                    let text = match indent.kind {
 4680                        IndentKind::Space => " ".repeat(indent.len as usize),
 4681                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4682                    };
 4683                    let point = Point::new(row.0, 0);
 4684                    indent_edits.push((point..point, text));
 4685                }
 4686            }
 4687            editor.edit(indent_edits, cx);
 4688        });
 4689    }
 4690
 4691    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4693
 4694        let buffer = self.buffer.read(cx);
 4695        let snapshot = buffer.snapshot(cx);
 4696
 4697        let mut edits = Vec::new();
 4698        let mut rows = Vec::new();
 4699        let mut rows_inserted = 0;
 4700
 4701        for selection in self.selections.all_adjusted(cx) {
 4702            let cursor = selection.head();
 4703            let row = cursor.row;
 4704
 4705            let point = Point::new(row + 1, 0);
 4706            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4707
 4708            let newline = "\n".to_string();
 4709            edits.push((start_of_line..start_of_line, newline));
 4710
 4711            rows_inserted += 1;
 4712            rows.push(row + rows_inserted);
 4713        }
 4714
 4715        self.transact(window, cx, |editor, window, cx| {
 4716            editor.edit(edits, cx);
 4717
 4718            editor.change_selections(Default::default(), window, cx, |s| {
 4719                let mut index = 0;
 4720                s.move_cursors_with(|map, _, _| {
 4721                    let row = rows[index];
 4722                    index += 1;
 4723
 4724                    let point = Point::new(row, 0);
 4725                    let boundary = map.next_line_boundary(point).1;
 4726                    let clipped = map.clip_point(boundary, Bias::Left);
 4727
 4728                    (clipped, SelectionGoal::None)
 4729                });
 4730            });
 4731
 4732            let mut indent_edits = Vec::new();
 4733            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4734            for row in rows {
 4735                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4736                for (row, indent) in indents {
 4737                    if indent.len == 0 {
 4738                        continue;
 4739                    }
 4740
 4741                    let text = match indent.kind {
 4742                        IndentKind::Space => " ".repeat(indent.len as usize),
 4743                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4744                    };
 4745                    let point = Point::new(row.0, 0);
 4746                    indent_edits.push((point..point, text));
 4747                }
 4748            }
 4749            editor.edit(indent_edits, cx);
 4750        });
 4751    }
 4752
 4753    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4754        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4755            original_indent_columns: Vec::new(),
 4756        });
 4757        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4758    }
 4759
 4760    fn insert_with_autoindent_mode(
 4761        &mut self,
 4762        text: &str,
 4763        autoindent_mode: Option<AutoindentMode>,
 4764        window: &mut Window,
 4765        cx: &mut Context<Self>,
 4766    ) {
 4767        if self.read_only(cx) {
 4768            return;
 4769        }
 4770
 4771        let text: Arc<str> = text.into();
 4772        self.transact(window, cx, |this, window, cx| {
 4773            let old_selections = this.selections.all_adjusted(cx);
 4774            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4775                let anchors = {
 4776                    let snapshot = buffer.read(cx);
 4777                    old_selections
 4778                        .iter()
 4779                        .map(|s| {
 4780                            let anchor = snapshot.anchor_after(s.head());
 4781                            s.map(|_| anchor)
 4782                        })
 4783                        .collect::<Vec<_>>()
 4784                };
 4785                buffer.edit(
 4786                    old_selections
 4787                        .iter()
 4788                        .map(|s| (s.start..s.end, text.clone())),
 4789                    autoindent_mode,
 4790                    cx,
 4791                );
 4792                anchors
 4793            });
 4794
 4795            this.change_selections(Default::default(), window, cx, |s| {
 4796                s.select_anchors(selection_anchors);
 4797            });
 4798
 4799            cx.notify();
 4800        });
 4801    }
 4802
 4803    fn trigger_completion_on_input(
 4804        &mut self,
 4805        text: &str,
 4806        trigger_in_words: bool,
 4807        window: &mut Window,
 4808        cx: &mut Context<Self>,
 4809    ) {
 4810        let completions_source = self
 4811            .context_menu
 4812            .borrow()
 4813            .as_ref()
 4814            .and_then(|menu| match menu {
 4815                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4816                CodeContextMenu::CodeActions(_) => None,
 4817            });
 4818
 4819        match completions_source {
 4820            Some(CompletionsMenuSource::Words) => {
 4821                self.show_word_completions(&ShowWordCompletions, window, cx)
 4822            }
 4823            Some(CompletionsMenuSource::Normal)
 4824            | Some(CompletionsMenuSource::SnippetChoices)
 4825            | None
 4826                if self.is_completion_trigger(
 4827                    text,
 4828                    trigger_in_words,
 4829                    completions_source.is_some(),
 4830                    cx,
 4831                ) =>
 4832            {
 4833                self.show_completions(
 4834                    &ShowCompletions {
 4835                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4836                    },
 4837                    window,
 4838                    cx,
 4839                )
 4840            }
 4841            _ => {
 4842                self.hide_context_menu(window, cx);
 4843            }
 4844        }
 4845    }
 4846
 4847    fn is_completion_trigger(
 4848        &self,
 4849        text: &str,
 4850        trigger_in_words: bool,
 4851        menu_is_open: bool,
 4852        cx: &mut Context<Self>,
 4853    ) -> bool {
 4854        let position = self.selections.newest_anchor().head();
 4855        let multibuffer = self.buffer.read(cx);
 4856        let Some(buffer) = position
 4857            .buffer_id
 4858            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4859        else {
 4860            return false;
 4861        };
 4862
 4863        if let Some(completion_provider) = &self.completion_provider {
 4864            completion_provider.is_completion_trigger(
 4865                &buffer,
 4866                position.text_anchor,
 4867                text,
 4868                trigger_in_words,
 4869                menu_is_open,
 4870                cx,
 4871            )
 4872        } else {
 4873            false
 4874        }
 4875    }
 4876
 4877    /// If any empty selections is touching the start of its innermost containing autoclose
 4878    /// region, expand it to select the brackets.
 4879    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4880        let selections = self.selections.all::<usize>(cx);
 4881        let buffer = self.buffer.read(cx).read(cx);
 4882        let new_selections = self
 4883            .selections_with_autoclose_regions(selections, &buffer)
 4884            .map(|(mut selection, region)| {
 4885                if !selection.is_empty() {
 4886                    return selection;
 4887                }
 4888
 4889                if let Some(region) = region {
 4890                    let mut range = region.range.to_offset(&buffer);
 4891                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4892                        range.start -= region.pair.start.len();
 4893                        if buffer.contains_str_at(range.start, &region.pair.start)
 4894                            && buffer.contains_str_at(range.end, &region.pair.end)
 4895                        {
 4896                            range.end += region.pair.end.len();
 4897                            selection.start = range.start;
 4898                            selection.end = range.end;
 4899
 4900                            return selection;
 4901                        }
 4902                    }
 4903                }
 4904
 4905                let always_treat_brackets_as_autoclosed = buffer
 4906                    .language_settings_at(selection.start, cx)
 4907                    .always_treat_brackets_as_autoclosed;
 4908
 4909                if !always_treat_brackets_as_autoclosed {
 4910                    return selection;
 4911                }
 4912
 4913                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4914                    for (pair, enabled) in scope.brackets() {
 4915                        if !enabled || !pair.close {
 4916                            continue;
 4917                        }
 4918
 4919                        if buffer.contains_str_at(selection.start, &pair.end) {
 4920                            let pair_start_len = pair.start.len();
 4921                            if buffer.contains_str_at(
 4922                                selection.start.saturating_sub(pair_start_len),
 4923                                &pair.start,
 4924                            ) {
 4925                                selection.start -= pair_start_len;
 4926                                selection.end += pair.end.len();
 4927
 4928                                return selection;
 4929                            }
 4930                        }
 4931                    }
 4932                }
 4933
 4934                selection
 4935            })
 4936            .collect();
 4937
 4938        drop(buffer);
 4939        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4940            selections.select(new_selections)
 4941        });
 4942    }
 4943
 4944    /// Iterate the given selections, and for each one, find the smallest surrounding
 4945    /// autoclose region. This uses the ordering of the selections and the autoclose
 4946    /// regions to avoid repeated comparisons.
 4947    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4948        &'a self,
 4949        selections: impl IntoIterator<Item = Selection<D>>,
 4950        buffer: &'a MultiBufferSnapshot,
 4951    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4952        let mut i = 0;
 4953        let mut regions = self.autoclose_regions.as_slice();
 4954        selections.into_iter().map(move |selection| {
 4955            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4956
 4957            let mut enclosing = None;
 4958            while let Some(pair_state) = regions.get(i) {
 4959                if pair_state.range.end.to_offset(buffer) < range.start {
 4960                    regions = &regions[i + 1..];
 4961                    i = 0;
 4962                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4963                    break;
 4964                } else {
 4965                    if pair_state.selection_id == selection.id {
 4966                        enclosing = Some(pair_state);
 4967                    }
 4968                    i += 1;
 4969                }
 4970            }
 4971
 4972            (selection, enclosing)
 4973        })
 4974    }
 4975
 4976    /// Remove any autoclose regions that no longer contain their selection.
 4977    fn invalidate_autoclose_regions(
 4978        &mut self,
 4979        mut selections: &[Selection<Anchor>],
 4980        buffer: &MultiBufferSnapshot,
 4981    ) {
 4982        self.autoclose_regions.retain(|state| {
 4983            let mut i = 0;
 4984            while let Some(selection) = selections.get(i) {
 4985                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4986                    selections = &selections[1..];
 4987                    continue;
 4988                }
 4989                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4990                    break;
 4991                }
 4992                if selection.id == state.selection_id {
 4993                    return true;
 4994                } else {
 4995                    i += 1;
 4996                }
 4997            }
 4998            false
 4999        });
 5000    }
 5001
 5002    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5003        let offset = position.to_offset(buffer);
 5004        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5005        if offset > word_range.start && kind == Some(CharKind::Word) {
 5006            Some(
 5007                buffer
 5008                    .text_for_range(word_range.start..offset)
 5009                    .collect::<String>(),
 5010            )
 5011        } else {
 5012            None
 5013        }
 5014    }
 5015
 5016    pub fn toggle_inline_values(
 5017        &mut self,
 5018        _: &ToggleInlineValues,
 5019        _: &mut Window,
 5020        cx: &mut Context<Self>,
 5021    ) {
 5022        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5023
 5024        self.refresh_inline_values(cx);
 5025    }
 5026
 5027    pub fn toggle_inlay_hints(
 5028        &mut self,
 5029        _: &ToggleInlayHints,
 5030        _: &mut Window,
 5031        cx: &mut Context<Self>,
 5032    ) {
 5033        self.refresh_inlay_hints(
 5034            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5035            cx,
 5036        );
 5037    }
 5038
 5039    pub fn inlay_hints_enabled(&self) -> bool {
 5040        self.inlay_hint_cache.enabled
 5041    }
 5042
 5043    pub fn inline_values_enabled(&self) -> bool {
 5044        self.inline_value_cache.enabled
 5045    }
 5046
 5047    #[cfg(any(test, feature = "test-support"))]
 5048    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5049        self.display_map
 5050            .read(cx)
 5051            .current_inlays()
 5052            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5053            .cloned()
 5054            .collect()
 5055    }
 5056
 5057    #[cfg(any(test, feature = "test-support"))]
 5058    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5059        self.display_map
 5060            .read(cx)
 5061            .current_inlays()
 5062            .cloned()
 5063            .collect()
 5064    }
 5065
 5066    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5067        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5068            return;
 5069        }
 5070
 5071        let reason_description = reason.description();
 5072        let ignore_debounce = matches!(
 5073            reason,
 5074            InlayHintRefreshReason::SettingsChange(_)
 5075                | InlayHintRefreshReason::Toggle(_)
 5076                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5077                | InlayHintRefreshReason::ModifiersChanged(_)
 5078        );
 5079        let (invalidate_cache, required_languages) = match reason {
 5080            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5081                match self.inlay_hint_cache.modifiers_override(enabled) {
 5082                    Some(enabled) => {
 5083                        if enabled {
 5084                            (InvalidationStrategy::RefreshRequested, None)
 5085                        } else {
 5086                            self.splice_inlays(
 5087                                &self
 5088                                    .visible_inlay_hints(cx)
 5089                                    .iter()
 5090                                    .map(|inlay| inlay.id)
 5091                                    .collect::<Vec<InlayId>>(),
 5092                                Vec::new(),
 5093                                cx,
 5094                            );
 5095                            return;
 5096                        }
 5097                    }
 5098                    None => return,
 5099                }
 5100            }
 5101            InlayHintRefreshReason::Toggle(enabled) => {
 5102                if self.inlay_hint_cache.toggle(enabled) {
 5103                    if enabled {
 5104                        (InvalidationStrategy::RefreshRequested, None)
 5105                    } else {
 5106                        self.splice_inlays(
 5107                            &self
 5108                                .visible_inlay_hints(cx)
 5109                                .iter()
 5110                                .map(|inlay| inlay.id)
 5111                                .collect::<Vec<InlayId>>(),
 5112                            Vec::new(),
 5113                            cx,
 5114                        );
 5115                        return;
 5116                    }
 5117                } else {
 5118                    return;
 5119                }
 5120            }
 5121            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5122                match self.inlay_hint_cache.update_settings(
 5123                    &self.buffer,
 5124                    new_settings,
 5125                    self.visible_inlay_hints(cx),
 5126                    cx,
 5127                ) {
 5128                    ControlFlow::Break(Some(InlaySplice {
 5129                        to_remove,
 5130                        to_insert,
 5131                    })) => {
 5132                        self.splice_inlays(&to_remove, to_insert, cx);
 5133                        return;
 5134                    }
 5135                    ControlFlow::Break(None) => return,
 5136                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5137                }
 5138            }
 5139            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5140                if let Some(InlaySplice {
 5141                    to_remove,
 5142                    to_insert,
 5143                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5144                {
 5145                    self.splice_inlays(&to_remove, to_insert, cx);
 5146                }
 5147                self.display_map.update(cx, |display_map, _| {
 5148                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5149                });
 5150                return;
 5151            }
 5152            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5153            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5154                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5155            }
 5156            InlayHintRefreshReason::RefreshRequested => {
 5157                (InvalidationStrategy::RefreshRequested, None)
 5158            }
 5159        };
 5160
 5161        if let Some(InlaySplice {
 5162            to_remove,
 5163            to_insert,
 5164        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5165            reason_description,
 5166            self.visible_excerpts(required_languages.as_ref(), cx),
 5167            invalidate_cache,
 5168            ignore_debounce,
 5169            cx,
 5170        ) {
 5171            self.splice_inlays(&to_remove, to_insert, cx);
 5172        }
 5173    }
 5174
 5175    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5180            .cloned()
 5181            .collect()
 5182    }
 5183
 5184    pub fn visible_excerpts(
 5185        &self,
 5186        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5187        cx: &mut Context<Editor>,
 5188    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5189        let Some(project) = self.project.as_ref() else {
 5190            return HashMap::default();
 5191        };
 5192        let project = project.read(cx);
 5193        let multi_buffer = self.buffer().read(cx);
 5194        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5195        let multi_buffer_visible_start = self
 5196            .scroll_manager
 5197            .anchor()
 5198            .anchor
 5199            .to_point(&multi_buffer_snapshot);
 5200        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5201            multi_buffer_visible_start
 5202                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5203            Bias::Left,
 5204        );
 5205        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5206        multi_buffer_snapshot
 5207            .range_to_buffer_ranges(multi_buffer_visible_range)
 5208            .into_iter()
 5209            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5210            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5211                let buffer_file = project::File::from_dyn(buffer.file())?;
 5212                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5213                let worktree_entry = buffer_worktree
 5214                    .read(cx)
 5215                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5216                if worktree_entry.is_ignored {
 5217                    return None;
 5218                }
 5219
 5220                let language = buffer.language()?;
 5221                if let Some(restrict_to_languages) = restrict_to_languages {
 5222                    if !restrict_to_languages.contains(language) {
 5223                        return None;
 5224                    }
 5225                }
 5226                Some((
 5227                    excerpt_id,
 5228                    (
 5229                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5230                        buffer.version().clone(),
 5231                        excerpt_visible_range,
 5232                    ),
 5233                ))
 5234            })
 5235            .collect()
 5236    }
 5237
 5238    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5239        TextLayoutDetails {
 5240            text_system: window.text_system().clone(),
 5241            editor_style: self.style.clone().unwrap(),
 5242            rem_size: window.rem_size(),
 5243            scroll_anchor: self.scroll_manager.anchor(),
 5244            visible_rows: self.visible_line_count(),
 5245            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5246        }
 5247    }
 5248
 5249    pub fn splice_inlays(
 5250        &self,
 5251        to_remove: &[InlayId],
 5252        to_insert: Vec<Inlay>,
 5253        cx: &mut Context<Self>,
 5254    ) {
 5255        self.display_map.update(cx, |display_map, cx| {
 5256            display_map.splice_inlays(to_remove, to_insert, cx)
 5257        });
 5258        cx.notify();
 5259    }
 5260
 5261    fn trigger_on_type_formatting(
 5262        &self,
 5263        input: String,
 5264        window: &mut Window,
 5265        cx: &mut Context<Self>,
 5266    ) -> Option<Task<Result<()>>> {
 5267        if input.len() != 1 {
 5268            return None;
 5269        }
 5270
 5271        let project = self.project.as_ref()?;
 5272        let position = self.selections.newest_anchor().head();
 5273        let (buffer, buffer_position) = self
 5274            .buffer
 5275            .read(cx)
 5276            .text_anchor_for_position(position, cx)?;
 5277
 5278        let settings = language_settings::language_settings(
 5279            buffer
 5280                .read(cx)
 5281                .language_at(buffer_position)
 5282                .map(|l| l.name()),
 5283            buffer.read(cx).file(),
 5284            cx,
 5285        );
 5286        if !settings.use_on_type_format {
 5287            return None;
 5288        }
 5289
 5290        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5291        // hence we do LSP request & edit on host side only — add formats to host's history.
 5292        let push_to_lsp_host_history = true;
 5293        // If this is not the host, append its history with new edits.
 5294        let push_to_client_history = project.read(cx).is_via_collab();
 5295
 5296        let on_type_formatting = project.update(cx, |project, cx| {
 5297            project.on_type_format(
 5298                buffer.clone(),
 5299                buffer_position,
 5300                input,
 5301                push_to_lsp_host_history,
 5302                cx,
 5303            )
 5304        });
 5305        Some(cx.spawn_in(window, async move |editor, cx| {
 5306            if let Some(transaction) = on_type_formatting.await? {
 5307                if push_to_client_history {
 5308                    buffer
 5309                        .update(cx, |buffer, _| {
 5310                            buffer.push_transaction(transaction, Instant::now());
 5311                            buffer.finalize_last_transaction();
 5312                        })
 5313                        .ok();
 5314                }
 5315                editor.update(cx, |editor, cx| {
 5316                    editor.refresh_document_highlights(cx);
 5317                })?;
 5318            }
 5319            Ok(())
 5320        }))
 5321    }
 5322
 5323    pub fn show_word_completions(
 5324        &mut self,
 5325        _: &ShowWordCompletions,
 5326        window: &mut Window,
 5327        cx: &mut Context<Self>,
 5328    ) {
 5329        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5330    }
 5331
 5332    pub fn show_completions(
 5333        &mut self,
 5334        options: &ShowCompletions,
 5335        window: &mut Window,
 5336        cx: &mut Context<Self>,
 5337    ) {
 5338        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5339    }
 5340
 5341    fn open_or_update_completions_menu(
 5342        &mut self,
 5343        requested_source: Option<CompletionsMenuSource>,
 5344        trigger: Option<&str>,
 5345        window: &mut Window,
 5346        cx: &mut Context<Self>,
 5347    ) {
 5348        if self.pending_rename.is_some() {
 5349            return;
 5350        }
 5351
 5352        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5353
 5354        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5355        // inserted and selected. To handle that case, the start of the selection is used so that
 5356        // the menu starts with all choices.
 5357        let position = self
 5358            .selections
 5359            .newest_anchor()
 5360            .start
 5361            .bias_right(&multibuffer_snapshot);
 5362        if position.diff_base_anchor.is_some() {
 5363            return;
 5364        }
 5365        let (buffer, buffer_position) =
 5366            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5367                output
 5368            } else {
 5369                return;
 5370            };
 5371        let buffer_snapshot = buffer.read(cx).snapshot();
 5372
 5373        let query: Option<Arc<String>> =
 5374            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5375
 5376        drop(multibuffer_snapshot);
 5377
 5378        let provider = match requested_source {
 5379            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5380            Some(CompletionsMenuSource::Words) => None,
 5381            Some(CompletionsMenuSource::SnippetChoices) => {
 5382                log::error!("bug: SnippetChoices requested_source is not handled");
 5383                None
 5384            }
 5385        };
 5386
 5387        let sort_completions = provider
 5388            .as_ref()
 5389            .map_or(false, |provider| provider.sort_completions());
 5390
 5391        let filter_completions = provider
 5392            .as_ref()
 5393            .map_or(true, |provider| provider.filter_completions());
 5394
 5395        let trigger_kind = match trigger {
 5396            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5397                CompletionTriggerKind::TRIGGER_CHARACTER
 5398            }
 5399            _ => CompletionTriggerKind::INVOKED,
 5400        };
 5401        let completion_context = CompletionContext {
 5402            trigger_character: trigger.and_then(|trigger| {
 5403                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5404                    Some(String::from(trigger))
 5405                } else {
 5406                    None
 5407                }
 5408            }),
 5409            trigger_kind,
 5410        };
 5411
 5412        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5413        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5414        // involve trigger chars, so this is skipped in that case.
 5415        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5416        {
 5417            let menu_is_open = matches!(
 5418                self.context_menu.borrow().as_ref(),
 5419                Some(CodeContextMenu::Completions(_))
 5420            );
 5421            if menu_is_open {
 5422                self.hide_context_menu(window, cx);
 5423            }
 5424        }
 5425
 5426        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5427            if filter_completions {
 5428                menu.filter(query.clone(), provider.clone(), window, cx);
 5429            }
 5430            // When `is_incomplete` is false, no need to re-query completions when the current query
 5431            // is a suffix of the initial query.
 5432            if !menu.is_incomplete {
 5433                // If the new query is a suffix of the old query (typing more characters) and
 5434                // the previous result was complete, the existing completions can be filtered.
 5435                //
 5436                // Note that this is always true for snippet completions.
 5437                let query_matches = match (&menu.initial_query, &query) {
 5438                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5439                    (None, _) => true,
 5440                    _ => false,
 5441                };
 5442                if query_matches {
 5443                    let position_matches = if menu.initial_position == position {
 5444                        true
 5445                    } else {
 5446                        let snapshot = self.buffer.read(cx).read(cx);
 5447                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5448                    };
 5449                    if position_matches {
 5450                        return;
 5451                    }
 5452                }
 5453            }
 5454        };
 5455
 5456        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5457            buffer_snapshot.surrounding_word(buffer_position, false)
 5458        {
 5459            let word_to_exclude = buffer_snapshot
 5460                .text_for_range(word_range.clone())
 5461                .collect::<String>();
 5462            (
 5463                buffer_snapshot.anchor_before(word_range.start)
 5464                    ..buffer_snapshot.anchor_after(buffer_position),
 5465                Some(word_to_exclude),
 5466            )
 5467        } else {
 5468            (buffer_position..buffer_position, None)
 5469        };
 5470
 5471        let language = buffer_snapshot
 5472            .language_at(buffer_position)
 5473            .map(|language| language.name());
 5474
 5475        let completion_settings =
 5476            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5477
 5478        let show_completion_documentation = buffer_snapshot
 5479            .settings_at(buffer_position, cx)
 5480            .show_completion_documentation;
 5481
 5482        // The document can be large, so stay in reasonable bounds when searching for words,
 5483        // otherwise completion pop-up might be slow to appear.
 5484        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5485        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5486        let min_word_search = buffer_snapshot.clip_point(
 5487            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5488            Bias::Left,
 5489        );
 5490        let max_word_search = buffer_snapshot.clip_point(
 5491            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5492            Bias::Right,
 5493        );
 5494        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5495            ..buffer_snapshot.point_to_offset(max_word_search);
 5496
 5497        let skip_digits = query
 5498            .as_ref()
 5499            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5500
 5501        let (mut words, provider_responses) = match &provider {
 5502            Some(provider) => {
 5503                let provider_responses = provider.completions(
 5504                    position.excerpt_id,
 5505                    &buffer,
 5506                    buffer_position,
 5507                    completion_context,
 5508                    window,
 5509                    cx,
 5510                );
 5511
 5512                let words = match completion_settings.words {
 5513                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5514                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5515                        .background_spawn(async move {
 5516                            buffer_snapshot.words_in_range(WordsQuery {
 5517                                fuzzy_contents: None,
 5518                                range: word_search_range,
 5519                                skip_digits,
 5520                            })
 5521                        }),
 5522                };
 5523
 5524                (words, provider_responses)
 5525            }
 5526            None => (
 5527                cx.background_spawn(async move {
 5528                    buffer_snapshot.words_in_range(WordsQuery {
 5529                        fuzzy_contents: None,
 5530                        range: word_search_range,
 5531                        skip_digits,
 5532                    })
 5533                }),
 5534                Task::ready(Ok(Vec::new())),
 5535            ),
 5536        };
 5537
 5538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5539
 5540        let id = post_inc(&mut self.next_completion_id);
 5541        let task = cx.spawn_in(window, async move |editor, cx| {
 5542            let Ok(()) = editor.update(cx, |this, _| {
 5543                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5544            }) else {
 5545                return;
 5546            };
 5547
 5548            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5549            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5550            let mut completions = Vec::new();
 5551            let mut is_incomplete = false;
 5552            if let Some(provider_responses) = provider_responses.await.log_err() {
 5553                if !provider_responses.is_empty() {
 5554                    for response in provider_responses {
 5555                        completions.extend(response.completions);
 5556                        is_incomplete = is_incomplete || response.is_incomplete;
 5557                    }
 5558                    if completion_settings.words == WordsCompletionMode::Fallback {
 5559                        words = Task::ready(BTreeMap::default());
 5560                    }
 5561                }
 5562            }
 5563
 5564            let mut words = words.await;
 5565            if let Some(word_to_exclude) = &word_to_exclude {
 5566                words.remove(word_to_exclude);
 5567            }
 5568            for lsp_completion in &completions {
 5569                words.remove(&lsp_completion.new_text);
 5570            }
 5571            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5572                replace_range: word_replace_range.clone(),
 5573                new_text: word.clone(),
 5574                label: CodeLabel::plain(word, None),
 5575                icon_path: None,
 5576                documentation: None,
 5577                source: CompletionSource::BufferWord {
 5578                    word_range,
 5579                    resolved: false,
 5580                },
 5581                insert_text_mode: Some(InsertTextMode::AS_IS),
 5582                confirm: None,
 5583            }));
 5584
 5585            let menu = if completions.is_empty() {
 5586                None
 5587            } else {
 5588                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5589                    let languages = editor
 5590                        .workspace
 5591                        .as_ref()
 5592                        .and_then(|(workspace, _)| workspace.upgrade())
 5593                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5594                    let menu = CompletionsMenu::new(
 5595                        id,
 5596                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5597                        sort_completions,
 5598                        show_completion_documentation,
 5599                        position,
 5600                        query.clone(),
 5601                        is_incomplete,
 5602                        buffer.clone(),
 5603                        completions.into(),
 5604                        snippet_sort_order,
 5605                        languages,
 5606                        language,
 5607                        cx,
 5608                    );
 5609
 5610                    let query = if filter_completions { query } else { None };
 5611                    let matches_task = if let Some(query) = query {
 5612                        menu.do_async_filtering(query, cx)
 5613                    } else {
 5614                        Task::ready(menu.unfiltered_matches())
 5615                    };
 5616                    (menu, matches_task)
 5617                }) else {
 5618                    return;
 5619                };
 5620
 5621                let matches = matches_task.await;
 5622
 5623                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5624                    // Newer menu already set, so exit.
 5625                    match editor.context_menu.borrow().as_ref() {
 5626                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5627                            if prev_menu.id > id {
 5628                                return;
 5629                            }
 5630                        }
 5631                        _ => {}
 5632                    };
 5633
 5634                    // Only valid to take prev_menu because it the new menu is immediately set
 5635                    // below, or the menu is hidden.
 5636                    match editor.context_menu.borrow_mut().take() {
 5637                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5638                            let position_matches =
 5639                                if prev_menu.initial_position == menu.initial_position {
 5640                                    true
 5641                                } else {
 5642                                    let snapshot = editor.buffer.read(cx).read(cx);
 5643                                    prev_menu.initial_position.to_offset(&snapshot)
 5644                                        == menu.initial_position.to_offset(&snapshot)
 5645                                };
 5646                            if position_matches {
 5647                                // Preserve markdown cache before `set_filter_results` because it will
 5648                                // try to populate the documentation cache.
 5649                                menu.preserve_markdown_cache(prev_menu);
 5650                            }
 5651                        }
 5652                        _ => {}
 5653                    };
 5654
 5655                    menu.set_filter_results(matches, provider, window, cx);
 5656                }) else {
 5657                    return;
 5658                };
 5659
 5660                menu.visible().then_some(menu)
 5661            };
 5662
 5663            editor
 5664                .update_in(cx, |editor, window, cx| {
 5665                    if editor.focus_handle.is_focused(window) {
 5666                        if let Some(menu) = menu {
 5667                            *editor.context_menu.borrow_mut() =
 5668                                Some(CodeContextMenu::Completions(menu));
 5669
 5670                            crate::hover_popover::hide_hover(editor, cx);
 5671                            if editor.show_edit_predictions_in_menu() {
 5672                                editor.update_visible_inline_completion(window, cx);
 5673                            } else {
 5674                                editor.discard_inline_completion(false, cx);
 5675                            }
 5676
 5677                            cx.notify();
 5678                            return;
 5679                        }
 5680                    }
 5681
 5682                    if editor.completion_tasks.len() <= 1 {
 5683                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5684                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5685                        // If it was already hidden and we don't show inline completions in the menu, we should
 5686                        // also show the inline-completion when available.
 5687                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5688                            editor.update_visible_inline_completion(window, cx);
 5689                        }
 5690                    }
 5691                })
 5692                .ok();
 5693        });
 5694
 5695        self.completion_tasks.push((id, task));
 5696    }
 5697
 5698    #[cfg(feature = "test-support")]
 5699    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5700        let menu = self.context_menu.borrow();
 5701        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5702            let completions = menu.completions.borrow();
 5703            Some(completions.to_vec())
 5704        } else {
 5705            None
 5706        }
 5707    }
 5708
 5709    pub fn with_completions_menu_matching_id<R>(
 5710        &self,
 5711        id: CompletionId,
 5712        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5713    ) -> R {
 5714        let mut context_menu = self.context_menu.borrow_mut();
 5715        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5716            return f(None);
 5717        };
 5718        if completions_menu.id != id {
 5719            return f(None);
 5720        }
 5721        f(Some(completions_menu))
 5722    }
 5723
 5724    pub fn confirm_completion(
 5725        &mut self,
 5726        action: &ConfirmCompletion,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) -> Option<Task<Result<()>>> {
 5730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5731        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5732    }
 5733
 5734    pub fn confirm_completion_insert(
 5735        &mut self,
 5736        _: &ConfirmCompletionInsert,
 5737        window: &mut Window,
 5738        cx: &mut Context<Self>,
 5739    ) -> Option<Task<Result<()>>> {
 5740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5741        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5742    }
 5743
 5744    pub fn confirm_completion_replace(
 5745        &mut self,
 5746        _: &ConfirmCompletionReplace,
 5747        window: &mut Window,
 5748        cx: &mut Context<Self>,
 5749    ) -> Option<Task<Result<()>>> {
 5750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5751        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5752    }
 5753
 5754    pub fn compose_completion(
 5755        &mut self,
 5756        action: &ComposeCompletion,
 5757        window: &mut Window,
 5758        cx: &mut Context<Self>,
 5759    ) -> Option<Task<Result<()>>> {
 5760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5761        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5762    }
 5763
 5764    fn do_completion(
 5765        &mut self,
 5766        item_ix: Option<usize>,
 5767        intent: CompletionIntent,
 5768        window: &mut Window,
 5769        cx: &mut Context<Editor>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        use language::ToOffset as _;
 5772
 5773        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5774        else {
 5775            return None;
 5776        };
 5777
 5778        let candidate_id = {
 5779            let entries = completions_menu.entries.borrow();
 5780            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5781            if self.show_edit_predictions_in_menu() {
 5782                self.discard_inline_completion(true, cx);
 5783            }
 5784            mat.candidate_id
 5785        };
 5786
 5787        let completion = completions_menu
 5788            .completions
 5789            .borrow()
 5790            .get(candidate_id)?
 5791            .clone();
 5792        cx.stop_propagation();
 5793
 5794        let buffer_handle = completions_menu.buffer.clone();
 5795
 5796        let CompletionEdit {
 5797            new_text,
 5798            snippet,
 5799            replace_range,
 5800        } = process_completion_for_edit(
 5801            &completion,
 5802            intent,
 5803            &buffer_handle,
 5804            &completions_menu.initial_position.text_anchor,
 5805            cx,
 5806        );
 5807
 5808        let buffer = buffer_handle.read(cx);
 5809        let snapshot = self.buffer.read(cx).snapshot(cx);
 5810        let newest_anchor = self.selections.newest_anchor();
 5811        let replace_range_multibuffer = {
 5812            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5813            let multibuffer_anchor = snapshot
 5814                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5815                .unwrap()
 5816                ..snapshot
 5817                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5818                    .unwrap();
 5819            multibuffer_anchor.start.to_offset(&snapshot)
 5820                ..multibuffer_anchor.end.to_offset(&snapshot)
 5821        };
 5822        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5823            return None;
 5824        }
 5825
 5826        let old_text = buffer
 5827            .text_for_range(replace_range.clone())
 5828            .collect::<String>();
 5829        let lookbehind = newest_anchor
 5830            .start
 5831            .text_anchor
 5832            .to_offset(buffer)
 5833            .saturating_sub(replace_range.start);
 5834        let lookahead = replace_range
 5835            .end
 5836            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5837        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5838        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5839
 5840        let selections = self.selections.all::<usize>(cx);
 5841        let mut ranges = Vec::new();
 5842        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5843
 5844        for selection in &selections {
 5845            let range = if selection.id == newest_anchor.id {
 5846                replace_range_multibuffer.clone()
 5847            } else {
 5848                let mut range = selection.range();
 5849
 5850                // if prefix is present, don't duplicate it
 5851                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5852                    range.start = range.start.saturating_sub(lookbehind);
 5853
 5854                    // if suffix is also present, mimic the newest cursor and replace it
 5855                    if selection.id != newest_anchor.id
 5856                        && snapshot.contains_str_at(range.end, suffix)
 5857                    {
 5858                        range.end += lookahead;
 5859                    }
 5860                }
 5861                range
 5862            };
 5863
 5864            ranges.push(range.clone());
 5865
 5866            if !self.linked_edit_ranges.is_empty() {
 5867                let start_anchor = snapshot.anchor_before(range.start);
 5868                let end_anchor = snapshot.anchor_after(range.end);
 5869                if let Some(ranges) = self
 5870                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5871                {
 5872                    for (buffer, edits) in ranges {
 5873                        linked_edits
 5874                            .entry(buffer.clone())
 5875                            .or_default()
 5876                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5877                    }
 5878                }
 5879            }
 5880        }
 5881
 5882        let common_prefix_len = old_text
 5883            .chars()
 5884            .zip(new_text.chars())
 5885            .take_while(|(a, b)| a == b)
 5886            .map(|(a, _)| a.len_utf8())
 5887            .sum::<usize>();
 5888
 5889        cx.emit(EditorEvent::InputHandled {
 5890            utf16_range_to_replace: None,
 5891            text: new_text[common_prefix_len..].into(),
 5892        });
 5893
 5894        self.transact(window, cx, |this, window, cx| {
 5895            if let Some(mut snippet) = snippet {
 5896                snippet.text = new_text.to_string();
 5897                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5898            } else {
 5899                this.buffer.update(cx, |buffer, cx| {
 5900                    let auto_indent = match completion.insert_text_mode {
 5901                        Some(InsertTextMode::AS_IS) => None,
 5902                        _ => this.autoindent_mode.clone(),
 5903                    };
 5904                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5905                    buffer.edit(edits, auto_indent, cx);
 5906                });
 5907            }
 5908            for (buffer, edits) in linked_edits {
 5909                buffer.update(cx, |buffer, cx| {
 5910                    let snapshot = buffer.snapshot();
 5911                    let edits = edits
 5912                        .into_iter()
 5913                        .map(|(range, text)| {
 5914                            use text::ToPoint as TP;
 5915                            let end_point = TP::to_point(&range.end, &snapshot);
 5916                            let start_point = TP::to_point(&range.start, &snapshot);
 5917                            (start_point..end_point, text)
 5918                        })
 5919                        .sorted_by_key(|(range, _)| range.start);
 5920                    buffer.edit(edits, None, cx);
 5921                })
 5922            }
 5923
 5924            this.refresh_inline_completion(true, false, window, cx);
 5925        });
 5926
 5927        let show_new_completions_on_confirm = completion
 5928            .confirm
 5929            .as_ref()
 5930            .map_or(false, |confirm| confirm(intent, window, cx));
 5931        if show_new_completions_on_confirm {
 5932            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5933        }
 5934
 5935        let provider = self.completion_provider.as_ref()?;
 5936        drop(completion);
 5937        let apply_edits = provider.apply_additional_edits_for_completion(
 5938            buffer_handle,
 5939            completions_menu.completions.clone(),
 5940            candidate_id,
 5941            true,
 5942            cx,
 5943        );
 5944
 5945        let editor_settings = EditorSettings::get_global(cx);
 5946        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5947            // After the code completion is finished, users often want to know what signatures are needed.
 5948            // so we should automatically call signature_help
 5949            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5950        }
 5951
 5952        Some(cx.foreground_executor().spawn(async move {
 5953            apply_edits.await?;
 5954            Ok(())
 5955        }))
 5956    }
 5957
 5958    pub fn toggle_code_actions(
 5959        &mut self,
 5960        action: &ToggleCodeActions,
 5961        window: &mut Window,
 5962        cx: &mut Context<Self>,
 5963    ) {
 5964        let quick_launch = action.quick_launch;
 5965        let mut context_menu = self.context_menu.borrow_mut();
 5966        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5967            if code_actions.deployed_from == action.deployed_from {
 5968                // Toggle if we're selecting the same one
 5969                *context_menu = None;
 5970                cx.notify();
 5971                return;
 5972            } else {
 5973                // Otherwise, clear it and start a new one
 5974                *context_menu = None;
 5975                cx.notify();
 5976            }
 5977        }
 5978        drop(context_menu);
 5979        let snapshot = self.snapshot(window, cx);
 5980        let deployed_from = action.deployed_from.clone();
 5981        let action = action.clone();
 5982        self.completion_tasks.clear();
 5983        self.discard_inline_completion(false, cx);
 5984
 5985        let multibuffer_point = match &action.deployed_from {
 5986            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5987                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5988            }
 5989            _ => self.selections.newest::<Point>(cx).head(),
 5990        };
 5991        let Some((buffer, buffer_row)) = snapshot
 5992            .buffer_snapshot
 5993            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5994            .and_then(|(buffer_snapshot, range)| {
 5995                self.buffer()
 5996                    .read(cx)
 5997                    .buffer(buffer_snapshot.remote_id())
 5998                    .map(|buffer| (buffer, range.start.row))
 5999            })
 6000        else {
 6001            return;
 6002        };
 6003        let buffer_id = buffer.read(cx).remote_id();
 6004        let tasks = self
 6005            .tasks
 6006            .get(&(buffer_id, buffer_row))
 6007            .map(|t| Arc::new(t.to_owned()));
 6008
 6009        if !self.focus_handle.is_focused(window) {
 6010            return;
 6011        }
 6012        let project = self.project.clone();
 6013
 6014        let code_actions_task = match deployed_from {
 6015            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6016            _ => self.code_actions(buffer_row, window, cx),
 6017        };
 6018
 6019        let runnable_task = match deployed_from {
 6020            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6021            _ => {
 6022                let mut task_context_task = Task::ready(None);
 6023                if let Some(tasks) = &tasks {
 6024                    if let Some(project) = project {
 6025                        task_context_task =
 6026                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6027                    }
 6028                }
 6029
 6030                cx.spawn_in(window, {
 6031                    let buffer = buffer.clone();
 6032                    async move |editor, cx| {
 6033                        let task_context = task_context_task.await;
 6034
 6035                        let resolved_tasks =
 6036                            tasks
 6037                                .zip(task_context.clone())
 6038                                .map(|(tasks, task_context)| ResolvedTasks {
 6039                                    templates: tasks.resolve(&task_context).collect(),
 6040                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6041                                        multibuffer_point.row,
 6042                                        tasks.column,
 6043                                    )),
 6044                                });
 6045                        let debug_scenarios = editor
 6046                            .update(cx, |editor, cx| {
 6047                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6048                            })?
 6049                            .await;
 6050                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6051                    }
 6052                })
 6053            }
 6054        };
 6055
 6056        cx.spawn_in(window, async move |editor, cx| {
 6057            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6058            let code_actions = code_actions_task.await;
 6059            let spawn_straight_away = quick_launch
 6060                && resolved_tasks
 6061                    .as_ref()
 6062                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6063                && code_actions
 6064                    .as_ref()
 6065                    .map_or(true, |actions| actions.is_empty())
 6066                && debug_scenarios.is_empty();
 6067
 6068            editor.update_in(cx, |editor, window, cx| {
 6069                crate::hover_popover::hide_hover(editor, cx);
 6070                let actions = CodeActionContents::new(
 6071                    resolved_tasks,
 6072                    code_actions,
 6073                    debug_scenarios,
 6074                    task_context.unwrap_or_default(),
 6075                );
 6076
 6077                // Don't show the menu if there are no actions available
 6078                if actions.is_empty() {
 6079                    cx.notify();
 6080                    return Task::ready(Ok(()));
 6081                }
 6082
 6083                *editor.context_menu.borrow_mut() =
 6084                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6085                        buffer,
 6086                        actions,
 6087                        selected_item: Default::default(),
 6088                        scroll_handle: UniformListScrollHandle::default(),
 6089                        deployed_from,
 6090                    }));
 6091                cx.notify();
 6092                if spawn_straight_away {
 6093                    if let Some(task) = editor.confirm_code_action(
 6094                        &ConfirmCodeAction { item_ix: Some(0) },
 6095                        window,
 6096                        cx,
 6097                    ) {
 6098                        return task;
 6099                    }
 6100                }
 6101
 6102                Task::ready(Ok(()))
 6103            })
 6104        })
 6105        .detach_and_log_err(cx);
 6106    }
 6107
 6108    fn debug_scenarios(
 6109        &mut self,
 6110        resolved_tasks: &Option<ResolvedTasks>,
 6111        buffer: &Entity<Buffer>,
 6112        cx: &mut App,
 6113    ) -> Task<Vec<task::DebugScenario>> {
 6114        maybe!({
 6115            let project = self.project.as_ref()?;
 6116            let dap_store = project.read(cx).dap_store();
 6117            let mut scenarios = vec![];
 6118            let resolved_tasks = resolved_tasks.as_ref()?;
 6119            let buffer = buffer.read(cx);
 6120            let language = buffer.language()?;
 6121            let file = buffer.file();
 6122            let debug_adapter = language_settings(language.name().into(), file, cx)
 6123                .debuggers
 6124                .first()
 6125                .map(SharedString::from)
 6126                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6127
 6128            dap_store.update(cx, |dap_store, cx| {
 6129                for (_, task) in &resolved_tasks.templates {
 6130                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6131                        task.original_task().clone(),
 6132                        debug_adapter.clone().into(),
 6133                        task.display_label().to_owned().into(),
 6134                        cx,
 6135                    );
 6136                    scenarios.push(maybe_scenario);
 6137                }
 6138            });
 6139            Some(cx.background_spawn(async move {
 6140                let scenarios = futures::future::join_all(scenarios)
 6141                    .await
 6142                    .into_iter()
 6143                    .flatten()
 6144                    .collect::<Vec<_>>();
 6145                scenarios
 6146            }))
 6147        })
 6148        .unwrap_or_else(|| Task::ready(vec![]))
 6149    }
 6150
 6151    fn code_actions(
 6152        &mut self,
 6153        buffer_row: u32,
 6154        window: &mut Window,
 6155        cx: &mut Context<Self>,
 6156    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6157        let mut task = self.code_actions_task.take();
 6158        cx.spawn_in(window, async move |editor, cx| {
 6159            while let Some(prev_task) = task {
 6160                prev_task.await.log_err();
 6161                task = editor
 6162                    .update(cx, |this, _| this.code_actions_task.take())
 6163                    .ok()?;
 6164            }
 6165
 6166            editor
 6167                .update(cx, |editor, cx| {
 6168                    editor
 6169                        .available_code_actions
 6170                        .clone()
 6171                        .and_then(|(location, code_actions)| {
 6172                            let snapshot = location.buffer.read(cx).snapshot();
 6173                            let point_range = location.range.to_point(&snapshot);
 6174                            let point_range = point_range.start.row..=point_range.end.row;
 6175                            if point_range.contains(&buffer_row) {
 6176                                Some(code_actions)
 6177                            } else {
 6178                                None
 6179                            }
 6180                        })
 6181                })
 6182                .ok()
 6183                .flatten()
 6184        })
 6185    }
 6186
 6187    pub fn confirm_code_action(
 6188        &mut self,
 6189        action: &ConfirmCodeAction,
 6190        window: &mut Window,
 6191        cx: &mut Context<Self>,
 6192    ) -> Option<Task<Result<()>>> {
 6193        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6194
 6195        let actions_menu =
 6196            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6197                menu
 6198            } else {
 6199                return None;
 6200            };
 6201
 6202        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6203        let action = actions_menu.actions.get(action_ix)?;
 6204        let title = action.label();
 6205        let buffer = actions_menu.buffer;
 6206        let workspace = self.workspace()?;
 6207
 6208        match action {
 6209            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6210                workspace.update(cx, |workspace, cx| {
 6211                    workspace.schedule_resolved_task(
 6212                        task_source_kind,
 6213                        resolved_task,
 6214                        false,
 6215                        window,
 6216                        cx,
 6217                    );
 6218
 6219                    Some(Task::ready(Ok(())))
 6220                })
 6221            }
 6222            CodeActionsItem::CodeAction {
 6223                excerpt_id,
 6224                action,
 6225                provider,
 6226            } => {
 6227                let apply_code_action =
 6228                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6229                let workspace = workspace.downgrade();
 6230                Some(cx.spawn_in(window, async move |editor, cx| {
 6231                    let project_transaction = apply_code_action.await?;
 6232                    Self::open_project_transaction(
 6233                        &editor,
 6234                        workspace,
 6235                        project_transaction,
 6236                        title,
 6237                        cx,
 6238                    )
 6239                    .await
 6240                }))
 6241            }
 6242            CodeActionsItem::DebugScenario(scenario) => {
 6243                let context = actions_menu.actions.context.clone();
 6244
 6245                workspace.update(cx, |workspace, cx| {
 6246                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6247                    workspace.start_debug_session(
 6248                        scenario,
 6249                        context,
 6250                        Some(buffer),
 6251                        None,
 6252                        window,
 6253                        cx,
 6254                    );
 6255                });
 6256                Some(Task::ready(Ok(())))
 6257            }
 6258        }
 6259    }
 6260
 6261    pub async fn open_project_transaction(
 6262        this: &WeakEntity<Editor>,
 6263        workspace: WeakEntity<Workspace>,
 6264        transaction: ProjectTransaction,
 6265        title: String,
 6266        cx: &mut AsyncWindowContext,
 6267    ) -> Result<()> {
 6268        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6269        cx.update(|_, cx| {
 6270            entries.sort_unstable_by_key(|(buffer, _)| {
 6271                buffer.read(cx).file().map(|f| f.path().clone())
 6272            });
 6273        })?;
 6274
 6275        // If the project transaction's edits are all contained within this editor, then
 6276        // avoid opening a new editor to display them.
 6277
 6278        if let Some((buffer, transaction)) = entries.first() {
 6279            if entries.len() == 1 {
 6280                let excerpt = this.update(cx, |editor, cx| {
 6281                    editor
 6282                        .buffer()
 6283                        .read(cx)
 6284                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6285                })?;
 6286                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6287                    if excerpted_buffer == *buffer {
 6288                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6289                            let excerpt_range = excerpt_range.to_offset(buffer);
 6290                            buffer
 6291                                .edited_ranges_for_transaction::<usize>(transaction)
 6292                                .all(|range| {
 6293                                    excerpt_range.start <= range.start
 6294                                        && excerpt_range.end >= range.end
 6295                                })
 6296                        })?;
 6297
 6298                        if all_edits_within_excerpt {
 6299                            return Ok(());
 6300                        }
 6301                    }
 6302                }
 6303            }
 6304        } else {
 6305            return Ok(());
 6306        }
 6307
 6308        let mut ranges_to_highlight = Vec::new();
 6309        let excerpt_buffer = cx.new(|cx| {
 6310            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6311            for (buffer_handle, transaction) in &entries {
 6312                let edited_ranges = buffer_handle
 6313                    .read(cx)
 6314                    .edited_ranges_for_transaction::<Point>(transaction)
 6315                    .collect::<Vec<_>>();
 6316                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6317                    PathKey::for_buffer(buffer_handle, cx),
 6318                    buffer_handle.clone(),
 6319                    edited_ranges,
 6320                    DEFAULT_MULTIBUFFER_CONTEXT,
 6321                    cx,
 6322                );
 6323
 6324                ranges_to_highlight.extend(ranges);
 6325            }
 6326            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6327            multibuffer
 6328        })?;
 6329
 6330        workspace.update_in(cx, |workspace, window, cx| {
 6331            let project = workspace.project().clone();
 6332            let editor =
 6333                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6334            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6335            editor.update(cx, |editor, cx| {
 6336                editor.highlight_background::<Self>(
 6337                    &ranges_to_highlight,
 6338                    |theme| theme.colors().editor_highlighted_line_background,
 6339                    cx,
 6340                );
 6341            });
 6342        })?;
 6343
 6344        Ok(())
 6345    }
 6346
 6347    pub fn clear_code_action_providers(&mut self) {
 6348        self.code_action_providers.clear();
 6349        self.available_code_actions.take();
 6350    }
 6351
 6352    pub fn add_code_action_provider(
 6353        &mut self,
 6354        provider: Rc<dyn CodeActionProvider>,
 6355        window: &mut Window,
 6356        cx: &mut Context<Self>,
 6357    ) {
 6358        if self
 6359            .code_action_providers
 6360            .iter()
 6361            .any(|existing_provider| existing_provider.id() == provider.id())
 6362        {
 6363            return;
 6364        }
 6365
 6366        self.code_action_providers.push(provider);
 6367        self.refresh_code_actions(window, cx);
 6368    }
 6369
 6370    pub fn remove_code_action_provider(
 6371        &mut self,
 6372        id: Arc<str>,
 6373        window: &mut Window,
 6374        cx: &mut Context<Self>,
 6375    ) {
 6376        self.code_action_providers
 6377            .retain(|provider| provider.id() != id);
 6378        self.refresh_code_actions(window, cx);
 6379    }
 6380
 6381    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6382        !self.code_action_providers.is_empty()
 6383            && EditorSettings::get_global(cx).toolbar.code_actions
 6384    }
 6385
 6386    pub fn has_available_code_actions(&self) -> bool {
 6387        self.available_code_actions
 6388            .as_ref()
 6389            .is_some_and(|(_, actions)| !actions.is_empty())
 6390    }
 6391
 6392    fn render_inline_code_actions(
 6393        &self,
 6394        icon_size: ui::IconSize,
 6395        display_row: DisplayRow,
 6396        is_active: bool,
 6397        cx: &mut Context<Self>,
 6398    ) -> AnyElement {
 6399        let show_tooltip = !self.context_menu_visible();
 6400        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6401            .icon_size(icon_size)
 6402            .shape(ui::IconButtonShape::Square)
 6403            .style(ButtonStyle::Transparent)
 6404            .icon_color(ui::Color::Hidden)
 6405            .toggle_state(is_active)
 6406            .when(show_tooltip, |this| {
 6407                this.tooltip({
 6408                    let focus_handle = self.focus_handle.clone();
 6409                    move |window, cx| {
 6410                        Tooltip::for_action_in(
 6411                            "Toggle Code Actions",
 6412                            &ToggleCodeActions {
 6413                                deployed_from: None,
 6414                                quick_launch: false,
 6415                            },
 6416                            &focus_handle,
 6417                            window,
 6418                            cx,
 6419                        )
 6420                    }
 6421                })
 6422            })
 6423            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6424                window.focus(&editor.focus_handle(cx));
 6425                editor.toggle_code_actions(
 6426                    &crate::actions::ToggleCodeActions {
 6427                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6428                            display_row,
 6429                        )),
 6430                        quick_launch: false,
 6431                    },
 6432                    window,
 6433                    cx,
 6434                );
 6435            }))
 6436            .into_any_element()
 6437    }
 6438
 6439    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6440        &self.context_menu
 6441    }
 6442
 6443    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6444        let newest_selection = self.selections.newest_anchor().clone();
 6445        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6446        let buffer = self.buffer.read(cx);
 6447        if newest_selection.head().diff_base_anchor.is_some() {
 6448            return None;
 6449        }
 6450        let (start_buffer, start) =
 6451            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6452        let (end_buffer, end) =
 6453            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6454        if start_buffer != end_buffer {
 6455            return None;
 6456        }
 6457
 6458        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6459            cx.background_executor()
 6460                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6461                .await;
 6462
 6463            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6464                let providers = this.code_action_providers.clone();
 6465                let tasks = this
 6466                    .code_action_providers
 6467                    .iter()
 6468                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6469                    .collect::<Vec<_>>();
 6470                (providers, tasks)
 6471            })?;
 6472
 6473            let mut actions = Vec::new();
 6474            for (provider, provider_actions) in
 6475                providers.into_iter().zip(future::join_all(tasks).await)
 6476            {
 6477                if let Some(provider_actions) = provider_actions.log_err() {
 6478                    actions.extend(provider_actions.into_iter().map(|action| {
 6479                        AvailableCodeAction {
 6480                            excerpt_id: newest_selection.start.excerpt_id,
 6481                            action,
 6482                            provider: provider.clone(),
 6483                        }
 6484                    }));
 6485                }
 6486            }
 6487
 6488            this.update(cx, |this, cx| {
 6489                this.available_code_actions = if actions.is_empty() {
 6490                    None
 6491                } else {
 6492                    Some((
 6493                        Location {
 6494                            buffer: start_buffer,
 6495                            range: start..end,
 6496                        },
 6497                        actions.into(),
 6498                    ))
 6499                };
 6500                cx.notify();
 6501            })
 6502        }));
 6503        None
 6504    }
 6505
 6506    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6507        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6508            self.show_git_blame_inline = false;
 6509
 6510            self.show_git_blame_inline_delay_task =
 6511                Some(cx.spawn_in(window, async move |this, cx| {
 6512                    cx.background_executor().timer(delay).await;
 6513
 6514                    this.update(cx, |this, cx| {
 6515                        this.show_git_blame_inline = true;
 6516                        cx.notify();
 6517                    })
 6518                    .log_err();
 6519                }));
 6520        }
 6521    }
 6522
 6523    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6524        let snapshot = self.snapshot(window, cx);
 6525        let cursor = self.selections.newest::<Point>(cx).head();
 6526        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6527        else {
 6528            return;
 6529        };
 6530
 6531        let Some(blame) = self.blame.as_ref() else {
 6532            return;
 6533        };
 6534
 6535        let row_info = RowInfo {
 6536            buffer_id: Some(buffer.remote_id()),
 6537            buffer_row: Some(point.row),
 6538            ..Default::default()
 6539        };
 6540        let Some(blame_entry) = blame
 6541            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6542            .flatten()
 6543        else {
 6544            return;
 6545        };
 6546
 6547        let anchor = self.selections.newest_anchor().head();
 6548        let position = self.to_pixel_point(anchor, &snapshot, window);
 6549        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6550            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6551        };
 6552    }
 6553
 6554    fn show_blame_popover(
 6555        &mut self,
 6556        blame_entry: &BlameEntry,
 6557        position: gpui::Point<Pixels>,
 6558        ignore_timeout: bool,
 6559        cx: &mut Context<Self>,
 6560    ) {
 6561        if let Some(state) = &mut self.inline_blame_popover {
 6562            state.hide_task.take();
 6563        } else {
 6564            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6565            let blame_entry = blame_entry.clone();
 6566            let show_task = cx.spawn(async move |editor, cx| {
 6567                if !ignore_timeout {
 6568                    cx.background_executor()
 6569                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6570                        .await;
 6571                }
 6572                editor
 6573                    .update(cx, |editor, cx| {
 6574                        editor.inline_blame_popover_show_task.take();
 6575                        let Some(blame) = editor.blame.as_ref() else {
 6576                            return;
 6577                        };
 6578                        let blame = blame.read(cx);
 6579                        let details = blame.details_for_entry(&blame_entry);
 6580                        let markdown = cx.new(|cx| {
 6581                            Markdown::new(
 6582                                details
 6583                                    .as_ref()
 6584                                    .map(|message| message.message.clone())
 6585                                    .unwrap_or_default(),
 6586                                None,
 6587                                None,
 6588                                cx,
 6589                            )
 6590                        });
 6591                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6592                            position,
 6593                            hide_task: None,
 6594                            popover_bounds: None,
 6595                            popover_state: InlineBlamePopoverState {
 6596                                scroll_handle: ScrollHandle::new(),
 6597                                commit_message: details,
 6598                                markdown,
 6599                            },
 6600                            keyboard_grace: ignore_timeout,
 6601                        });
 6602                        cx.notify();
 6603                    })
 6604                    .ok();
 6605            });
 6606            self.inline_blame_popover_show_task = Some(show_task);
 6607        }
 6608    }
 6609
 6610    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6611        self.inline_blame_popover_show_task.take();
 6612        if let Some(state) = &mut self.inline_blame_popover {
 6613            let hide_task = cx.spawn(async move |editor, cx| {
 6614                cx.background_executor()
 6615                    .timer(std::time::Duration::from_millis(100))
 6616                    .await;
 6617                editor
 6618                    .update(cx, |editor, cx| {
 6619                        editor.inline_blame_popover.take();
 6620                        cx.notify();
 6621                    })
 6622                    .ok();
 6623            });
 6624            state.hide_task = Some(hide_task);
 6625        }
 6626    }
 6627
 6628    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6629        if self.pending_rename.is_some() {
 6630            return None;
 6631        }
 6632
 6633        let provider = self.semantics_provider.clone()?;
 6634        let buffer = self.buffer.read(cx);
 6635        let newest_selection = self.selections.newest_anchor().clone();
 6636        let cursor_position = newest_selection.head();
 6637        let (cursor_buffer, cursor_buffer_position) =
 6638            buffer.text_anchor_for_position(cursor_position, cx)?;
 6639        let (tail_buffer, tail_buffer_position) =
 6640            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6641        if cursor_buffer != tail_buffer {
 6642            return None;
 6643        }
 6644
 6645        let snapshot = cursor_buffer.read(cx).snapshot();
 6646        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6647        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6648        if start_word_range != end_word_range {
 6649            self.document_highlights_task.take();
 6650            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6651            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6652            return None;
 6653        }
 6654
 6655        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6656        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6657            cx.background_executor()
 6658                .timer(Duration::from_millis(debounce))
 6659                .await;
 6660
 6661            let highlights = if let Some(highlights) = cx
 6662                .update(|cx| {
 6663                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6664                })
 6665                .ok()
 6666                .flatten()
 6667            {
 6668                highlights.await.log_err()
 6669            } else {
 6670                None
 6671            };
 6672
 6673            if let Some(highlights) = highlights {
 6674                this.update(cx, |this, cx| {
 6675                    if this.pending_rename.is_some() {
 6676                        return;
 6677                    }
 6678
 6679                    let buffer_id = cursor_position.buffer_id;
 6680                    let buffer = this.buffer.read(cx);
 6681                    if !buffer
 6682                        .text_anchor_for_position(cursor_position, cx)
 6683                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6684                    {
 6685                        return;
 6686                    }
 6687
 6688                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6689                    let mut write_ranges = Vec::new();
 6690                    let mut read_ranges = Vec::new();
 6691                    for highlight in highlights {
 6692                        for (excerpt_id, excerpt_range) in
 6693                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6694                        {
 6695                            let start = highlight
 6696                                .range
 6697                                .start
 6698                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6699                            let end = highlight
 6700                                .range
 6701                                .end
 6702                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6703                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6704                                continue;
 6705                            }
 6706
 6707                            let range = Anchor {
 6708                                buffer_id,
 6709                                excerpt_id,
 6710                                text_anchor: start,
 6711                                diff_base_anchor: None,
 6712                            }..Anchor {
 6713                                buffer_id,
 6714                                excerpt_id,
 6715                                text_anchor: end,
 6716                                diff_base_anchor: None,
 6717                            };
 6718                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6719                                write_ranges.push(range);
 6720                            } else {
 6721                                read_ranges.push(range);
 6722                            }
 6723                        }
 6724                    }
 6725
 6726                    this.highlight_background::<DocumentHighlightRead>(
 6727                        &read_ranges,
 6728                        |theme| theme.colors().editor_document_highlight_read_background,
 6729                        cx,
 6730                    );
 6731                    this.highlight_background::<DocumentHighlightWrite>(
 6732                        &write_ranges,
 6733                        |theme| theme.colors().editor_document_highlight_write_background,
 6734                        cx,
 6735                    );
 6736                    cx.notify();
 6737                })
 6738                .log_err();
 6739            }
 6740        }));
 6741        None
 6742    }
 6743
 6744    fn prepare_highlight_query_from_selection(
 6745        &mut self,
 6746        cx: &mut Context<Editor>,
 6747    ) -> Option<(String, Range<Anchor>)> {
 6748        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6749            return None;
 6750        }
 6751        if !EditorSettings::get_global(cx).selection_highlight {
 6752            return None;
 6753        }
 6754        if self.selections.count() != 1 || self.selections.line_mode {
 6755            return None;
 6756        }
 6757        let selection = self.selections.newest::<Point>(cx);
 6758        if selection.is_empty() || selection.start.row != selection.end.row {
 6759            return None;
 6760        }
 6761        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6762        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6763        let query = multi_buffer_snapshot
 6764            .text_for_range(selection_anchor_range.clone())
 6765            .collect::<String>();
 6766        if query.trim().is_empty() {
 6767            return None;
 6768        }
 6769        Some((query, selection_anchor_range))
 6770    }
 6771
 6772    fn update_selection_occurrence_highlights(
 6773        &mut self,
 6774        query_text: String,
 6775        query_range: Range<Anchor>,
 6776        multi_buffer_range_to_query: Range<Point>,
 6777        use_debounce: bool,
 6778        window: &mut Window,
 6779        cx: &mut Context<Editor>,
 6780    ) -> Task<()> {
 6781        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6782        cx.spawn_in(window, async move |editor, cx| {
 6783            if use_debounce {
 6784                cx.background_executor()
 6785                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6786                    .await;
 6787            }
 6788            let match_task = cx.background_spawn(async move {
 6789                let buffer_ranges = multi_buffer_snapshot
 6790                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6791                    .into_iter()
 6792                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6793                let mut match_ranges = Vec::new();
 6794                let Ok(regex) = project::search::SearchQuery::text(
 6795                    query_text.clone(),
 6796                    false,
 6797                    false,
 6798                    false,
 6799                    Default::default(),
 6800                    Default::default(),
 6801                    false,
 6802                    None,
 6803                ) else {
 6804                    return Vec::default();
 6805                };
 6806                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6807                    match_ranges.extend(
 6808                        regex
 6809                            .search(&buffer_snapshot, Some(search_range.clone()))
 6810                            .await
 6811                            .into_iter()
 6812                            .filter_map(|match_range| {
 6813                                let match_start = buffer_snapshot
 6814                                    .anchor_after(search_range.start + match_range.start);
 6815                                let match_end = buffer_snapshot
 6816                                    .anchor_before(search_range.start + match_range.end);
 6817                                let match_anchor_range = Anchor::range_in_buffer(
 6818                                    excerpt_id,
 6819                                    buffer_snapshot.remote_id(),
 6820                                    match_start..match_end,
 6821                                );
 6822                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6823                            }),
 6824                    );
 6825                }
 6826                match_ranges
 6827            });
 6828            let match_ranges = match_task.await;
 6829            editor
 6830                .update_in(cx, |editor, _, cx| {
 6831                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6832                    if !match_ranges.is_empty() {
 6833                        editor.highlight_background::<SelectedTextHighlight>(
 6834                            &match_ranges,
 6835                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6836                            cx,
 6837                        )
 6838                    }
 6839                })
 6840                .log_err();
 6841        })
 6842    }
 6843
 6844    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6845        struct NewlineFold;
 6846        let type_id = std::any::TypeId::of::<NewlineFold>();
 6847        if !self.mode.is_single_line() {
 6848            return;
 6849        }
 6850        let snapshot = self.snapshot(window, cx);
 6851        if snapshot.buffer_snapshot.max_point().row == 0 {
 6852            return;
 6853        }
 6854        let task = cx.background_spawn(async move {
 6855            let new_newlines = snapshot
 6856                .buffer_chars_at(0)
 6857                .filter_map(|(c, i)| {
 6858                    if c == '\n' {
 6859                        Some(
 6860                            snapshot.buffer_snapshot.anchor_after(i)
 6861                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6862                        )
 6863                    } else {
 6864                        None
 6865                    }
 6866                })
 6867                .collect::<Vec<_>>();
 6868            let existing_newlines = snapshot
 6869                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6870                .filter_map(|fold| {
 6871                    if fold.placeholder.type_tag == Some(type_id) {
 6872                        Some(fold.range.start..fold.range.end)
 6873                    } else {
 6874                        None
 6875                    }
 6876                })
 6877                .collect::<Vec<_>>();
 6878
 6879            (new_newlines, existing_newlines)
 6880        });
 6881        self.folding_newlines = cx.spawn(async move |this, cx| {
 6882            let (new_newlines, existing_newlines) = task.await;
 6883            if new_newlines == existing_newlines {
 6884                return;
 6885            }
 6886            let placeholder = FoldPlaceholder {
 6887                render: Arc::new(move |_, _, cx| {
 6888                    div()
 6889                        .bg(cx.theme().status().hint_background)
 6890                        .border_b_1()
 6891                        .size_full()
 6892                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6893                        .border_color(cx.theme().status().hint)
 6894                        .child("\\n")
 6895                        .into_any()
 6896                }),
 6897                constrain_width: false,
 6898                merge_adjacent: false,
 6899                type_tag: Some(type_id),
 6900            };
 6901            let creases = new_newlines
 6902                .into_iter()
 6903                .map(|range| Crease::simple(range, placeholder.clone()))
 6904                .collect();
 6905            this.update(cx, |this, cx| {
 6906                this.display_map.update(cx, |display_map, cx| {
 6907                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6908                    display_map.fold(creases, cx);
 6909                });
 6910            })
 6911            .ok();
 6912        });
 6913    }
 6914
 6915    fn refresh_selected_text_highlights(
 6916        &mut self,
 6917        on_buffer_edit: bool,
 6918        window: &mut Window,
 6919        cx: &mut Context<Editor>,
 6920    ) {
 6921        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6922        else {
 6923            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6924            self.quick_selection_highlight_task.take();
 6925            self.debounced_selection_highlight_task.take();
 6926            return;
 6927        };
 6928        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6929        if on_buffer_edit
 6930            || self
 6931                .quick_selection_highlight_task
 6932                .as_ref()
 6933                .map_or(true, |(prev_anchor_range, _)| {
 6934                    prev_anchor_range != &query_range
 6935                })
 6936        {
 6937            let multi_buffer_visible_start = self
 6938                .scroll_manager
 6939                .anchor()
 6940                .anchor
 6941                .to_point(&multi_buffer_snapshot);
 6942            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6943                multi_buffer_visible_start
 6944                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6945                Bias::Left,
 6946            );
 6947            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6948            self.quick_selection_highlight_task = Some((
 6949                query_range.clone(),
 6950                self.update_selection_occurrence_highlights(
 6951                    query_text.clone(),
 6952                    query_range.clone(),
 6953                    multi_buffer_visible_range,
 6954                    false,
 6955                    window,
 6956                    cx,
 6957                ),
 6958            ));
 6959        }
 6960        if on_buffer_edit
 6961            || self
 6962                .debounced_selection_highlight_task
 6963                .as_ref()
 6964                .map_or(true, |(prev_anchor_range, _)| {
 6965                    prev_anchor_range != &query_range
 6966                })
 6967        {
 6968            let multi_buffer_start = multi_buffer_snapshot
 6969                .anchor_before(0)
 6970                .to_point(&multi_buffer_snapshot);
 6971            let multi_buffer_end = multi_buffer_snapshot
 6972                .anchor_after(multi_buffer_snapshot.len())
 6973                .to_point(&multi_buffer_snapshot);
 6974            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6975            self.debounced_selection_highlight_task = Some((
 6976                query_range.clone(),
 6977                self.update_selection_occurrence_highlights(
 6978                    query_text,
 6979                    query_range,
 6980                    multi_buffer_full_range,
 6981                    true,
 6982                    window,
 6983                    cx,
 6984                ),
 6985            ));
 6986        }
 6987    }
 6988
 6989    pub fn refresh_inline_completion(
 6990        &mut self,
 6991        debounce: bool,
 6992        user_requested: bool,
 6993        window: &mut Window,
 6994        cx: &mut Context<Self>,
 6995    ) -> Option<()> {
 6996        let provider = self.edit_prediction_provider()?;
 6997        let cursor = self.selections.newest_anchor().head();
 6998        let (buffer, cursor_buffer_position) =
 6999            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7000
 7001        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7002            self.discard_inline_completion(false, cx);
 7003            return None;
 7004        }
 7005
 7006        if !user_requested
 7007            && (!self.should_show_edit_predictions()
 7008                || !self.is_focused(window)
 7009                || buffer.read(cx).is_empty())
 7010        {
 7011            self.discard_inline_completion(false, cx);
 7012            return None;
 7013        }
 7014
 7015        self.update_visible_inline_completion(window, cx);
 7016        provider.refresh(
 7017            self.project.clone(),
 7018            buffer,
 7019            cursor_buffer_position,
 7020            debounce,
 7021            cx,
 7022        );
 7023        Some(())
 7024    }
 7025
 7026    fn show_edit_predictions_in_menu(&self) -> bool {
 7027        match self.edit_prediction_settings {
 7028            EditPredictionSettings::Disabled => false,
 7029            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7030        }
 7031    }
 7032
 7033    pub fn edit_predictions_enabled(&self) -> bool {
 7034        match self.edit_prediction_settings {
 7035            EditPredictionSettings::Disabled => false,
 7036            EditPredictionSettings::Enabled { .. } => true,
 7037        }
 7038    }
 7039
 7040    fn edit_prediction_requires_modifier(&self) -> bool {
 7041        match self.edit_prediction_settings {
 7042            EditPredictionSettings::Disabled => false,
 7043            EditPredictionSettings::Enabled {
 7044                preview_requires_modifier,
 7045                ..
 7046            } => preview_requires_modifier,
 7047        }
 7048    }
 7049
 7050    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7051        if self.edit_prediction_provider.is_none() {
 7052            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7053        } else {
 7054            let selection = self.selections.newest_anchor();
 7055            let cursor = selection.head();
 7056
 7057            if let Some((buffer, cursor_buffer_position)) =
 7058                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7059            {
 7060                self.edit_prediction_settings =
 7061                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7062            }
 7063        }
 7064    }
 7065
 7066    fn edit_prediction_settings_at_position(
 7067        &self,
 7068        buffer: &Entity<Buffer>,
 7069        buffer_position: language::Anchor,
 7070        cx: &App,
 7071    ) -> EditPredictionSettings {
 7072        if !self.mode.is_full()
 7073            || !self.show_inline_completions_override.unwrap_or(true)
 7074            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 7075        {
 7076            return EditPredictionSettings::Disabled;
 7077        }
 7078
 7079        let buffer = buffer.read(cx);
 7080
 7081        let file = buffer.file();
 7082
 7083        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7084            return EditPredictionSettings::Disabled;
 7085        };
 7086
 7087        let by_provider = matches!(
 7088            self.menu_inline_completions_policy,
 7089            MenuInlineCompletionsPolicy::ByProvider
 7090        );
 7091
 7092        let show_in_menu = by_provider
 7093            && self
 7094                .edit_prediction_provider
 7095                .as_ref()
 7096                .map_or(false, |provider| {
 7097                    provider.provider.show_completions_in_menu()
 7098                });
 7099
 7100        let preview_requires_modifier =
 7101            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7102
 7103        EditPredictionSettings::Enabled {
 7104            show_in_menu,
 7105            preview_requires_modifier,
 7106        }
 7107    }
 7108
 7109    fn should_show_edit_predictions(&self) -> bool {
 7110        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7111    }
 7112
 7113    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7114        matches!(
 7115            self.edit_prediction_preview,
 7116            EditPredictionPreview::Active { .. }
 7117        )
 7118    }
 7119
 7120    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7121        let cursor = self.selections.newest_anchor().head();
 7122        if let Some((buffer, cursor_position)) =
 7123            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7124        {
 7125            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7126        } else {
 7127            false
 7128        }
 7129    }
 7130
 7131    pub fn supports_minimap(&self, cx: &App) -> bool {
 7132        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7133    }
 7134
 7135    fn edit_predictions_enabled_in_buffer(
 7136        &self,
 7137        buffer: &Entity<Buffer>,
 7138        buffer_position: language::Anchor,
 7139        cx: &App,
 7140    ) -> bool {
 7141        maybe!({
 7142            if self.read_only(cx) {
 7143                return Some(false);
 7144            }
 7145            let provider = self.edit_prediction_provider()?;
 7146            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7147                return Some(false);
 7148            }
 7149            let buffer = buffer.read(cx);
 7150            let Some(file) = buffer.file() else {
 7151                return Some(true);
 7152            };
 7153            let settings = all_language_settings(Some(file), cx);
 7154            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7155        })
 7156        .unwrap_or(false)
 7157    }
 7158
 7159    fn cycle_inline_completion(
 7160        &mut self,
 7161        direction: Direction,
 7162        window: &mut Window,
 7163        cx: &mut Context<Self>,
 7164    ) -> Option<()> {
 7165        let provider = self.edit_prediction_provider()?;
 7166        let cursor = self.selections.newest_anchor().head();
 7167        let (buffer, cursor_buffer_position) =
 7168            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7169        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7170            return None;
 7171        }
 7172
 7173        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7174        self.update_visible_inline_completion(window, cx);
 7175
 7176        Some(())
 7177    }
 7178
 7179    pub fn show_inline_completion(
 7180        &mut self,
 7181        _: &ShowEditPrediction,
 7182        window: &mut Window,
 7183        cx: &mut Context<Self>,
 7184    ) {
 7185        if !self.has_active_inline_completion() {
 7186            self.refresh_inline_completion(false, true, window, cx);
 7187            return;
 7188        }
 7189
 7190        self.update_visible_inline_completion(window, cx);
 7191    }
 7192
 7193    pub fn display_cursor_names(
 7194        &mut self,
 7195        _: &DisplayCursorNames,
 7196        window: &mut Window,
 7197        cx: &mut Context<Self>,
 7198    ) {
 7199        self.show_cursor_names(window, cx);
 7200    }
 7201
 7202    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7203        self.show_cursor_names = true;
 7204        cx.notify();
 7205        cx.spawn_in(window, async move |this, cx| {
 7206            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7207            this.update(cx, |this, cx| {
 7208                this.show_cursor_names = false;
 7209                cx.notify()
 7210            })
 7211            .ok()
 7212        })
 7213        .detach();
 7214    }
 7215
 7216    pub fn next_edit_prediction(
 7217        &mut self,
 7218        _: &NextEditPrediction,
 7219        window: &mut Window,
 7220        cx: &mut Context<Self>,
 7221    ) {
 7222        if self.has_active_inline_completion() {
 7223            self.cycle_inline_completion(Direction::Next, window, cx);
 7224        } else {
 7225            let is_copilot_disabled = self
 7226                .refresh_inline_completion(false, true, window, cx)
 7227                .is_none();
 7228            if is_copilot_disabled {
 7229                cx.propagate();
 7230            }
 7231        }
 7232    }
 7233
 7234    pub fn previous_edit_prediction(
 7235        &mut self,
 7236        _: &PreviousEditPrediction,
 7237        window: &mut Window,
 7238        cx: &mut Context<Self>,
 7239    ) {
 7240        if self.has_active_inline_completion() {
 7241            self.cycle_inline_completion(Direction::Prev, window, cx);
 7242        } else {
 7243            let is_copilot_disabled = self
 7244                .refresh_inline_completion(false, true, window, cx)
 7245                .is_none();
 7246            if is_copilot_disabled {
 7247                cx.propagate();
 7248            }
 7249        }
 7250    }
 7251
 7252    pub fn accept_edit_prediction(
 7253        &mut self,
 7254        _: &AcceptEditPrediction,
 7255        window: &mut Window,
 7256        cx: &mut Context<Self>,
 7257    ) {
 7258        if self.show_edit_predictions_in_menu() {
 7259            self.hide_context_menu(window, cx);
 7260        }
 7261
 7262        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7263            return;
 7264        };
 7265
 7266        self.report_inline_completion_event(
 7267            active_inline_completion.completion_id.clone(),
 7268            true,
 7269            cx,
 7270        );
 7271
 7272        match &active_inline_completion.completion {
 7273            InlineCompletion::Move { target, .. } => {
 7274                let target = *target;
 7275
 7276                if let Some(position_map) = &self.last_position_map {
 7277                    if position_map
 7278                        .visible_row_range
 7279                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7280                        || !self.edit_prediction_requires_modifier()
 7281                    {
 7282                        self.unfold_ranges(&[target..target], true, false, cx);
 7283                        // Note that this is also done in vim's handler of the Tab action.
 7284                        self.change_selections(
 7285                            SelectionEffects::scroll(Autoscroll::newest()),
 7286                            window,
 7287                            cx,
 7288                            |selections| {
 7289                                selections.select_anchor_ranges([target..target]);
 7290                            },
 7291                        );
 7292                        self.clear_row_highlights::<EditPredictionPreview>();
 7293
 7294                        self.edit_prediction_preview
 7295                            .set_previous_scroll_position(None);
 7296                    } else {
 7297                        self.edit_prediction_preview
 7298                            .set_previous_scroll_position(Some(
 7299                                position_map.snapshot.scroll_anchor,
 7300                            ));
 7301
 7302                        self.highlight_rows::<EditPredictionPreview>(
 7303                            target..target,
 7304                            cx.theme().colors().editor_highlighted_line_background,
 7305                            RowHighlightOptions {
 7306                                autoscroll: true,
 7307                                ..Default::default()
 7308                            },
 7309                            cx,
 7310                        );
 7311                        self.request_autoscroll(Autoscroll::fit(), cx);
 7312                    }
 7313                }
 7314            }
 7315            InlineCompletion::Edit { edits, .. } => {
 7316                if let Some(provider) = self.edit_prediction_provider() {
 7317                    provider.accept(cx);
 7318                }
 7319
 7320                // Store the transaction ID and selections before applying the edit
 7321                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7322
 7323                let snapshot = self.buffer.read(cx).snapshot(cx);
 7324                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7325
 7326                self.buffer.update(cx, |buffer, cx| {
 7327                    buffer.edit(edits.iter().cloned(), None, cx)
 7328                });
 7329
 7330                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7331                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7332                });
 7333
 7334                let selections = self.selections.disjoint_anchors();
 7335                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7336                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7337                    if has_new_transaction {
 7338                        self.selection_history
 7339                            .insert_transaction(transaction_id_now, selections);
 7340                    }
 7341                }
 7342
 7343                self.update_visible_inline_completion(window, cx);
 7344                if self.active_inline_completion.is_none() {
 7345                    self.refresh_inline_completion(true, true, window, cx);
 7346                }
 7347
 7348                cx.notify();
 7349            }
 7350        }
 7351
 7352        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7353    }
 7354
 7355    pub fn accept_partial_inline_completion(
 7356        &mut self,
 7357        _: &AcceptPartialEditPrediction,
 7358        window: &mut Window,
 7359        cx: &mut Context<Self>,
 7360    ) {
 7361        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7362            return;
 7363        };
 7364        if self.selections.count() != 1 {
 7365            return;
 7366        }
 7367
 7368        self.report_inline_completion_event(
 7369            active_inline_completion.completion_id.clone(),
 7370            true,
 7371            cx,
 7372        );
 7373
 7374        match &active_inline_completion.completion {
 7375            InlineCompletion::Move { target, .. } => {
 7376                let target = *target;
 7377                self.change_selections(
 7378                    SelectionEffects::scroll(Autoscroll::newest()),
 7379                    window,
 7380                    cx,
 7381                    |selections| {
 7382                        selections.select_anchor_ranges([target..target]);
 7383                    },
 7384                );
 7385            }
 7386            InlineCompletion::Edit { edits, .. } => {
 7387                // Find an insertion that starts at the cursor position.
 7388                let snapshot = self.buffer.read(cx).snapshot(cx);
 7389                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7390                let insertion = edits.iter().find_map(|(range, text)| {
 7391                    let range = range.to_offset(&snapshot);
 7392                    if range.is_empty() && range.start == cursor_offset {
 7393                        Some(text)
 7394                    } else {
 7395                        None
 7396                    }
 7397                });
 7398
 7399                if let Some(text) = insertion {
 7400                    let mut partial_completion = text
 7401                        .chars()
 7402                        .by_ref()
 7403                        .take_while(|c| c.is_alphabetic())
 7404                        .collect::<String>();
 7405                    if partial_completion.is_empty() {
 7406                        partial_completion = text
 7407                            .chars()
 7408                            .by_ref()
 7409                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7410                            .collect::<String>();
 7411                    }
 7412
 7413                    cx.emit(EditorEvent::InputHandled {
 7414                        utf16_range_to_replace: None,
 7415                        text: partial_completion.clone().into(),
 7416                    });
 7417
 7418                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7419
 7420                    self.refresh_inline_completion(true, true, window, cx);
 7421                    cx.notify();
 7422                } else {
 7423                    self.accept_edit_prediction(&Default::default(), window, cx);
 7424                }
 7425            }
 7426        }
 7427    }
 7428
 7429    fn discard_inline_completion(
 7430        &mut self,
 7431        should_report_inline_completion_event: bool,
 7432        cx: &mut Context<Self>,
 7433    ) -> bool {
 7434        if should_report_inline_completion_event {
 7435            let completion_id = self
 7436                .active_inline_completion
 7437                .as_ref()
 7438                .and_then(|active_completion| active_completion.completion_id.clone());
 7439
 7440            self.report_inline_completion_event(completion_id, false, cx);
 7441        }
 7442
 7443        if let Some(provider) = self.edit_prediction_provider() {
 7444            provider.discard(cx);
 7445        }
 7446
 7447        self.take_active_inline_completion(cx)
 7448    }
 7449
 7450    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7451        let Some(provider) = self.edit_prediction_provider() else {
 7452            return;
 7453        };
 7454
 7455        let Some((_, buffer, _)) = self
 7456            .buffer
 7457            .read(cx)
 7458            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7459        else {
 7460            return;
 7461        };
 7462
 7463        let extension = buffer
 7464            .read(cx)
 7465            .file()
 7466            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7467
 7468        let event_type = match accepted {
 7469            true => "Edit Prediction Accepted",
 7470            false => "Edit Prediction Discarded",
 7471        };
 7472        telemetry::event!(
 7473            event_type,
 7474            provider = provider.name(),
 7475            prediction_id = id,
 7476            suggestion_accepted = accepted,
 7477            file_extension = extension,
 7478        );
 7479    }
 7480
 7481    pub fn has_active_inline_completion(&self) -> bool {
 7482        self.active_inline_completion.is_some()
 7483    }
 7484
 7485    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7486        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7487            return false;
 7488        };
 7489
 7490        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7491        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7492        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7493        true
 7494    }
 7495
 7496    /// Returns true when we're displaying the edit prediction popover below the cursor
 7497    /// like we are not previewing and the LSP autocomplete menu is visible
 7498    /// or we are in `when_holding_modifier` mode.
 7499    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7500        if self.edit_prediction_preview_is_active()
 7501            || !self.show_edit_predictions_in_menu()
 7502            || !self.edit_predictions_enabled()
 7503        {
 7504            return false;
 7505        }
 7506
 7507        if self.has_visible_completions_menu() {
 7508            return true;
 7509        }
 7510
 7511        has_completion && self.edit_prediction_requires_modifier()
 7512    }
 7513
 7514    fn handle_modifiers_changed(
 7515        &mut self,
 7516        modifiers: Modifiers,
 7517        position_map: &PositionMap,
 7518        window: &mut Window,
 7519        cx: &mut Context<Self>,
 7520    ) {
 7521        if self.show_edit_predictions_in_menu() {
 7522            self.update_edit_prediction_preview(&modifiers, window, cx);
 7523        }
 7524
 7525        self.update_selection_mode(&modifiers, position_map, window, cx);
 7526
 7527        let mouse_position = window.mouse_position();
 7528        if !position_map.text_hitbox.is_hovered(window) {
 7529            return;
 7530        }
 7531
 7532        self.update_hovered_link(
 7533            position_map.point_for_position(mouse_position),
 7534            &position_map.snapshot,
 7535            modifiers,
 7536            window,
 7537            cx,
 7538        )
 7539    }
 7540
 7541    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7542        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7543        if invert {
 7544            match multi_cursor_setting {
 7545                MultiCursorModifier::Alt => modifiers.alt,
 7546                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7547            }
 7548        } else {
 7549            match multi_cursor_setting {
 7550                MultiCursorModifier::Alt => modifiers.secondary(),
 7551                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7552            }
 7553        }
 7554    }
 7555
 7556    fn columnar_selection_mode(
 7557        modifiers: &Modifiers,
 7558        cx: &mut Context<Self>,
 7559    ) -> Option<ColumnarMode> {
 7560        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7561            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7562                Some(ColumnarMode::FromMouse)
 7563            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7564                Some(ColumnarMode::FromSelection)
 7565            } else {
 7566                None
 7567            }
 7568        } else {
 7569            None
 7570        }
 7571    }
 7572
 7573    fn update_selection_mode(
 7574        &mut self,
 7575        modifiers: &Modifiers,
 7576        position_map: &PositionMap,
 7577        window: &mut Window,
 7578        cx: &mut Context<Self>,
 7579    ) {
 7580        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7581            return;
 7582        };
 7583        if self.selections.pending.is_none() {
 7584            return;
 7585        }
 7586
 7587        let mouse_position = window.mouse_position();
 7588        let point_for_position = position_map.point_for_position(mouse_position);
 7589        let position = point_for_position.previous_valid;
 7590
 7591        self.select(
 7592            SelectPhase::BeginColumnar {
 7593                position,
 7594                reset: false,
 7595                mode,
 7596                goal_column: point_for_position.exact_unclipped.column(),
 7597            },
 7598            window,
 7599            cx,
 7600        );
 7601    }
 7602
 7603    fn update_edit_prediction_preview(
 7604        &mut self,
 7605        modifiers: &Modifiers,
 7606        window: &mut Window,
 7607        cx: &mut Context<Self>,
 7608    ) {
 7609        let mut modifiers_held = false;
 7610        if let Some(accept_keystroke) = self
 7611            .accept_edit_prediction_keybind(false, window, cx)
 7612            .keystroke()
 7613        {
 7614            modifiers_held = modifiers_held
 7615                || (&accept_keystroke.modifiers == modifiers
 7616                    && accept_keystroke.modifiers.modified());
 7617        };
 7618        if let Some(accept_partial_keystroke) = self
 7619            .accept_edit_prediction_keybind(true, window, cx)
 7620            .keystroke()
 7621        {
 7622            modifiers_held = modifiers_held
 7623                || (&accept_partial_keystroke.modifiers == modifiers
 7624                    && accept_partial_keystroke.modifiers.modified());
 7625        }
 7626
 7627        if modifiers_held {
 7628            if matches!(
 7629                self.edit_prediction_preview,
 7630                EditPredictionPreview::Inactive { .. }
 7631            ) {
 7632                self.edit_prediction_preview = EditPredictionPreview::Active {
 7633                    previous_scroll_position: None,
 7634                    since: Instant::now(),
 7635                };
 7636
 7637                self.update_visible_inline_completion(window, cx);
 7638                cx.notify();
 7639            }
 7640        } else if let EditPredictionPreview::Active {
 7641            previous_scroll_position,
 7642            since,
 7643        } = self.edit_prediction_preview
 7644        {
 7645            if let (Some(previous_scroll_position), Some(position_map)) =
 7646                (previous_scroll_position, self.last_position_map.as_ref())
 7647            {
 7648                self.set_scroll_position(
 7649                    previous_scroll_position
 7650                        .scroll_position(&position_map.snapshot.display_snapshot),
 7651                    window,
 7652                    cx,
 7653                );
 7654            }
 7655
 7656            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7657                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7658            };
 7659            self.clear_row_highlights::<EditPredictionPreview>();
 7660            self.update_visible_inline_completion(window, cx);
 7661            cx.notify();
 7662        }
 7663    }
 7664
 7665    fn update_visible_inline_completion(
 7666        &mut self,
 7667        _window: &mut Window,
 7668        cx: &mut Context<Self>,
 7669    ) -> Option<()> {
 7670        let selection = self.selections.newest_anchor();
 7671        let cursor = selection.head();
 7672        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7673        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7674        let excerpt_id = cursor.excerpt_id;
 7675
 7676        let show_in_menu = self.show_edit_predictions_in_menu();
 7677        let completions_menu_has_precedence = !show_in_menu
 7678            && (self.context_menu.borrow().is_some()
 7679                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7680
 7681        if completions_menu_has_precedence
 7682            || !offset_selection.is_empty()
 7683            || self
 7684                .active_inline_completion
 7685                .as_ref()
 7686                .map_or(false, |completion| {
 7687                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7688                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7689                    !invalidation_range.contains(&offset_selection.head())
 7690                })
 7691        {
 7692            self.discard_inline_completion(false, cx);
 7693            return None;
 7694        }
 7695
 7696        self.take_active_inline_completion(cx);
 7697        let Some(provider) = self.edit_prediction_provider() else {
 7698            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7699            return None;
 7700        };
 7701
 7702        let (buffer, cursor_buffer_position) =
 7703            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7704
 7705        self.edit_prediction_settings =
 7706            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7707
 7708        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7709
 7710        if self.edit_prediction_indent_conflict {
 7711            let cursor_point = cursor.to_point(&multibuffer);
 7712
 7713            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7714
 7715            if let Some((_, indent)) = indents.iter().next() {
 7716                if indent.len == cursor_point.column {
 7717                    self.edit_prediction_indent_conflict = false;
 7718                }
 7719            }
 7720        }
 7721
 7722        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7723        let edits = inline_completion
 7724            .edits
 7725            .into_iter()
 7726            .flat_map(|(range, new_text)| {
 7727                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7728                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7729                Some((start..end, new_text))
 7730            })
 7731            .collect::<Vec<_>>();
 7732        if edits.is_empty() {
 7733            return None;
 7734        }
 7735
 7736        let first_edit_start = edits.first().unwrap().0.start;
 7737        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7738        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7739
 7740        let last_edit_end = edits.last().unwrap().0.end;
 7741        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7742        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7743
 7744        let cursor_row = cursor.to_point(&multibuffer).row;
 7745
 7746        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7747
 7748        let mut inlay_ids = Vec::new();
 7749        let invalidation_row_range;
 7750        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7751            Some(cursor_row..edit_end_row)
 7752        } else if cursor_row > edit_end_row {
 7753            Some(edit_start_row..cursor_row)
 7754        } else {
 7755            None
 7756        };
 7757        let is_move =
 7758            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7759        let completion = if is_move {
 7760            invalidation_row_range =
 7761                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7762            let target = first_edit_start;
 7763            InlineCompletion::Move { target, snapshot }
 7764        } else {
 7765            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7766                && !self.inline_completions_hidden_for_vim_mode;
 7767
 7768            if show_completions_in_buffer {
 7769                if edits
 7770                    .iter()
 7771                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7772                {
 7773                    let mut inlays = Vec::new();
 7774                    for (range, new_text) in &edits {
 7775                        let inlay = Inlay::inline_completion(
 7776                            post_inc(&mut self.next_inlay_id),
 7777                            range.start,
 7778                            new_text.as_str(),
 7779                        );
 7780                        inlay_ids.push(inlay.id);
 7781                        inlays.push(inlay);
 7782                    }
 7783
 7784                    self.splice_inlays(&[], inlays, cx);
 7785                } else {
 7786                    let background_color = cx.theme().status().deleted_background;
 7787                    self.highlight_text::<InlineCompletionHighlight>(
 7788                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7789                        HighlightStyle {
 7790                            background_color: Some(background_color),
 7791                            ..Default::default()
 7792                        },
 7793                        cx,
 7794                    );
 7795                }
 7796            }
 7797
 7798            invalidation_row_range = edit_start_row..edit_end_row;
 7799
 7800            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7801                if provider.show_tab_accept_marker() {
 7802                    EditDisplayMode::TabAccept
 7803                } else {
 7804                    EditDisplayMode::Inline
 7805                }
 7806            } else {
 7807                EditDisplayMode::DiffPopover
 7808            };
 7809
 7810            InlineCompletion::Edit {
 7811                edits,
 7812                edit_preview: inline_completion.edit_preview,
 7813                display_mode,
 7814                snapshot,
 7815            }
 7816        };
 7817
 7818        let invalidation_range = multibuffer
 7819            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7820            ..multibuffer.anchor_after(Point::new(
 7821                invalidation_row_range.end,
 7822                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7823            ));
 7824
 7825        self.stale_inline_completion_in_menu = None;
 7826        self.active_inline_completion = Some(InlineCompletionState {
 7827            inlay_ids,
 7828            completion,
 7829            completion_id: inline_completion.id,
 7830            invalidation_range,
 7831        });
 7832
 7833        cx.notify();
 7834
 7835        Some(())
 7836    }
 7837
 7838    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7839        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7840    }
 7841
 7842    fn clear_tasks(&mut self) {
 7843        self.tasks.clear()
 7844    }
 7845
 7846    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7847        if self.tasks.insert(key, value).is_some() {
 7848            // This case should hopefully be rare, but just in case...
 7849            log::error!(
 7850                "multiple different run targets found on a single line, only the last target will be rendered"
 7851            )
 7852        }
 7853    }
 7854
 7855    /// Get all display points of breakpoints that will be rendered within editor
 7856    ///
 7857    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7858    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7859    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7860    fn active_breakpoints(
 7861        &self,
 7862        range: Range<DisplayRow>,
 7863        window: &mut Window,
 7864        cx: &mut Context<Self>,
 7865    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7866        let mut breakpoint_display_points = HashMap::default();
 7867
 7868        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7869            return breakpoint_display_points;
 7870        };
 7871
 7872        let snapshot = self.snapshot(window, cx);
 7873
 7874        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7875        let Some(project) = self.project.as_ref() else {
 7876            return breakpoint_display_points;
 7877        };
 7878
 7879        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7880            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7881
 7882        for (buffer_snapshot, range, excerpt_id) in
 7883            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7884        {
 7885            let Some(buffer) = project
 7886                .read(cx)
 7887                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7888            else {
 7889                continue;
 7890            };
 7891            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7892                &buffer,
 7893                Some(
 7894                    buffer_snapshot.anchor_before(range.start)
 7895                        ..buffer_snapshot.anchor_after(range.end),
 7896                ),
 7897                buffer_snapshot,
 7898                cx,
 7899            );
 7900            for (breakpoint, state) in breakpoints {
 7901                let multi_buffer_anchor =
 7902                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7903                let position = multi_buffer_anchor
 7904                    .to_point(&multi_buffer_snapshot)
 7905                    .to_display_point(&snapshot);
 7906
 7907                breakpoint_display_points.insert(
 7908                    position.row(),
 7909                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7910                );
 7911            }
 7912        }
 7913
 7914        breakpoint_display_points
 7915    }
 7916
 7917    fn breakpoint_context_menu(
 7918        &self,
 7919        anchor: Anchor,
 7920        window: &mut Window,
 7921        cx: &mut Context<Self>,
 7922    ) -> Entity<ui::ContextMenu> {
 7923        let weak_editor = cx.weak_entity();
 7924        let focus_handle = self.focus_handle(cx);
 7925
 7926        let row = self
 7927            .buffer
 7928            .read(cx)
 7929            .snapshot(cx)
 7930            .summary_for_anchor::<Point>(&anchor)
 7931            .row;
 7932
 7933        let breakpoint = self
 7934            .breakpoint_at_row(row, window, cx)
 7935            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7936
 7937        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7938            "Edit Log Breakpoint"
 7939        } else {
 7940            "Set Log Breakpoint"
 7941        };
 7942
 7943        let condition_breakpoint_msg = if breakpoint
 7944            .as_ref()
 7945            .is_some_and(|bp| bp.1.condition.is_some())
 7946        {
 7947            "Edit Condition Breakpoint"
 7948        } else {
 7949            "Set Condition Breakpoint"
 7950        };
 7951
 7952        let hit_condition_breakpoint_msg = if breakpoint
 7953            .as_ref()
 7954            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7955        {
 7956            "Edit Hit Condition Breakpoint"
 7957        } else {
 7958            "Set Hit Condition Breakpoint"
 7959        };
 7960
 7961        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7962            "Unset Breakpoint"
 7963        } else {
 7964            "Set Breakpoint"
 7965        };
 7966
 7967        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7968
 7969        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7970            BreakpointState::Enabled => Some("Disable"),
 7971            BreakpointState::Disabled => Some("Enable"),
 7972        });
 7973
 7974        let (anchor, breakpoint) =
 7975            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7976
 7977        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7978            menu.on_blur_subscription(Subscription::new(|| {}))
 7979                .context(focus_handle)
 7980                .when(run_to_cursor, |this| {
 7981                    let weak_editor = weak_editor.clone();
 7982                    this.entry("Run to cursor", None, move |window, cx| {
 7983                        weak_editor
 7984                            .update(cx, |editor, cx| {
 7985                                editor.change_selections(
 7986                                    SelectionEffects::no_scroll(),
 7987                                    window,
 7988                                    cx,
 7989                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 7990                                );
 7991                            })
 7992                            .ok();
 7993
 7994                        window.dispatch_action(Box::new(RunToCursor), cx);
 7995                    })
 7996                    .separator()
 7997                })
 7998                .when_some(toggle_state_msg, |this, msg| {
 7999                    this.entry(msg, None, {
 8000                        let weak_editor = weak_editor.clone();
 8001                        let breakpoint = breakpoint.clone();
 8002                        move |_window, cx| {
 8003                            weak_editor
 8004                                .update(cx, |this, cx| {
 8005                                    this.edit_breakpoint_at_anchor(
 8006                                        anchor,
 8007                                        breakpoint.as_ref().clone(),
 8008                                        BreakpointEditAction::InvertState,
 8009                                        cx,
 8010                                    );
 8011                                })
 8012                                .log_err();
 8013                        }
 8014                    })
 8015                })
 8016                .entry(set_breakpoint_msg, None, {
 8017                    let weak_editor = weak_editor.clone();
 8018                    let breakpoint = breakpoint.clone();
 8019                    move |_window, cx| {
 8020                        weak_editor
 8021                            .update(cx, |this, cx| {
 8022                                this.edit_breakpoint_at_anchor(
 8023                                    anchor,
 8024                                    breakpoint.as_ref().clone(),
 8025                                    BreakpointEditAction::Toggle,
 8026                                    cx,
 8027                                );
 8028                            })
 8029                            .log_err();
 8030                    }
 8031                })
 8032                .entry(log_breakpoint_msg, None, {
 8033                    let breakpoint = breakpoint.clone();
 8034                    let weak_editor = weak_editor.clone();
 8035                    move |window, cx| {
 8036                        weak_editor
 8037                            .update(cx, |this, cx| {
 8038                                this.add_edit_breakpoint_block(
 8039                                    anchor,
 8040                                    breakpoint.as_ref(),
 8041                                    BreakpointPromptEditAction::Log,
 8042                                    window,
 8043                                    cx,
 8044                                );
 8045                            })
 8046                            .log_err();
 8047                    }
 8048                })
 8049                .entry(condition_breakpoint_msg, None, {
 8050                    let breakpoint = breakpoint.clone();
 8051                    let weak_editor = weak_editor.clone();
 8052                    move |window, cx| {
 8053                        weak_editor
 8054                            .update(cx, |this, cx| {
 8055                                this.add_edit_breakpoint_block(
 8056                                    anchor,
 8057                                    breakpoint.as_ref(),
 8058                                    BreakpointPromptEditAction::Condition,
 8059                                    window,
 8060                                    cx,
 8061                                );
 8062                            })
 8063                            .log_err();
 8064                    }
 8065                })
 8066                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8067                    weak_editor
 8068                        .update(cx, |this, cx| {
 8069                            this.add_edit_breakpoint_block(
 8070                                anchor,
 8071                                breakpoint.as_ref(),
 8072                                BreakpointPromptEditAction::HitCondition,
 8073                                window,
 8074                                cx,
 8075                            );
 8076                        })
 8077                        .log_err();
 8078                })
 8079        })
 8080    }
 8081
 8082    fn render_breakpoint(
 8083        &self,
 8084        position: Anchor,
 8085        row: DisplayRow,
 8086        breakpoint: &Breakpoint,
 8087        state: Option<BreakpointSessionState>,
 8088        cx: &mut Context<Self>,
 8089    ) -> IconButton {
 8090        let is_rejected = state.is_some_and(|s| !s.verified);
 8091        // Is it a breakpoint that shows up when hovering over gutter?
 8092        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8093            (false, false),
 8094            |PhantomBreakpointIndicator {
 8095                 is_active,
 8096                 display_row,
 8097                 collides_with_existing_breakpoint,
 8098             }| {
 8099                (
 8100                    is_active && display_row == row,
 8101                    collides_with_existing_breakpoint,
 8102                )
 8103            },
 8104        );
 8105
 8106        let (color, icon) = {
 8107            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8108                (false, false) => ui::IconName::DebugBreakpoint,
 8109                (true, false) => ui::IconName::DebugLogBreakpoint,
 8110                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8111                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8112            };
 8113
 8114            let color = if is_phantom {
 8115                Color::Hint
 8116            } else if is_rejected {
 8117                Color::Disabled
 8118            } else {
 8119                Color::Debugger
 8120            };
 8121
 8122            (color, icon)
 8123        };
 8124
 8125        let breakpoint = Arc::from(breakpoint.clone());
 8126
 8127        let alt_as_text = gpui::Keystroke {
 8128            modifiers: Modifiers::secondary_key(),
 8129            ..Default::default()
 8130        };
 8131        let primary_action_text = if breakpoint.is_disabled() {
 8132            "Enable breakpoint"
 8133        } else if is_phantom && !collides_with_existing {
 8134            "Set breakpoint"
 8135        } else {
 8136            "Unset breakpoint"
 8137        };
 8138        let focus_handle = self.focus_handle.clone();
 8139
 8140        let meta = if is_rejected {
 8141            SharedString::from("No executable code is associated with this line.")
 8142        } else if collides_with_existing && !breakpoint.is_disabled() {
 8143            SharedString::from(format!(
 8144                "{alt_as_text}-click to disable,\nright-click for more options."
 8145            ))
 8146        } else {
 8147            SharedString::from("Right-click for more options.")
 8148        };
 8149        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8150            .icon_size(IconSize::XSmall)
 8151            .size(ui::ButtonSize::None)
 8152            .when(is_rejected, |this| {
 8153                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8154            })
 8155            .icon_color(color)
 8156            .style(ButtonStyle::Transparent)
 8157            .on_click(cx.listener({
 8158                let breakpoint = breakpoint.clone();
 8159
 8160                move |editor, event: &ClickEvent, window, cx| {
 8161                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8162                        BreakpointEditAction::InvertState
 8163                    } else {
 8164                        BreakpointEditAction::Toggle
 8165                    };
 8166
 8167                    window.focus(&editor.focus_handle(cx));
 8168                    editor.edit_breakpoint_at_anchor(
 8169                        position,
 8170                        breakpoint.as_ref().clone(),
 8171                        edit_action,
 8172                        cx,
 8173                    );
 8174                }
 8175            }))
 8176            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8177                editor.set_breakpoint_context_menu(
 8178                    row,
 8179                    Some(position),
 8180                    event.down.position,
 8181                    window,
 8182                    cx,
 8183                );
 8184            }))
 8185            .tooltip(move |window, cx| {
 8186                Tooltip::with_meta_in(
 8187                    primary_action_text,
 8188                    Some(&ToggleBreakpoint),
 8189                    meta.clone(),
 8190                    &focus_handle,
 8191                    window,
 8192                    cx,
 8193                )
 8194            })
 8195    }
 8196
 8197    fn build_tasks_context(
 8198        project: &Entity<Project>,
 8199        buffer: &Entity<Buffer>,
 8200        buffer_row: u32,
 8201        tasks: &Arc<RunnableTasks>,
 8202        cx: &mut Context<Self>,
 8203    ) -> Task<Option<task::TaskContext>> {
 8204        let position = Point::new(buffer_row, tasks.column);
 8205        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8206        let location = Location {
 8207            buffer: buffer.clone(),
 8208            range: range_start..range_start,
 8209        };
 8210        // Fill in the environmental variables from the tree-sitter captures
 8211        let mut captured_task_variables = TaskVariables::default();
 8212        for (capture_name, value) in tasks.extra_variables.clone() {
 8213            captured_task_variables.insert(
 8214                task::VariableName::Custom(capture_name.into()),
 8215                value.clone(),
 8216            );
 8217        }
 8218        project.update(cx, |project, cx| {
 8219            project.task_store().update(cx, |task_store, cx| {
 8220                task_store.task_context_for_location(captured_task_variables, location, cx)
 8221            })
 8222        })
 8223    }
 8224
 8225    pub fn spawn_nearest_task(
 8226        &mut self,
 8227        action: &SpawnNearestTask,
 8228        window: &mut Window,
 8229        cx: &mut Context<Self>,
 8230    ) {
 8231        let Some((workspace, _)) = self.workspace.clone() else {
 8232            return;
 8233        };
 8234        let Some(project) = self.project.clone() else {
 8235            return;
 8236        };
 8237
 8238        // Try to find a closest, enclosing node using tree-sitter that has a
 8239        // task
 8240        let Some((buffer, buffer_row, tasks)) = self
 8241            .find_enclosing_node_task(cx)
 8242            // Or find the task that's closest in row-distance.
 8243            .or_else(|| self.find_closest_task(cx))
 8244        else {
 8245            return;
 8246        };
 8247
 8248        let reveal_strategy = action.reveal;
 8249        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8250        cx.spawn_in(window, async move |_, cx| {
 8251            let context = task_context.await?;
 8252            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8253
 8254            let resolved = &mut resolved_task.resolved;
 8255            resolved.reveal = reveal_strategy;
 8256
 8257            workspace
 8258                .update_in(cx, |workspace, window, cx| {
 8259                    workspace.schedule_resolved_task(
 8260                        task_source_kind,
 8261                        resolved_task,
 8262                        false,
 8263                        window,
 8264                        cx,
 8265                    );
 8266                })
 8267                .ok()
 8268        })
 8269        .detach();
 8270    }
 8271
 8272    fn find_closest_task(
 8273        &mut self,
 8274        cx: &mut Context<Self>,
 8275    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8276        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8277
 8278        let ((buffer_id, row), tasks) = self
 8279            .tasks
 8280            .iter()
 8281            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8282
 8283        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8284        let tasks = Arc::new(tasks.to_owned());
 8285        Some((buffer, *row, tasks))
 8286    }
 8287
 8288    fn find_enclosing_node_task(
 8289        &mut self,
 8290        cx: &mut Context<Self>,
 8291    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8292        let snapshot = self.buffer.read(cx).snapshot(cx);
 8293        let offset = self.selections.newest::<usize>(cx).head();
 8294        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8295        let buffer_id = excerpt.buffer().remote_id();
 8296
 8297        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8298        let mut cursor = layer.node().walk();
 8299
 8300        while cursor.goto_first_child_for_byte(offset).is_some() {
 8301            if cursor.node().end_byte() == offset {
 8302                cursor.goto_next_sibling();
 8303            }
 8304        }
 8305
 8306        // Ascend to the smallest ancestor that contains the range and has a task.
 8307        loop {
 8308            let node = cursor.node();
 8309            let node_range = node.byte_range();
 8310            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8311
 8312            // Check if this node contains our offset
 8313            if node_range.start <= offset && node_range.end >= offset {
 8314                // If it contains offset, check for task
 8315                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8316                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8317                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8318                }
 8319            }
 8320
 8321            if !cursor.goto_parent() {
 8322                break;
 8323            }
 8324        }
 8325        None
 8326    }
 8327
 8328    fn render_run_indicator(
 8329        &self,
 8330        _style: &EditorStyle,
 8331        is_active: bool,
 8332        row: DisplayRow,
 8333        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8334        cx: &mut Context<Self>,
 8335    ) -> IconButton {
 8336        let color = Color::Muted;
 8337        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8338
 8339        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8340            .shape(ui::IconButtonShape::Square)
 8341            .icon_size(IconSize::XSmall)
 8342            .icon_color(color)
 8343            .toggle_state(is_active)
 8344            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8345                let quick_launch = e.down.button == MouseButton::Left;
 8346                window.focus(&editor.focus_handle(cx));
 8347                editor.toggle_code_actions(
 8348                    &ToggleCodeActions {
 8349                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8350                        quick_launch,
 8351                    },
 8352                    window,
 8353                    cx,
 8354                );
 8355            }))
 8356            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8357                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8358            }))
 8359    }
 8360
 8361    pub fn context_menu_visible(&self) -> bool {
 8362        !self.edit_prediction_preview_is_active()
 8363            && self
 8364                .context_menu
 8365                .borrow()
 8366                .as_ref()
 8367                .map_or(false, |menu| menu.visible())
 8368    }
 8369
 8370    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8371        self.context_menu
 8372            .borrow()
 8373            .as_ref()
 8374            .map(|menu| menu.origin())
 8375    }
 8376
 8377    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8378        self.context_menu_options = Some(options);
 8379    }
 8380
 8381    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8382    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8383
 8384    fn render_edit_prediction_popover(
 8385        &mut self,
 8386        text_bounds: &Bounds<Pixels>,
 8387        content_origin: gpui::Point<Pixels>,
 8388        right_margin: Pixels,
 8389        editor_snapshot: &EditorSnapshot,
 8390        visible_row_range: Range<DisplayRow>,
 8391        scroll_top: f32,
 8392        scroll_bottom: f32,
 8393        line_layouts: &[LineWithInvisibles],
 8394        line_height: Pixels,
 8395        scroll_pixel_position: gpui::Point<Pixels>,
 8396        newest_selection_head: Option<DisplayPoint>,
 8397        editor_width: Pixels,
 8398        style: &EditorStyle,
 8399        window: &mut Window,
 8400        cx: &mut App,
 8401    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8402        if self.mode().is_minimap() {
 8403            return None;
 8404        }
 8405        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8406
 8407        if self.edit_prediction_visible_in_cursor_popover(true) {
 8408            return None;
 8409        }
 8410
 8411        match &active_inline_completion.completion {
 8412            InlineCompletion::Move { target, .. } => {
 8413                let target_display_point = target.to_display_point(editor_snapshot);
 8414
 8415                if self.edit_prediction_requires_modifier() {
 8416                    if !self.edit_prediction_preview_is_active() {
 8417                        return None;
 8418                    }
 8419
 8420                    self.render_edit_prediction_modifier_jump_popover(
 8421                        text_bounds,
 8422                        content_origin,
 8423                        visible_row_range,
 8424                        line_layouts,
 8425                        line_height,
 8426                        scroll_pixel_position,
 8427                        newest_selection_head,
 8428                        target_display_point,
 8429                        window,
 8430                        cx,
 8431                    )
 8432                } else {
 8433                    self.render_edit_prediction_eager_jump_popover(
 8434                        text_bounds,
 8435                        content_origin,
 8436                        editor_snapshot,
 8437                        visible_row_range,
 8438                        scroll_top,
 8439                        scroll_bottom,
 8440                        line_height,
 8441                        scroll_pixel_position,
 8442                        target_display_point,
 8443                        editor_width,
 8444                        window,
 8445                        cx,
 8446                    )
 8447                }
 8448            }
 8449            InlineCompletion::Edit {
 8450                display_mode: EditDisplayMode::Inline,
 8451                ..
 8452            } => None,
 8453            InlineCompletion::Edit {
 8454                display_mode: EditDisplayMode::TabAccept,
 8455                edits,
 8456                ..
 8457            } => {
 8458                let range = &edits.first()?.0;
 8459                let target_display_point = range.end.to_display_point(editor_snapshot);
 8460
 8461                self.render_edit_prediction_end_of_line_popover(
 8462                    "Accept",
 8463                    editor_snapshot,
 8464                    visible_row_range,
 8465                    target_display_point,
 8466                    line_height,
 8467                    scroll_pixel_position,
 8468                    content_origin,
 8469                    editor_width,
 8470                    window,
 8471                    cx,
 8472                )
 8473            }
 8474            InlineCompletion::Edit {
 8475                edits,
 8476                edit_preview,
 8477                display_mode: EditDisplayMode::DiffPopover,
 8478                snapshot,
 8479            } => self.render_edit_prediction_diff_popover(
 8480                text_bounds,
 8481                content_origin,
 8482                right_margin,
 8483                editor_snapshot,
 8484                visible_row_range,
 8485                line_layouts,
 8486                line_height,
 8487                scroll_pixel_position,
 8488                newest_selection_head,
 8489                editor_width,
 8490                style,
 8491                edits,
 8492                edit_preview,
 8493                snapshot,
 8494                window,
 8495                cx,
 8496            ),
 8497        }
 8498    }
 8499
 8500    fn render_edit_prediction_modifier_jump_popover(
 8501        &mut self,
 8502        text_bounds: &Bounds<Pixels>,
 8503        content_origin: gpui::Point<Pixels>,
 8504        visible_row_range: Range<DisplayRow>,
 8505        line_layouts: &[LineWithInvisibles],
 8506        line_height: Pixels,
 8507        scroll_pixel_position: gpui::Point<Pixels>,
 8508        newest_selection_head: Option<DisplayPoint>,
 8509        target_display_point: DisplayPoint,
 8510        window: &mut Window,
 8511        cx: &mut App,
 8512    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8513        let scrolled_content_origin =
 8514            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8515
 8516        const SCROLL_PADDING_Y: Pixels = px(12.);
 8517
 8518        if target_display_point.row() < visible_row_range.start {
 8519            return self.render_edit_prediction_scroll_popover(
 8520                |_| SCROLL_PADDING_Y,
 8521                IconName::ArrowUp,
 8522                visible_row_range,
 8523                line_layouts,
 8524                newest_selection_head,
 8525                scrolled_content_origin,
 8526                window,
 8527                cx,
 8528            );
 8529        } else if target_display_point.row() >= visible_row_range.end {
 8530            return self.render_edit_prediction_scroll_popover(
 8531                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8532                IconName::ArrowDown,
 8533                visible_row_range,
 8534                line_layouts,
 8535                newest_selection_head,
 8536                scrolled_content_origin,
 8537                window,
 8538                cx,
 8539            );
 8540        }
 8541
 8542        const POLE_WIDTH: Pixels = px(2.);
 8543
 8544        let line_layout =
 8545            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8546        let target_column = target_display_point.column() as usize;
 8547
 8548        let target_x = line_layout.x_for_index(target_column);
 8549        let target_y =
 8550            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8551
 8552        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8553
 8554        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8555        border_color.l += 0.001;
 8556
 8557        let mut element = v_flex()
 8558            .items_end()
 8559            .when(flag_on_right, |el| el.items_start())
 8560            .child(if flag_on_right {
 8561                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8562                    .rounded_bl(px(0.))
 8563                    .rounded_tl(px(0.))
 8564                    .border_l_2()
 8565                    .border_color(border_color)
 8566            } else {
 8567                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8568                    .rounded_br(px(0.))
 8569                    .rounded_tr(px(0.))
 8570                    .border_r_2()
 8571                    .border_color(border_color)
 8572            })
 8573            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8574            .into_any();
 8575
 8576        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8577
 8578        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8579            - point(
 8580                if flag_on_right {
 8581                    POLE_WIDTH
 8582                } else {
 8583                    size.width - POLE_WIDTH
 8584                },
 8585                size.height - line_height,
 8586            );
 8587
 8588        origin.x = origin.x.max(content_origin.x);
 8589
 8590        element.prepaint_at(origin, window, cx);
 8591
 8592        Some((element, origin))
 8593    }
 8594
 8595    fn render_edit_prediction_scroll_popover(
 8596        &mut self,
 8597        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8598        scroll_icon: IconName,
 8599        visible_row_range: Range<DisplayRow>,
 8600        line_layouts: &[LineWithInvisibles],
 8601        newest_selection_head: Option<DisplayPoint>,
 8602        scrolled_content_origin: gpui::Point<Pixels>,
 8603        window: &mut Window,
 8604        cx: &mut App,
 8605    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8606        let mut element = self
 8607            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8608            .into_any();
 8609
 8610        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8611
 8612        let cursor = newest_selection_head?;
 8613        let cursor_row_layout =
 8614            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8615        let cursor_column = cursor.column() as usize;
 8616
 8617        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8618
 8619        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8620
 8621        element.prepaint_at(origin, window, cx);
 8622        Some((element, origin))
 8623    }
 8624
 8625    fn render_edit_prediction_eager_jump_popover(
 8626        &mut self,
 8627        text_bounds: &Bounds<Pixels>,
 8628        content_origin: gpui::Point<Pixels>,
 8629        editor_snapshot: &EditorSnapshot,
 8630        visible_row_range: Range<DisplayRow>,
 8631        scroll_top: f32,
 8632        scroll_bottom: f32,
 8633        line_height: Pixels,
 8634        scroll_pixel_position: gpui::Point<Pixels>,
 8635        target_display_point: DisplayPoint,
 8636        editor_width: Pixels,
 8637        window: &mut Window,
 8638        cx: &mut App,
 8639    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8640        if target_display_point.row().as_f32() < scroll_top {
 8641            let mut element = self
 8642                .render_edit_prediction_line_popover(
 8643                    "Jump to Edit",
 8644                    Some(IconName::ArrowUp),
 8645                    window,
 8646                    cx,
 8647                )?
 8648                .into_any();
 8649
 8650            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8651            let offset = point(
 8652                (text_bounds.size.width - size.width) / 2.,
 8653                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8654            );
 8655
 8656            let origin = text_bounds.origin + offset;
 8657            element.prepaint_at(origin, window, cx);
 8658            Some((element, origin))
 8659        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8660            let mut element = self
 8661                .render_edit_prediction_line_popover(
 8662                    "Jump to Edit",
 8663                    Some(IconName::ArrowDown),
 8664                    window,
 8665                    cx,
 8666                )?
 8667                .into_any();
 8668
 8669            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8670            let offset = point(
 8671                (text_bounds.size.width - size.width) / 2.,
 8672                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8673            );
 8674
 8675            let origin = text_bounds.origin + offset;
 8676            element.prepaint_at(origin, window, cx);
 8677            Some((element, origin))
 8678        } else {
 8679            self.render_edit_prediction_end_of_line_popover(
 8680                "Jump to Edit",
 8681                editor_snapshot,
 8682                visible_row_range,
 8683                target_display_point,
 8684                line_height,
 8685                scroll_pixel_position,
 8686                content_origin,
 8687                editor_width,
 8688                window,
 8689                cx,
 8690            )
 8691        }
 8692    }
 8693
 8694    fn render_edit_prediction_end_of_line_popover(
 8695        self: &mut Editor,
 8696        label: &'static str,
 8697        editor_snapshot: &EditorSnapshot,
 8698        visible_row_range: Range<DisplayRow>,
 8699        target_display_point: DisplayPoint,
 8700        line_height: Pixels,
 8701        scroll_pixel_position: gpui::Point<Pixels>,
 8702        content_origin: gpui::Point<Pixels>,
 8703        editor_width: Pixels,
 8704        window: &mut Window,
 8705        cx: &mut App,
 8706    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8707        let target_line_end = DisplayPoint::new(
 8708            target_display_point.row(),
 8709            editor_snapshot.line_len(target_display_point.row()),
 8710        );
 8711
 8712        let mut element = self
 8713            .render_edit_prediction_line_popover(label, None, window, cx)?
 8714            .into_any();
 8715
 8716        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8717
 8718        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8719
 8720        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8721        let mut origin = start_point
 8722            + line_origin
 8723            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8724        origin.x = origin.x.max(content_origin.x);
 8725
 8726        let max_x = content_origin.x + editor_width - size.width;
 8727
 8728        if origin.x > max_x {
 8729            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8730
 8731            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8732                origin.y += offset;
 8733                IconName::ArrowUp
 8734            } else {
 8735                origin.y -= offset;
 8736                IconName::ArrowDown
 8737            };
 8738
 8739            element = self
 8740                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8741                .into_any();
 8742
 8743            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8744
 8745            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8746        }
 8747
 8748        element.prepaint_at(origin, window, cx);
 8749        Some((element, origin))
 8750    }
 8751
 8752    fn render_edit_prediction_diff_popover(
 8753        self: &Editor,
 8754        text_bounds: &Bounds<Pixels>,
 8755        content_origin: gpui::Point<Pixels>,
 8756        right_margin: Pixels,
 8757        editor_snapshot: &EditorSnapshot,
 8758        visible_row_range: Range<DisplayRow>,
 8759        line_layouts: &[LineWithInvisibles],
 8760        line_height: Pixels,
 8761        scroll_pixel_position: gpui::Point<Pixels>,
 8762        newest_selection_head: Option<DisplayPoint>,
 8763        editor_width: Pixels,
 8764        style: &EditorStyle,
 8765        edits: &Vec<(Range<Anchor>, String)>,
 8766        edit_preview: &Option<language::EditPreview>,
 8767        snapshot: &language::BufferSnapshot,
 8768        window: &mut Window,
 8769        cx: &mut App,
 8770    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8771        let edit_start = edits
 8772            .first()
 8773            .unwrap()
 8774            .0
 8775            .start
 8776            .to_display_point(editor_snapshot);
 8777        let edit_end = edits
 8778            .last()
 8779            .unwrap()
 8780            .0
 8781            .end
 8782            .to_display_point(editor_snapshot);
 8783
 8784        let is_visible = visible_row_range.contains(&edit_start.row())
 8785            || visible_row_range.contains(&edit_end.row());
 8786        if !is_visible {
 8787            return None;
 8788        }
 8789
 8790        let highlighted_edits =
 8791            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8792
 8793        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8794        let line_count = highlighted_edits.text.lines().count();
 8795
 8796        const BORDER_WIDTH: Pixels = px(1.);
 8797
 8798        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8799        let has_keybind = keybind.is_some();
 8800
 8801        let mut element = h_flex()
 8802            .items_start()
 8803            .child(
 8804                h_flex()
 8805                    .bg(cx.theme().colors().editor_background)
 8806                    .border(BORDER_WIDTH)
 8807                    .shadow_xs()
 8808                    .border_color(cx.theme().colors().border)
 8809                    .rounded_l_lg()
 8810                    .when(line_count > 1, |el| el.rounded_br_lg())
 8811                    .pr_1()
 8812                    .child(styled_text),
 8813            )
 8814            .child(
 8815                h_flex()
 8816                    .h(line_height + BORDER_WIDTH * 2.)
 8817                    .px_1p5()
 8818                    .gap_1()
 8819                    // Workaround: For some reason, there's a gap if we don't do this
 8820                    .ml(-BORDER_WIDTH)
 8821                    .shadow(vec![gpui::BoxShadow {
 8822                        color: gpui::black().opacity(0.05),
 8823                        offset: point(px(1.), px(1.)),
 8824                        blur_radius: px(2.),
 8825                        spread_radius: px(0.),
 8826                    }])
 8827                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8828                    .border(BORDER_WIDTH)
 8829                    .border_color(cx.theme().colors().border)
 8830                    .rounded_r_lg()
 8831                    .id("edit_prediction_diff_popover_keybind")
 8832                    .when(!has_keybind, |el| {
 8833                        let status_colors = cx.theme().status();
 8834
 8835                        el.bg(status_colors.error_background)
 8836                            .border_color(status_colors.error.opacity(0.6))
 8837                            .child(Icon::new(IconName::Info).color(Color::Error))
 8838                            .cursor_default()
 8839                            .hoverable_tooltip(move |_window, cx| {
 8840                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8841                            })
 8842                    })
 8843                    .children(keybind),
 8844            )
 8845            .into_any();
 8846
 8847        let longest_row =
 8848            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8849        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8850            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8851        } else {
 8852            layout_line(
 8853                longest_row,
 8854                editor_snapshot,
 8855                style,
 8856                editor_width,
 8857                |_| false,
 8858                window,
 8859                cx,
 8860            )
 8861            .width
 8862        };
 8863
 8864        let viewport_bounds =
 8865            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8866                right: -right_margin,
 8867                ..Default::default()
 8868            });
 8869
 8870        let x_after_longest =
 8871            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8872                - scroll_pixel_position.x;
 8873
 8874        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8875
 8876        // Fully visible if it can be displayed within the window (allow overlapping other
 8877        // panes). However, this is only allowed if the popover starts within text_bounds.
 8878        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8879            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8880
 8881        let mut origin = if can_position_to_the_right {
 8882            point(
 8883                x_after_longest,
 8884                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8885                    - scroll_pixel_position.y,
 8886            )
 8887        } else {
 8888            let cursor_row = newest_selection_head.map(|head| head.row());
 8889            let above_edit = edit_start
 8890                .row()
 8891                .0
 8892                .checked_sub(line_count as u32)
 8893                .map(DisplayRow);
 8894            let below_edit = Some(edit_end.row() + 1);
 8895            let above_cursor =
 8896                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8897            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8898
 8899            // Place the edit popover adjacent to the edit if there is a location
 8900            // available that is onscreen and does not obscure the cursor. Otherwise,
 8901            // place it adjacent to the cursor.
 8902            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8903                .into_iter()
 8904                .flatten()
 8905                .find(|&start_row| {
 8906                    let end_row = start_row + line_count as u32;
 8907                    visible_row_range.contains(&start_row)
 8908                        && visible_row_range.contains(&end_row)
 8909                        && cursor_row.map_or(true, |cursor_row| {
 8910                            !((start_row..end_row).contains(&cursor_row))
 8911                        })
 8912                })?;
 8913
 8914            content_origin
 8915                + point(
 8916                    -scroll_pixel_position.x,
 8917                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8918                )
 8919        };
 8920
 8921        origin.x -= BORDER_WIDTH;
 8922
 8923        window.defer_draw(element, origin, 1);
 8924
 8925        // Do not return an element, since it will already be drawn due to defer_draw.
 8926        None
 8927    }
 8928
 8929    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8930        px(30.)
 8931    }
 8932
 8933    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8934        if self.read_only(cx) {
 8935            cx.theme().players().read_only()
 8936        } else {
 8937            self.style.as_ref().unwrap().local_player
 8938        }
 8939    }
 8940
 8941    fn render_edit_prediction_accept_keybind(
 8942        &self,
 8943        window: &mut Window,
 8944        cx: &App,
 8945    ) -> Option<AnyElement> {
 8946        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8947        let accept_keystroke = accept_binding.keystroke()?;
 8948
 8949        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8950
 8951        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8952            Color::Accent
 8953        } else {
 8954            Color::Muted
 8955        };
 8956
 8957        h_flex()
 8958            .px_0p5()
 8959            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8960            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8961            .text_size(TextSize::XSmall.rems(cx))
 8962            .child(h_flex().children(ui::render_modifiers(
 8963                &accept_keystroke.modifiers,
 8964                PlatformStyle::platform(),
 8965                Some(modifiers_color),
 8966                Some(IconSize::XSmall.rems().into()),
 8967                true,
 8968            )))
 8969            .when(is_platform_style_mac, |parent| {
 8970                parent.child(accept_keystroke.key.clone())
 8971            })
 8972            .when(!is_platform_style_mac, |parent| {
 8973                parent.child(
 8974                    Key::new(
 8975                        util::capitalize(&accept_keystroke.key),
 8976                        Some(Color::Default),
 8977                    )
 8978                    .size(Some(IconSize::XSmall.rems().into())),
 8979                )
 8980            })
 8981            .into_any()
 8982            .into()
 8983    }
 8984
 8985    fn render_edit_prediction_line_popover(
 8986        &self,
 8987        label: impl Into<SharedString>,
 8988        icon: Option<IconName>,
 8989        window: &mut Window,
 8990        cx: &App,
 8991    ) -> Option<Stateful<Div>> {
 8992        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8993
 8994        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8995        let has_keybind = keybind.is_some();
 8996
 8997        let result = h_flex()
 8998            .id("ep-line-popover")
 8999            .py_0p5()
 9000            .pl_1()
 9001            .pr(padding_right)
 9002            .gap_1()
 9003            .rounded_md()
 9004            .border_1()
 9005            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9006            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9007            .shadow_xs()
 9008            .when(!has_keybind, |el| {
 9009                let status_colors = cx.theme().status();
 9010
 9011                el.bg(status_colors.error_background)
 9012                    .border_color(status_colors.error.opacity(0.6))
 9013                    .pl_2()
 9014                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9015                    .cursor_default()
 9016                    .hoverable_tooltip(move |_window, cx| {
 9017                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9018                    })
 9019            })
 9020            .children(keybind)
 9021            .child(
 9022                Label::new(label)
 9023                    .size(LabelSize::Small)
 9024                    .when(!has_keybind, |el| {
 9025                        el.color(cx.theme().status().error.into()).strikethrough()
 9026                    }),
 9027            )
 9028            .when(!has_keybind, |el| {
 9029                el.child(
 9030                    h_flex().ml_1().child(
 9031                        Icon::new(IconName::Info)
 9032                            .size(IconSize::Small)
 9033                            .color(cx.theme().status().error.into()),
 9034                    ),
 9035                )
 9036            })
 9037            .when_some(icon, |element, icon| {
 9038                element.child(
 9039                    div()
 9040                        .mt(px(1.5))
 9041                        .child(Icon::new(icon).size(IconSize::Small)),
 9042                )
 9043            });
 9044
 9045        Some(result)
 9046    }
 9047
 9048    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9049        let accent_color = cx.theme().colors().text_accent;
 9050        let editor_bg_color = cx.theme().colors().editor_background;
 9051        editor_bg_color.blend(accent_color.opacity(0.1))
 9052    }
 9053
 9054    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9055        let accent_color = cx.theme().colors().text_accent;
 9056        let editor_bg_color = cx.theme().colors().editor_background;
 9057        editor_bg_color.blend(accent_color.opacity(0.6))
 9058    }
 9059
 9060    fn render_edit_prediction_cursor_popover(
 9061        &self,
 9062        min_width: Pixels,
 9063        max_width: Pixels,
 9064        cursor_point: Point,
 9065        style: &EditorStyle,
 9066        accept_keystroke: Option<&gpui::Keystroke>,
 9067        _window: &Window,
 9068        cx: &mut Context<Editor>,
 9069    ) -> Option<AnyElement> {
 9070        let provider = self.edit_prediction_provider.as_ref()?;
 9071
 9072        if provider.provider.needs_terms_acceptance(cx) {
 9073            return Some(
 9074                h_flex()
 9075                    .min_w(min_width)
 9076                    .flex_1()
 9077                    .px_2()
 9078                    .py_1()
 9079                    .gap_3()
 9080                    .elevation_2(cx)
 9081                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9082                    .id("accept-terms")
 9083                    .cursor_pointer()
 9084                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9085                    .on_click(cx.listener(|this, _event, window, cx| {
 9086                        cx.stop_propagation();
 9087                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 9088                        window.dispatch_action(
 9089                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9090                            cx,
 9091                        );
 9092                    }))
 9093                    .child(
 9094                        h_flex()
 9095                            .flex_1()
 9096                            .gap_2()
 9097                            .child(Icon::new(IconName::ZedPredict))
 9098                            .child(Label::new("Accept Terms of Service"))
 9099                            .child(div().w_full())
 9100                            .child(
 9101                                Icon::new(IconName::ArrowUpRight)
 9102                                    .color(Color::Muted)
 9103                                    .size(IconSize::Small),
 9104                            )
 9105                            .into_any_element(),
 9106                    )
 9107                    .into_any(),
 9108            );
 9109        }
 9110
 9111        let is_refreshing = provider.provider.is_refreshing(cx);
 9112
 9113        fn pending_completion_container() -> Div {
 9114            h_flex()
 9115                .h_full()
 9116                .flex_1()
 9117                .gap_2()
 9118                .child(Icon::new(IconName::ZedPredict))
 9119        }
 9120
 9121        let completion = match &self.active_inline_completion {
 9122            Some(prediction) => {
 9123                if !self.has_visible_completions_menu() {
 9124                    const RADIUS: Pixels = px(6.);
 9125                    const BORDER_WIDTH: Pixels = px(1.);
 9126
 9127                    return Some(
 9128                        h_flex()
 9129                            .elevation_2(cx)
 9130                            .border(BORDER_WIDTH)
 9131                            .border_color(cx.theme().colors().border)
 9132                            .when(accept_keystroke.is_none(), |el| {
 9133                                el.border_color(cx.theme().status().error)
 9134                            })
 9135                            .rounded(RADIUS)
 9136                            .rounded_tl(px(0.))
 9137                            .overflow_hidden()
 9138                            .child(div().px_1p5().child(match &prediction.completion {
 9139                                InlineCompletion::Move { target, snapshot } => {
 9140                                    use text::ToPoint as _;
 9141                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9142                                    {
 9143                                        Icon::new(IconName::ZedPredictDown)
 9144                                    } else {
 9145                                        Icon::new(IconName::ZedPredictUp)
 9146                                    }
 9147                                }
 9148                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 9149                            }))
 9150                            .child(
 9151                                h_flex()
 9152                                    .gap_1()
 9153                                    .py_1()
 9154                                    .px_2()
 9155                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9156                                    .border_l_1()
 9157                                    .border_color(cx.theme().colors().border)
 9158                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9159                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9160                                        el.child(
 9161                                            Label::new("Hold")
 9162                                                .size(LabelSize::Small)
 9163                                                .when(accept_keystroke.is_none(), |el| {
 9164                                                    el.strikethrough()
 9165                                                })
 9166                                                .line_height_style(LineHeightStyle::UiLabel),
 9167                                        )
 9168                                    })
 9169                                    .id("edit_prediction_cursor_popover_keybind")
 9170                                    .when(accept_keystroke.is_none(), |el| {
 9171                                        let status_colors = cx.theme().status();
 9172
 9173                                        el.bg(status_colors.error_background)
 9174                                            .border_color(status_colors.error.opacity(0.6))
 9175                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9176                                            .cursor_default()
 9177                                            .hoverable_tooltip(move |_window, cx| {
 9178                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9179                                                    .into()
 9180                                            })
 9181                                    })
 9182                                    .when_some(
 9183                                        accept_keystroke.as_ref(),
 9184                                        |el, accept_keystroke| {
 9185                                            el.child(h_flex().children(ui::render_modifiers(
 9186                                                &accept_keystroke.modifiers,
 9187                                                PlatformStyle::platform(),
 9188                                                Some(Color::Default),
 9189                                                Some(IconSize::XSmall.rems().into()),
 9190                                                false,
 9191                                            )))
 9192                                        },
 9193                                    ),
 9194                            )
 9195                            .into_any(),
 9196                    );
 9197                }
 9198
 9199                self.render_edit_prediction_cursor_popover_preview(
 9200                    prediction,
 9201                    cursor_point,
 9202                    style,
 9203                    cx,
 9204                )?
 9205            }
 9206
 9207            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 9208                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9209                    stale_completion,
 9210                    cursor_point,
 9211                    style,
 9212                    cx,
 9213                )?,
 9214
 9215                None => {
 9216                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 9217                }
 9218            },
 9219
 9220            None => pending_completion_container().child(Label::new("No Prediction")),
 9221        };
 9222
 9223        let completion = if is_refreshing {
 9224            completion
 9225                .with_animation(
 9226                    "loading-completion",
 9227                    Animation::new(Duration::from_secs(2))
 9228                        .repeat()
 9229                        .with_easing(pulsating_between(0.4, 0.8)),
 9230                    |label, delta| label.opacity(delta),
 9231                )
 9232                .into_any_element()
 9233        } else {
 9234            completion.into_any_element()
 9235        };
 9236
 9237        let has_completion = self.active_inline_completion.is_some();
 9238
 9239        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9240        Some(
 9241            h_flex()
 9242                .min_w(min_width)
 9243                .max_w(max_width)
 9244                .flex_1()
 9245                .elevation_2(cx)
 9246                .border_color(cx.theme().colors().border)
 9247                .child(
 9248                    div()
 9249                        .flex_1()
 9250                        .py_1()
 9251                        .px_2()
 9252                        .overflow_hidden()
 9253                        .child(completion),
 9254                )
 9255                .when_some(accept_keystroke, |el, accept_keystroke| {
 9256                    if !accept_keystroke.modifiers.modified() {
 9257                        return el;
 9258                    }
 9259
 9260                    el.child(
 9261                        h_flex()
 9262                            .h_full()
 9263                            .border_l_1()
 9264                            .rounded_r_lg()
 9265                            .border_color(cx.theme().colors().border)
 9266                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9267                            .gap_1()
 9268                            .py_1()
 9269                            .px_2()
 9270                            .child(
 9271                                h_flex()
 9272                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9273                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9274                                    .child(h_flex().children(ui::render_modifiers(
 9275                                        &accept_keystroke.modifiers,
 9276                                        PlatformStyle::platform(),
 9277                                        Some(if !has_completion {
 9278                                            Color::Muted
 9279                                        } else {
 9280                                            Color::Default
 9281                                        }),
 9282                                        None,
 9283                                        false,
 9284                                    ))),
 9285                            )
 9286                            .child(Label::new("Preview").into_any_element())
 9287                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9288                    )
 9289                })
 9290                .into_any(),
 9291        )
 9292    }
 9293
 9294    fn render_edit_prediction_cursor_popover_preview(
 9295        &self,
 9296        completion: &InlineCompletionState,
 9297        cursor_point: Point,
 9298        style: &EditorStyle,
 9299        cx: &mut Context<Editor>,
 9300    ) -> Option<Div> {
 9301        use text::ToPoint as _;
 9302
 9303        fn render_relative_row_jump(
 9304            prefix: impl Into<String>,
 9305            current_row: u32,
 9306            target_row: u32,
 9307        ) -> Div {
 9308            let (row_diff, arrow) = if target_row < current_row {
 9309                (current_row - target_row, IconName::ArrowUp)
 9310            } else {
 9311                (target_row - current_row, IconName::ArrowDown)
 9312            };
 9313
 9314            h_flex()
 9315                .child(
 9316                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9317                        .color(Color::Muted)
 9318                        .size(LabelSize::Small),
 9319                )
 9320                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9321        }
 9322
 9323        match &completion.completion {
 9324            InlineCompletion::Move {
 9325                target, snapshot, ..
 9326            } => Some(
 9327                h_flex()
 9328                    .px_2()
 9329                    .gap_2()
 9330                    .flex_1()
 9331                    .child(
 9332                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9333                            Icon::new(IconName::ZedPredictDown)
 9334                        } else {
 9335                            Icon::new(IconName::ZedPredictUp)
 9336                        },
 9337                    )
 9338                    .child(Label::new("Jump to Edit")),
 9339            ),
 9340
 9341            InlineCompletion::Edit {
 9342                edits,
 9343                edit_preview,
 9344                snapshot,
 9345                display_mode: _,
 9346            } => {
 9347                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9348
 9349                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9350                    &snapshot,
 9351                    &edits,
 9352                    edit_preview.as_ref()?,
 9353                    true,
 9354                    cx,
 9355                )
 9356                .first_line_preview();
 9357
 9358                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9359                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9360
 9361                let preview = h_flex()
 9362                    .gap_1()
 9363                    .min_w_16()
 9364                    .child(styled_text)
 9365                    .when(has_more_lines, |parent| parent.child(""));
 9366
 9367                let left = if first_edit_row != cursor_point.row {
 9368                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9369                        .into_any_element()
 9370                } else {
 9371                    Icon::new(IconName::ZedPredict).into_any_element()
 9372                };
 9373
 9374                Some(
 9375                    h_flex()
 9376                        .h_full()
 9377                        .flex_1()
 9378                        .gap_2()
 9379                        .pr_1()
 9380                        .overflow_x_hidden()
 9381                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9382                        .child(left)
 9383                        .child(preview),
 9384                )
 9385            }
 9386        }
 9387    }
 9388
 9389    pub fn render_context_menu(
 9390        &self,
 9391        style: &EditorStyle,
 9392        max_height_in_lines: u32,
 9393        window: &mut Window,
 9394        cx: &mut Context<Editor>,
 9395    ) -> Option<AnyElement> {
 9396        let menu = self.context_menu.borrow();
 9397        let menu = menu.as_ref()?;
 9398        if !menu.visible() {
 9399            return None;
 9400        };
 9401        Some(menu.render(style, max_height_in_lines, window, cx))
 9402    }
 9403
 9404    fn render_context_menu_aside(
 9405        &mut self,
 9406        max_size: Size<Pixels>,
 9407        window: &mut Window,
 9408        cx: &mut Context<Editor>,
 9409    ) -> Option<AnyElement> {
 9410        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9411            if menu.visible() {
 9412                menu.render_aside(max_size, window, cx)
 9413            } else {
 9414                None
 9415            }
 9416        })
 9417    }
 9418
 9419    fn hide_context_menu(
 9420        &mut self,
 9421        window: &mut Window,
 9422        cx: &mut Context<Self>,
 9423    ) -> Option<CodeContextMenu> {
 9424        cx.notify();
 9425        self.completion_tasks.clear();
 9426        let context_menu = self.context_menu.borrow_mut().take();
 9427        self.stale_inline_completion_in_menu.take();
 9428        self.update_visible_inline_completion(window, cx);
 9429        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9430            if let Some(completion_provider) = &self.completion_provider {
 9431                completion_provider.selection_changed(None, window, cx);
 9432            }
 9433        }
 9434        context_menu
 9435    }
 9436
 9437    fn show_snippet_choices(
 9438        &mut self,
 9439        choices: &Vec<String>,
 9440        selection: Range<Anchor>,
 9441        cx: &mut Context<Self>,
 9442    ) {
 9443        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9444            (Some(a), Some(b)) if a == b => a,
 9445            _ => {
 9446                log::error!("expected anchor range to have matching buffer IDs");
 9447                return;
 9448            }
 9449        };
 9450        let multi_buffer = self.buffer().read(cx);
 9451        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9452            return;
 9453        };
 9454
 9455        let id = post_inc(&mut self.next_completion_id);
 9456        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9457        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9458            CompletionsMenu::new_snippet_choices(
 9459                id,
 9460                true,
 9461                choices,
 9462                selection,
 9463                buffer,
 9464                snippet_sort_order,
 9465            ),
 9466        ));
 9467    }
 9468
 9469    pub fn insert_snippet(
 9470        &mut self,
 9471        insertion_ranges: &[Range<usize>],
 9472        snippet: Snippet,
 9473        window: &mut Window,
 9474        cx: &mut Context<Self>,
 9475    ) -> Result<()> {
 9476        struct Tabstop<T> {
 9477            is_end_tabstop: bool,
 9478            ranges: Vec<Range<T>>,
 9479            choices: Option<Vec<String>>,
 9480        }
 9481
 9482        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9483            let snippet_text: Arc<str> = snippet.text.clone().into();
 9484            let edits = insertion_ranges
 9485                .iter()
 9486                .cloned()
 9487                .map(|range| (range, snippet_text.clone()));
 9488            let autoindent_mode = AutoindentMode::Block {
 9489                original_indent_columns: Vec::new(),
 9490            };
 9491            buffer.edit(edits, Some(autoindent_mode), cx);
 9492
 9493            let snapshot = &*buffer.read(cx);
 9494            let snippet = &snippet;
 9495            snippet
 9496                .tabstops
 9497                .iter()
 9498                .map(|tabstop| {
 9499                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9500                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9501                    });
 9502                    let mut tabstop_ranges = tabstop
 9503                        .ranges
 9504                        .iter()
 9505                        .flat_map(|tabstop_range| {
 9506                            let mut delta = 0_isize;
 9507                            insertion_ranges.iter().map(move |insertion_range| {
 9508                                let insertion_start = insertion_range.start as isize + delta;
 9509                                delta +=
 9510                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9511
 9512                                let start = ((insertion_start + tabstop_range.start) as usize)
 9513                                    .min(snapshot.len());
 9514                                let end = ((insertion_start + tabstop_range.end) as usize)
 9515                                    .min(snapshot.len());
 9516                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9517                            })
 9518                        })
 9519                        .collect::<Vec<_>>();
 9520                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9521
 9522                    Tabstop {
 9523                        is_end_tabstop,
 9524                        ranges: tabstop_ranges,
 9525                        choices: tabstop.choices.clone(),
 9526                    }
 9527                })
 9528                .collect::<Vec<_>>()
 9529        });
 9530        if let Some(tabstop) = tabstops.first() {
 9531            self.change_selections(Default::default(), window, cx, |s| {
 9532                // Reverse order so that the first range is the newest created selection.
 9533                // Completions will use it and autoscroll will prioritize it.
 9534                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9535            });
 9536
 9537            if let Some(choices) = &tabstop.choices {
 9538                if let Some(selection) = tabstop.ranges.first() {
 9539                    self.show_snippet_choices(choices, selection.clone(), cx)
 9540                }
 9541            }
 9542
 9543            // If we're already at the last tabstop and it's at the end of the snippet,
 9544            // we're done, we don't need to keep the state around.
 9545            if !tabstop.is_end_tabstop {
 9546                let choices = tabstops
 9547                    .iter()
 9548                    .map(|tabstop| tabstop.choices.clone())
 9549                    .collect();
 9550
 9551                let ranges = tabstops
 9552                    .into_iter()
 9553                    .map(|tabstop| tabstop.ranges)
 9554                    .collect::<Vec<_>>();
 9555
 9556                self.snippet_stack.push(SnippetState {
 9557                    active_index: 0,
 9558                    ranges,
 9559                    choices,
 9560                });
 9561            }
 9562
 9563            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9564            if self.autoclose_regions.is_empty() {
 9565                let snapshot = self.buffer.read(cx).snapshot(cx);
 9566                for selection in &mut self.selections.all::<Point>(cx) {
 9567                    let selection_head = selection.head();
 9568                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9569                        continue;
 9570                    };
 9571
 9572                    let mut bracket_pair = None;
 9573                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9574                    let prev_chars = snapshot
 9575                        .reversed_chars_at(selection_head)
 9576                        .collect::<String>();
 9577                    for (pair, enabled) in scope.brackets() {
 9578                        if enabled
 9579                            && pair.close
 9580                            && prev_chars.starts_with(pair.start.as_str())
 9581                            && next_chars.starts_with(pair.end.as_str())
 9582                        {
 9583                            bracket_pair = Some(pair.clone());
 9584                            break;
 9585                        }
 9586                    }
 9587                    if let Some(pair) = bracket_pair {
 9588                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9589                        let autoclose_enabled =
 9590                            self.use_autoclose && snapshot_settings.use_autoclose;
 9591                        if autoclose_enabled {
 9592                            let start = snapshot.anchor_after(selection_head);
 9593                            let end = snapshot.anchor_after(selection_head);
 9594                            self.autoclose_regions.push(AutocloseRegion {
 9595                                selection_id: selection.id,
 9596                                range: start..end,
 9597                                pair,
 9598                            });
 9599                        }
 9600                    }
 9601                }
 9602            }
 9603        }
 9604        Ok(())
 9605    }
 9606
 9607    pub fn move_to_next_snippet_tabstop(
 9608        &mut self,
 9609        window: &mut Window,
 9610        cx: &mut Context<Self>,
 9611    ) -> bool {
 9612        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9613    }
 9614
 9615    pub fn move_to_prev_snippet_tabstop(
 9616        &mut self,
 9617        window: &mut Window,
 9618        cx: &mut Context<Self>,
 9619    ) -> bool {
 9620        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9621    }
 9622
 9623    pub fn move_to_snippet_tabstop(
 9624        &mut self,
 9625        bias: Bias,
 9626        window: &mut Window,
 9627        cx: &mut Context<Self>,
 9628    ) -> bool {
 9629        if let Some(mut snippet) = self.snippet_stack.pop() {
 9630            match bias {
 9631                Bias::Left => {
 9632                    if snippet.active_index > 0 {
 9633                        snippet.active_index -= 1;
 9634                    } else {
 9635                        self.snippet_stack.push(snippet);
 9636                        return false;
 9637                    }
 9638                }
 9639                Bias::Right => {
 9640                    if snippet.active_index + 1 < snippet.ranges.len() {
 9641                        snippet.active_index += 1;
 9642                    } else {
 9643                        self.snippet_stack.push(snippet);
 9644                        return false;
 9645                    }
 9646                }
 9647            }
 9648            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9649                self.change_selections(Default::default(), window, cx, |s| {
 9650                    // Reverse order so that the first range is the newest created selection.
 9651                    // Completions will use it and autoscroll will prioritize it.
 9652                    s.select_ranges(current_ranges.iter().rev().cloned())
 9653                });
 9654
 9655                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9656                    if let Some(selection) = current_ranges.first() {
 9657                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9658                    }
 9659                }
 9660
 9661                // If snippet state is not at the last tabstop, push it back on the stack
 9662                if snippet.active_index + 1 < snippet.ranges.len() {
 9663                    self.snippet_stack.push(snippet);
 9664                }
 9665                return true;
 9666            }
 9667        }
 9668
 9669        false
 9670    }
 9671
 9672    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9673        self.transact(window, cx, |this, window, cx| {
 9674            this.select_all(&SelectAll, window, cx);
 9675            this.insert("", window, cx);
 9676        });
 9677    }
 9678
 9679    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9680        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9681        self.transact(window, cx, |this, window, cx| {
 9682            this.select_autoclose_pair(window, cx);
 9683            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9684            if !this.linked_edit_ranges.is_empty() {
 9685                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9686                let snapshot = this.buffer.read(cx).snapshot(cx);
 9687
 9688                for selection in selections.iter() {
 9689                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9690                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9691                    if selection_start.buffer_id != selection_end.buffer_id {
 9692                        continue;
 9693                    }
 9694                    if let Some(ranges) =
 9695                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9696                    {
 9697                        for (buffer, entries) in ranges {
 9698                            linked_ranges.entry(buffer).or_default().extend(entries);
 9699                        }
 9700                    }
 9701                }
 9702            }
 9703
 9704            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9705            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9706            for selection in &mut selections {
 9707                if selection.is_empty() {
 9708                    let old_head = selection.head();
 9709                    let mut new_head =
 9710                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9711                            .to_point(&display_map);
 9712                    if let Some((buffer, line_buffer_range)) = display_map
 9713                        .buffer_snapshot
 9714                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9715                    {
 9716                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9717                        let indent_len = match indent_size.kind {
 9718                            IndentKind::Space => {
 9719                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9720                            }
 9721                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9722                        };
 9723                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9724                            let indent_len = indent_len.get();
 9725                            new_head = cmp::min(
 9726                                new_head,
 9727                                MultiBufferPoint::new(
 9728                                    old_head.row,
 9729                                    ((old_head.column - 1) / indent_len) * indent_len,
 9730                                ),
 9731                            );
 9732                        }
 9733                    }
 9734
 9735                    selection.set_head(new_head, SelectionGoal::None);
 9736                }
 9737            }
 9738
 9739            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9740            this.insert("", window, cx);
 9741            let empty_str: Arc<str> = Arc::from("");
 9742            for (buffer, edits) in linked_ranges {
 9743                let snapshot = buffer.read(cx).snapshot();
 9744                use text::ToPoint as TP;
 9745
 9746                let edits = edits
 9747                    .into_iter()
 9748                    .map(|range| {
 9749                        let end_point = TP::to_point(&range.end, &snapshot);
 9750                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9751
 9752                        if end_point == start_point {
 9753                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9754                                .saturating_sub(1);
 9755                            start_point =
 9756                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9757                        };
 9758
 9759                        (start_point..end_point, empty_str.clone())
 9760                    })
 9761                    .sorted_by_key(|(range, _)| range.start)
 9762                    .collect::<Vec<_>>();
 9763                buffer.update(cx, |this, cx| {
 9764                    this.edit(edits, None, cx);
 9765                })
 9766            }
 9767            this.refresh_inline_completion(true, false, window, cx);
 9768            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9769        });
 9770    }
 9771
 9772    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9773        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9774        self.transact(window, cx, |this, window, cx| {
 9775            this.change_selections(Default::default(), window, cx, |s| {
 9776                s.move_with(|map, selection| {
 9777                    if selection.is_empty() {
 9778                        let cursor = movement::right(map, selection.head());
 9779                        selection.end = cursor;
 9780                        selection.reversed = true;
 9781                        selection.goal = SelectionGoal::None;
 9782                    }
 9783                })
 9784            });
 9785            this.insert("", window, cx);
 9786            this.refresh_inline_completion(true, false, window, cx);
 9787        });
 9788    }
 9789
 9790    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9791        if self.mode.is_single_line() {
 9792            cx.propagate();
 9793            return;
 9794        }
 9795
 9796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9797        if self.move_to_prev_snippet_tabstop(window, cx) {
 9798            return;
 9799        }
 9800        self.outdent(&Outdent, window, cx);
 9801    }
 9802
 9803    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9804        if self.mode.is_single_line() {
 9805            cx.propagate();
 9806            return;
 9807        }
 9808
 9809        if self.move_to_next_snippet_tabstop(window, cx) {
 9810            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9811            return;
 9812        }
 9813        if self.read_only(cx) {
 9814            return;
 9815        }
 9816        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9817        let mut selections = self.selections.all_adjusted(cx);
 9818        let buffer = self.buffer.read(cx);
 9819        let snapshot = buffer.snapshot(cx);
 9820        let rows_iter = selections.iter().map(|s| s.head().row);
 9821        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9822
 9823        let has_some_cursor_in_whitespace = selections
 9824            .iter()
 9825            .filter(|selection| selection.is_empty())
 9826            .any(|selection| {
 9827                let cursor = selection.head();
 9828                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9829                cursor.column < current_indent.len
 9830            });
 9831
 9832        let mut edits = Vec::new();
 9833        let mut prev_edited_row = 0;
 9834        let mut row_delta = 0;
 9835        for selection in &mut selections {
 9836            if selection.start.row != prev_edited_row {
 9837                row_delta = 0;
 9838            }
 9839            prev_edited_row = selection.end.row;
 9840
 9841            // If the selection is non-empty, then increase the indentation of the selected lines.
 9842            if !selection.is_empty() {
 9843                row_delta =
 9844                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9845                continue;
 9846            }
 9847
 9848            let cursor = selection.head();
 9849            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9850            if let Some(suggested_indent) =
 9851                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9852            {
 9853                // Don't do anything if already at suggested indent
 9854                // and there is any other cursor which is not
 9855                if has_some_cursor_in_whitespace
 9856                    && cursor.column == current_indent.len
 9857                    && current_indent.len == suggested_indent.len
 9858                {
 9859                    continue;
 9860                }
 9861
 9862                // Adjust line and move cursor to suggested indent
 9863                // if cursor is not at suggested indent
 9864                if cursor.column < suggested_indent.len
 9865                    && cursor.column <= current_indent.len
 9866                    && current_indent.len <= suggested_indent.len
 9867                {
 9868                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9869                    selection.end = selection.start;
 9870                    if row_delta == 0 {
 9871                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9872                            cursor.row,
 9873                            current_indent,
 9874                            suggested_indent,
 9875                        ));
 9876                        row_delta = suggested_indent.len - current_indent.len;
 9877                    }
 9878                    continue;
 9879                }
 9880
 9881                // If current indent is more than suggested indent
 9882                // only move cursor to current indent and skip indent
 9883                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9884                    selection.start = Point::new(cursor.row, current_indent.len);
 9885                    selection.end = selection.start;
 9886                    continue;
 9887                }
 9888            }
 9889
 9890            // Otherwise, insert a hard or soft tab.
 9891            let settings = buffer.language_settings_at(cursor, cx);
 9892            let tab_size = if settings.hard_tabs {
 9893                IndentSize::tab()
 9894            } else {
 9895                let tab_size = settings.tab_size.get();
 9896                let indent_remainder = snapshot
 9897                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9898                    .flat_map(str::chars)
 9899                    .fold(row_delta % tab_size, |counter: u32, c| {
 9900                        if c == '\t' {
 9901                            0
 9902                        } else {
 9903                            (counter + 1) % tab_size
 9904                        }
 9905                    });
 9906
 9907                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9908                IndentSize::spaces(chars_to_next_tab_stop)
 9909            };
 9910            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9911            selection.end = selection.start;
 9912            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9913            row_delta += tab_size.len;
 9914        }
 9915
 9916        self.transact(window, cx, |this, window, cx| {
 9917            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9918            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9919            this.refresh_inline_completion(true, false, window, cx);
 9920        });
 9921    }
 9922
 9923    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9924        if self.read_only(cx) {
 9925            return;
 9926        }
 9927        if self.mode.is_single_line() {
 9928            cx.propagate();
 9929            return;
 9930        }
 9931
 9932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9933        let mut selections = self.selections.all::<Point>(cx);
 9934        let mut prev_edited_row = 0;
 9935        let mut row_delta = 0;
 9936        let mut edits = Vec::new();
 9937        let buffer = self.buffer.read(cx);
 9938        let snapshot = buffer.snapshot(cx);
 9939        for selection in &mut selections {
 9940            if selection.start.row != prev_edited_row {
 9941                row_delta = 0;
 9942            }
 9943            prev_edited_row = selection.end.row;
 9944
 9945            row_delta =
 9946                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9947        }
 9948
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9951            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9952        });
 9953    }
 9954
 9955    fn indent_selection(
 9956        buffer: &MultiBuffer,
 9957        snapshot: &MultiBufferSnapshot,
 9958        selection: &mut Selection<Point>,
 9959        edits: &mut Vec<(Range<Point>, String)>,
 9960        delta_for_start_row: u32,
 9961        cx: &App,
 9962    ) -> u32 {
 9963        let settings = buffer.language_settings_at(selection.start, cx);
 9964        let tab_size = settings.tab_size.get();
 9965        let indent_kind = if settings.hard_tabs {
 9966            IndentKind::Tab
 9967        } else {
 9968            IndentKind::Space
 9969        };
 9970        let mut start_row = selection.start.row;
 9971        let mut end_row = selection.end.row + 1;
 9972
 9973        // If a selection ends at the beginning of a line, don't indent
 9974        // that last line.
 9975        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9976            end_row -= 1;
 9977        }
 9978
 9979        // Avoid re-indenting a row that has already been indented by a
 9980        // previous selection, but still update this selection's column
 9981        // to reflect that indentation.
 9982        if delta_for_start_row > 0 {
 9983            start_row += 1;
 9984            selection.start.column += delta_for_start_row;
 9985            if selection.end.row == selection.start.row {
 9986                selection.end.column += delta_for_start_row;
 9987            }
 9988        }
 9989
 9990        let mut delta_for_end_row = 0;
 9991        let has_multiple_rows = start_row + 1 != end_row;
 9992        for row in start_row..end_row {
 9993            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9994            let indent_delta = match (current_indent.kind, indent_kind) {
 9995                (IndentKind::Space, IndentKind::Space) => {
 9996                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9997                    IndentSize::spaces(columns_to_next_tab_stop)
 9998                }
 9999                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10000                (_, IndentKind::Tab) => IndentSize::tab(),
10001            };
10002
10003            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10004                0
10005            } else {
10006                selection.start.column
10007            };
10008            let row_start = Point::new(row, start);
10009            edits.push((
10010                row_start..row_start,
10011                indent_delta.chars().collect::<String>(),
10012            ));
10013
10014            // Update this selection's endpoints to reflect the indentation.
10015            if row == selection.start.row {
10016                selection.start.column += indent_delta.len;
10017            }
10018            if row == selection.end.row {
10019                selection.end.column += indent_delta.len;
10020                delta_for_end_row = indent_delta.len;
10021            }
10022        }
10023
10024        if selection.start.row == selection.end.row {
10025            delta_for_start_row + delta_for_end_row
10026        } else {
10027            delta_for_end_row
10028        }
10029    }
10030
10031    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10032        if self.read_only(cx) {
10033            return;
10034        }
10035        if self.mode.is_single_line() {
10036            cx.propagate();
10037            return;
10038        }
10039
10040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10041        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10042        let selections = self.selections.all::<Point>(cx);
10043        let mut deletion_ranges = Vec::new();
10044        let mut last_outdent = None;
10045        {
10046            let buffer = self.buffer.read(cx);
10047            let snapshot = buffer.snapshot(cx);
10048            for selection in &selections {
10049                let settings = buffer.language_settings_at(selection.start, cx);
10050                let tab_size = settings.tab_size.get();
10051                let mut rows = selection.spanned_rows(false, &display_map);
10052
10053                // Avoid re-outdenting a row that has already been outdented by a
10054                // previous selection.
10055                if let Some(last_row) = last_outdent {
10056                    if last_row == rows.start {
10057                        rows.start = rows.start.next_row();
10058                    }
10059                }
10060                let has_multiple_rows = rows.len() > 1;
10061                for row in rows.iter_rows() {
10062                    let indent_size = snapshot.indent_size_for_line(row);
10063                    if indent_size.len > 0 {
10064                        let deletion_len = match indent_size.kind {
10065                            IndentKind::Space => {
10066                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10067                                if columns_to_prev_tab_stop == 0 {
10068                                    tab_size
10069                                } else {
10070                                    columns_to_prev_tab_stop
10071                                }
10072                            }
10073                            IndentKind::Tab => 1,
10074                        };
10075                        let start = if has_multiple_rows
10076                            || deletion_len > selection.start.column
10077                            || indent_size.len < selection.start.column
10078                        {
10079                            0
10080                        } else {
10081                            selection.start.column - deletion_len
10082                        };
10083                        deletion_ranges.push(
10084                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10085                        );
10086                        last_outdent = Some(row);
10087                    }
10088                }
10089            }
10090        }
10091
10092        self.transact(window, cx, |this, window, cx| {
10093            this.buffer.update(cx, |buffer, cx| {
10094                let empty_str: Arc<str> = Arc::default();
10095                buffer.edit(
10096                    deletion_ranges
10097                        .into_iter()
10098                        .map(|range| (range, empty_str.clone())),
10099                    None,
10100                    cx,
10101                );
10102            });
10103            let selections = this.selections.all::<usize>(cx);
10104            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10105        });
10106    }
10107
10108    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10109        if self.read_only(cx) {
10110            return;
10111        }
10112        if self.mode.is_single_line() {
10113            cx.propagate();
10114            return;
10115        }
10116
10117        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10118        let selections = self
10119            .selections
10120            .all::<usize>(cx)
10121            .into_iter()
10122            .map(|s| s.range());
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |buffer, cx| {
10126                buffer.autoindent_ranges(selections, cx);
10127            });
10128            let selections = this.selections.all::<usize>(cx);
10129            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10130        });
10131    }
10132
10133    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10135        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10136        let selections = self.selections.all::<Point>(cx);
10137
10138        let mut new_cursors = Vec::new();
10139        let mut edit_ranges = Vec::new();
10140        let mut selections = selections.iter().peekable();
10141        while let Some(selection) = selections.next() {
10142            let mut rows = selection.spanned_rows(false, &display_map);
10143            let goal_display_column = selection.head().to_display_point(&display_map).column();
10144
10145            // Accumulate contiguous regions of rows that we want to delete.
10146            while let Some(next_selection) = selections.peek() {
10147                let next_rows = next_selection.spanned_rows(false, &display_map);
10148                if next_rows.start <= rows.end {
10149                    rows.end = next_rows.end;
10150                    selections.next().unwrap();
10151                } else {
10152                    break;
10153                }
10154            }
10155
10156            let buffer = &display_map.buffer_snapshot;
10157            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10158            let edit_end;
10159            let cursor_buffer_row;
10160            if buffer.max_point().row >= rows.end.0 {
10161                // If there's a line after the range, delete the \n from the end of the row range
10162                // and position the cursor on the next line.
10163                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10164                cursor_buffer_row = rows.end;
10165            } else {
10166                // If there isn't a line after the range, delete the \n from the line before the
10167                // start of the row range and position the cursor there.
10168                edit_start = edit_start.saturating_sub(1);
10169                edit_end = buffer.len();
10170                cursor_buffer_row = rows.start.previous_row();
10171            }
10172
10173            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10174            *cursor.column_mut() =
10175                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10176
10177            new_cursors.push((
10178                selection.id,
10179                buffer.anchor_after(cursor.to_point(&display_map)),
10180            ));
10181            edit_ranges.push(edit_start..edit_end);
10182        }
10183
10184        self.transact(window, cx, |this, window, cx| {
10185            let buffer = this.buffer.update(cx, |buffer, cx| {
10186                let empty_str: Arc<str> = Arc::default();
10187                buffer.edit(
10188                    edit_ranges
10189                        .into_iter()
10190                        .map(|range| (range, empty_str.clone())),
10191                    None,
10192                    cx,
10193                );
10194                buffer.snapshot(cx)
10195            });
10196            let new_selections = new_cursors
10197                .into_iter()
10198                .map(|(id, cursor)| {
10199                    let cursor = cursor.to_point(&buffer);
10200                    Selection {
10201                        id,
10202                        start: cursor,
10203                        end: cursor,
10204                        reversed: false,
10205                        goal: SelectionGoal::None,
10206                    }
10207                })
10208                .collect();
10209
10210            this.change_selections(Default::default(), window, cx, |s| {
10211                s.select(new_selections);
10212            });
10213        });
10214    }
10215
10216    pub fn join_lines_impl(
10217        &mut self,
10218        insert_whitespace: bool,
10219        window: &mut Window,
10220        cx: &mut Context<Self>,
10221    ) {
10222        if self.read_only(cx) {
10223            return;
10224        }
10225        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10226        for selection in self.selections.all::<Point>(cx) {
10227            let start = MultiBufferRow(selection.start.row);
10228            // Treat single line selections as if they include the next line. Otherwise this action
10229            // would do nothing for single line selections individual cursors.
10230            let end = if selection.start.row == selection.end.row {
10231                MultiBufferRow(selection.start.row + 1)
10232            } else {
10233                MultiBufferRow(selection.end.row)
10234            };
10235
10236            if let Some(last_row_range) = row_ranges.last_mut() {
10237                if start <= last_row_range.end {
10238                    last_row_range.end = end;
10239                    continue;
10240                }
10241            }
10242            row_ranges.push(start..end);
10243        }
10244
10245        let snapshot = self.buffer.read(cx).snapshot(cx);
10246        let mut cursor_positions = Vec::new();
10247        for row_range in &row_ranges {
10248            let anchor = snapshot.anchor_before(Point::new(
10249                row_range.end.previous_row().0,
10250                snapshot.line_len(row_range.end.previous_row()),
10251            ));
10252            cursor_positions.push(anchor..anchor);
10253        }
10254
10255        self.transact(window, cx, |this, window, cx| {
10256            for row_range in row_ranges.into_iter().rev() {
10257                for row in row_range.iter_rows().rev() {
10258                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10259                    let next_line_row = row.next_row();
10260                    let indent = snapshot.indent_size_for_line(next_line_row);
10261                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10262
10263                    let replace =
10264                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10265                            " "
10266                        } else {
10267                            ""
10268                        };
10269
10270                    this.buffer.update(cx, |buffer, cx| {
10271                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10272                    });
10273                }
10274            }
10275
10276            this.change_selections(Default::default(), window, cx, |s| {
10277                s.select_anchor_ranges(cursor_positions)
10278            });
10279        });
10280    }
10281
10282    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10283        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10284        self.join_lines_impl(true, window, cx);
10285    }
10286
10287    pub fn sort_lines_case_sensitive(
10288        &mut self,
10289        _: &SortLinesCaseSensitive,
10290        window: &mut Window,
10291        cx: &mut Context<Self>,
10292    ) {
10293        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10294    }
10295
10296    pub fn sort_lines_by_length(
10297        &mut self,
10298        _: &SortLinesByLength,
10299        window: &mut Window,
10300        cx: &mut Context<Self>,
10301    ) {
10302        self.manipulate_immutable_lines(window, cx, |lines| {
10303            lines.sort_by_key(|&line| line.chars().count())
10304        })
10305    }
10306
10307    pub fn sort_lines_case_insensitive(
10308        &mut self,
10309        _: &SortLinesCaseInsensitive,
10310        window: &mut Window,
10311        cx: &mut Context<Self>,
10312    ) {
10313        self.manipulate_immutable_lines(window, cx, |lines| {
10314            lines.sort_by_key(|line| line.to_lowercase())
10315        })
10316    }
10317
10318    pub fn unique_lines_case_insensitive(
10319        &mut self,
10320        _: &UniqueLinesCaseInsensitive,
10321        window: &mut Window,
10322        cx: &mut Context<Self>,
10323    ) {
10324        self.manipulate_immutable_lines(window, cx, |lines| {
10325            let mut seen = HashSet::default();
10326            lines.retain(|line| seen.insert(line.to_lowercase()));
10327        })
10328    }
10329
10330    pub fn unique_lines_case_sensitive(
10331        &mut self,
10332        _: &UniqueLinesCaseSensitive,
10333        window: &mut Window,
10334        cx: &mut Context<Self>,
10335    ) {
10336        self.manipulate_immutable_lines(window, cx, |lines| {
10337            let mut seen = HashSet::default();
10338            lines.retain(|line| seen.insert(*line));
10339        })
10340    }
10341
10342    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10343        let Some(project) = self.project.clone() else {
10344            return;
10345        };
10346        self.reload(project, window, cx)
10347            .detach_and_notify_err(window, cx);
10348    }
10349
10350    pub fn restore_file(
10351        &mut self,
10352        _: &::git::RestoreFile,
10353        window: &mut Window,
10354        cx: &mut Context<Self>,
10355    ) {
10356        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10357        let mut buffer_ids = HashSet::default();
10358        let snapshot = self.buffer().read(cx).snapshot(cx);
10359        for selection in self.selections.all::<usize>(cx) {
10360            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10361        }
10362
10363        let buffer = self.buffer().read(cx);
10364        let ranges = buffer_ids
10365            .into_iter()
10366            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10367            .collect::<Vec<_>>();
10368
10369        self.restore_hunks_in_ranges(ranges, window, cx);
10370    }
10371
10372    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10373        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10374        let selections = self
10375            .selections
10376            .all(cx)
10377            .into_iter()
10378            .map(|s| s.range())
10379            .collect();
10380        self.restore_hunks_in_ranges(selections, window, cx);
10381    }
10382
10383    pub fn restore_hunks_in_ranges(
10384        &mut self,
10385        ranges: Vec<Range<Point>>,
10386        window: &mut Window,
10387        cx: &mut Context<Editor>,
10388    ) {
10389        let mut revert_changes = HashMap::default();
10390        let chunk_by = self
10391            .snapshot(window, cx)
10392            .hunks_for_ranges(ranges)
10393            .into_iter()
10394            .chunk_by(|hunk| hunk.buffer_id);
10395        for (buffer_id, hunks) in &chunk_by {
10396            let hunks = hunks.collect::<Vec<_>>();
10397            for hunk in &hunks {
10398                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10399            }
10400            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10401        }
10402        drop(chunk_by);
10403        if !revert_changes.is_empty() {
10404            self.transact(window, cx, |editor, window, cx| {
10405                editor.restore(revert_changes, window, cx);
10406            });
10407        }
10408    }
10409
10410    pub fn open_active_item_in_terminal(
10411        &mut self,
10412        _: &OpenInTerminal,
10413        window: &mut Window,
10414        cx: &mut Context<Self>,
10415    ) {
10416        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10417            let project_path = buffer.read(cx).project_path(cx)?;
10418            let project = self.project.as_ref()?.read(cx);
10419            let entry = project.entry_for_path(&project_path, cx)?;
10420            let parent = match &entry.canonical_path {
10421                Some(canonical_path) => canonical_path.to_path_buf(),
10422                None => project.absolute_path(&project_path, cx)?,
10423            }
10424            .parent()?
10425            .to_path_buf();
10426            Some(parent)
10427        }) {
10428            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10429        }
10430    }
10431
10432    fn set_breakpoint_context_menu(
10433        &mut self,
10434        display_row: DisplayRow,
10435        position: Option<Anchor>,
10436        clicked_point: gpui::Point<Pixels>,
10437        window: &mut Window,
10438        cx: &mut Context<Self>,
10439    ) {
10440        let source = self
10441            .buffer
10442            .read(cx)
10443            .snapshot(cx)
10444            .anchor_before(Point::new(display_row.0, 0u32));
10445
10446        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10447
10448        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10449            self,
10450            source,
10451            clicked_point,
10452            context_menu,
10453            window,
10454            cx,
10455        );
10456    }
10457
10458    fn add_edit_breakpoint_block(
10459        &mut self,
10460        anchor: Anchor,
10461        breakpoint: &Breakpoint,
10462        edit_action: BreakpointPromptEditAction,
10463        window: &mut Window,
10464        cx: &mut Context<Self>,
10465    ) {
10466        let weak_editor = cx.weak_entity();
10467        let bp_prompt = cx.new(|cx| {
10468            BreakpointPromptEditor::new(
10469                weak_editor,
10470                anchor,
10471                breakpoint.clone(),
10472                edit_action,
10473                window,
10474                cx,
10475            )
10476        });
10477
10478        let height = bp_prompt.update(cx, |this, cx| {
10479            this.prompt
10480                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10481        });
10482        let cloned_prompt = bp_prompt.clone();
10483        let blocks = vec![BlockProperties {
10484            style: BlockStyle::Sticky,
10485            placement: BlockPlacement::Above(anchor),
10486            height: Some(height),
10487            render: Arc::new(move |cx| {
10488                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10489                cloned_prompt.clone().into_any_element()
10490            }),
10491            priority: 0,
10492        }];
10493
10494        let focus_handle = bp_prompt.focus_handle(cx);
10495        window.focus(&focus_handle);
10496
10497        let block_ids = self.insert_blocks(blocks, None, cx);
10498        bp_prompt.update(cx, |prompt, _| {
10499            prompt.add_block_ids(block_ids);
10500        });
10501    }
10502
10503    pub(crate) fn breakpoint_at_row(
10504        &self,
10505        row: u32,
10506        window: &mut Window,
10507        cx: &mut Context<Self>,
10508    ) -> Option<(Anchor, Breakpoint)> {
10509        let snapshot = self.snapshot(window, cx);
10510        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10511
10512        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10513    }
10514
10515    pub(crate) fn breakpoint_at_anchor(
10516        &self,
10517        breakpoint_position: Anchor,
10518        snapshot: &EditorSnapshot,
10519        cx: &mut Context<Self>,
10520    ) -> Option<(Anchor, Breakpoint)> {
10521        let project = self.project.clone()?;
10522
10523        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10524            snapshot
10525                .buffer_snapshot
10526                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10527        })?;
10528
10529        let enclosing_excerpt = breakpoint_position.excerpt_id;
10530        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10531        let buffer_snapshot = buffer.read(cx).snapshot();
10532
10533        let row = buffer_snapshot
10534            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10535            .row;
10536
10537        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10538        let anchor_end = snapshot
10539            .buffer_snapshot
10540            .anchor_after(Point::new(row, line_len));
10541
10542        let bp = self
10543            .breakpoint_store
10544            .as_ref()?
10545            .read_with(cx, |breakpoint_store, cx| {
10546                breakpoint_store
10547                    .breakpoints(
10548                        &buffer,
10549                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10550                        &buffer_snapshot,
10551                        cx,
10552                    )
10553                    .next()
10554                    .and_then(|(bp, _)| {
10555                        let breakpoint_row = buffer_snapshot
10556                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10557                            .row;
10558
10559                        if breakpoint_row == row {
10560                            snapshot
10561                                .buffer_snapshot
10562                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10563                                .map(|position| (position, bp.bp.clone()))
10564                        } else {
10565                            None
10566                        }
10567                    })
10568            });
10569        bp
10570    }
10571
10572    pub fn edit_log_breakpoint(
10573        &mut self,
10574        _: &EditLogBreakpoint,
10575        window: &mut Window,
10576        cx: &mut Context<Self>,
10577    ) {
10578        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10579            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10580                message: None,
10581                state: BreakpointState::Enabled,
10582                condition: None,
10583                hit_condition: None,
10584            });
10585
10586            self.add_edit_breakpoint_block(
10587                anchor,
10588                &breakpoint,
10589                BreakpointPromptEditAction::Log,
10590                window,
10591                cx,
10592            );
10593        }
10594    }
10595
10596    fn breakpoints_at_cursors(
10597        &self,
10598        window: &mut Window,
10599        cx: &mut Context<Self>,
10600    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10601        let snapshot = self.snapshot(window, cx);
10602        let cursors = self
10603            .selections
10604            .disjoint_anchors()
10605            .into_iter()
10606            .map(|selection| {
10607                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10608
10609                let breakpoint_position = self
10610                    .breakpoint_at_row(cursor_position.row, window, cx)
10611                    .map(|bp| bp.0)
10612                    .unwrap_or_else(|| {
10613                        snapshot
10614                            .display_snapshot
10615                            .buffer_snapshot
10616                            .anchor_after(Point::new(cursor_position.row, 0))
10617                    });
10618
10619                let breakpoint = self
10620                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10621                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10622
10623                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10624            })
10625            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
10626            .collect::<HashMap<Anchor, _>>();
10627
10628        cursors.into_iter().collect()
10629    }
10630
10631    pub fn enable_breakpoint(
10632        &mut self,
10633        _: &crate::actions::EnableBreakpoint,
10634        window: &mut Window,
10635        cx: &mut Context<Self>,
10636    ) {
10637        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10638            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10639                continue;
10640            };
10641            self.edit_breakpoint_at_anchor(
10642                anchor,
10643                breakpoint,
10644                BreakpointEditAction::InvertState,
10645                cx,
10646            );
10647        }
10648    }
10649
10650    pub fn disable_breakpoint(
10651        &mut self,
10652        _: &crate::actions::DisableBreakpoint,
10653        window: &mut Window,
10654        cx: &mut Context<Self>,
10655    ) {
10656        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10657            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10658                continue;
10659            };
10660            self.edit_breakpoint_at_anchor(
10661                anchor,
10662                breakpoint,
10663                BreakpointEditAction::InvertState,
10664                cx,
10665            );
10666        }
10667    }
10668
10669    pub fn toggle_breakpoint(
10670        &mut self,
10671        _: &crate::actions::ToggleBreakpoint,
10672        window: &mut Window,
10673        cx: &mut Context<Self>,
10674    ) {
10675        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10676            if let Some(breakpoint) = breakpoint {
10677                self.edit_breakpoint_at_anchor(
10678                    anchor,
10679                    breakpoint,
10680                    BreakpointEditAction::Toggle,
10681                    cx,
10682                );
10683            } else {
10684                self.edit_breakpoint_at_anchor(
10685                    anchor,
10686                    Breakpoint::new_standard(),
10687                    BreakpointEditAction::Toggle,
10688                    cx,
10689                );
10690            }
10691        }
10692    }
10693
10694    pub fn edit_breakpoint_at_anchor(
10695        &mut self,
10696        breakpoint_position: Anchor,
10697        breakpoint: Breakpoint,
10698        edit_action: BreakpointEditAction,
10699        cx: &mut Context<Self>,
10700    ) {
10701        let Some(breakpoint_store) = &self.breakpoint_store else {
10702            return;
10703        };
10704
10705        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10706            if breakpoint_position == Anchor::min() {
10707                self.buffer()
10708                    .read(cx)
10709                    .excerpt_buffer_ids()
10710                    .into_iter()
10711                    .next()
10712            } else {
10713                None
10714            }
10715        }) else {
10716            return;
10717        };
10718
10719        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10720            return;
10721        };
10722
10723        breakpoint_store.update(cx, |breakpoint_store, cx| {
10724            breakpoint_store.toggle_breakpoint(
10725                buffer,
10726                BreakpointWithPosition {
10727                    position: breakpoint_position.text_anchor,
10728                    bp: breakpoint,
10729                },
10730                edit_action,
10731                cx,
10732            );
10733        });
10734
10735        cx.notify();
10736    }
10737
10738    #[cfg(any(test, feature = "test-support"))]
10739    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10740        self.breakpoint_store.clone()
10741    }
10742
10743    pub fn prepare_restore_change(
10744        &self,
10745        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10746        hunk: &MultiBufferDiffHunk,
10747        cx: &mut App,
10748    ) -> Option<()> {
10749        if hunk.is_created_file() {
10750            return None;
10751        }
10752        let buffer = self.buffer.read(cx);
10753        let diff = buffer.diff_for(hunk.buffer_id)?;
10754        let buffer = buffer.buffer(hunk.buffer_id)?;
10755        let buffer = buffer.read(cx);
10756        let original_text = diff
10757            .read(cx)
10758            .base_text()
10759            .as_rope()
10760            .slice(hunk.diff_base_byte_range.clone());
10761        let buffer_snapshot = buffer.snapshot();
10762        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10763        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10764            probe
10765                .0
10766                .start
10767                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10768                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10769        }) {
10770            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10771            Some(())
10772        } else {
10773            None
10774        }
10775    }
10776
10777    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10778        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10779    }
10780
10781    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10782        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10783    }
10784
10785    fn manipulate_lines<M>(
10786        &mut self,
10787        window: &mut Window,
10788        cx: &mut Context<Self>,
10789        mut manipulate: M,
10790    ) where
10791        M: FnMut(&str) -> LineManipulationResult,
10792    {
10793        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10794
10795        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10796        let buffer = self.buffer.read(cx).snapshot(cx);
10797
10798        let mut edits = Vec::new();
10799
10800        let selections = self.selections.all::<Point>(cx);
10801        let mut selections = selections.iter().peekable();
10802        let mut contiguous_row_selections = Vec::new();
10803        let mut new_selections = Vec::new();
10804        let mut added_lines = 0;
10805        let mut removed_lines = 0;
10806
10807        while let Some(selection) = selections.next() {
10808            let (start_row, end_row) = consume_contiguous_rows(
10809                &mut contiguous_row_selections,
10810                selection,
10811                &display_map,
10812                &mut selections,
10813            );
10814
10815            let start_point = Point::new(start_row.0, 0);
10816            let end_point = Point::new(
10817                end_row.previous_row().0,
10818                buffer.line_len(end_row.previous_row()),
10819            );
10820            let text = buffer
10821                .text_for_range(start_point..end_point)
10822                .collect::<String>();
10823
10824            let LineManipulationResult {
10825                new_text,
10826                line_count_before,
10827                line_count_after,
10828            } = manipulate(&text);
10829
10830            edits.push((start_point..end_point, new_text));
10831
10832            // Selections must change based on added and removed line count
10833            let start_row =
10834                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10835            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10836            new_selections.push(Selection {
10837                id: selection.id,
10838                start: start_row,
10839                end: end_row,
10840                goal: SelectionGoal::None,
10841                reversed: selection.reversed,
10842            });
10843
10844            if line_count_after > line_count_before {
10845                added_lines += line_count_after - line_count_before;
10846            } else if line_count_before > line_count_after {
10847                removed_lines += line_count_before - line_count_after;
10848            }
10849        }
10850
10851        self.transact(window, cx, |this, window, cx| {
10852            let buffer = this.buffer.update(cx, |buffer, cx| {
10853                buffer.edit(edits, None, cx);
10854                buffer.snapshot(cx)
10855            });
10856
10857            // Recalculate offsets on newly edited buffer
10858            let new_selections = new_selections
10859                .iter()
10860                .map(|s| {
10861                    let start_point = Point::new(s.start.0, 0);
10862                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10863                    Selection {
10864                        id: s.id,
10865                        start: buffer.point_to_offset(start_point),
10866                        end: buffer.point_to_offset(end_point),
10867                        goal: s.goal,
10868                        reversed: s.reversed,
10869                    }
10870                })
10871                .collect();
10872
10873            this.change_selections(Default::default(), window, cx, |s| {
10874                s.select(new_selections);
10875            });
10876
10877            this.request_autoscroll(Autoscroll::fit(), cx);
10878        });
10879    }
10880
10881    fn manipulate_immutable_lines<Fn>(
10882        &mut self,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885        mut callback: Fn,
10886    ) where
10887        Fn: FnMut(&mut Vec<&str>),
10888    {
10889        self.manipulate_lines(window, cx, |text| {
10890            let mut lines: Vec<&str> = text.split('\n').collect();
10891            let line_count_before = lines.len();
10892
10893            callback(&mut lines);
10894
10895            LineManipulationResult {
10896                new_text: lines.join("\n"),
10897                line_count_before,
10898                line_count_after: lines.len(),
10899            }
10900        });
10901    }
10902
10903    fn manipulate_mutable_lines<Fn>(
10904        &mut self,
10905        window: &mut Window,
10906        cx: &mut Context<Self>,
10907        mut callback: Fn,
10908    ) where
10909        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10910    {
10911        self.manipulate_lines(window, cx, |text| {
10912            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10913            let line_count_before = lines.len();
10914
10915            callback(&mut lines);
10916
10917            LineManipulationResult {
10918                new_text: lines.join("\n"),
10919                line_count_before,
10920                line_count_after: lines.len(),
10921            }
10922        });
10923    }
10924
10925    pub fn convert_indentation_to_spaces(
10926        &mut self,
10927        _: &ConvertIndentationToSpaces,
10928        window: &mut Window,
10929        cx: &mut Context<Self>,
10930    ) {
10931        let settings = self.buffer.read(cx).language_settings(cx);
10932        let tab_size = settings.tab_size.get() as usize;
10933
10934        self.manipulate_mutable_lines(window, cx, |lines| {
10935            // Allocates a reasonably sized scratch buffer once for the whole loop
10936            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10937            // Avoids recomputing spaces that could be inserted many times
10938            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10939                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10940                .collect();
10941
10942            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10943                let mut chars = line.as_ref().chars();
10944                let mut col = 0;
10945                let mut changed = false;
10946
10947                while let Some(ch) = chars.next() {
10948                    match ch {
10949                        ' ' => {
10950                            reindented_line.push(' ');
10951                            col += 1;
10952                        }
10953                        '\t' => {
10954                            // \t are converted to spaces depending on the current column
10955                            let spaces_len = tab_size - (col % tab_size);
10956                            reindented_line.extend(&space_cache[spaces_len - 1]);
10957                            col += spaces_len;
10958                            changed = true;
10959                        }
10960                        _ => {
10961                            // If we dont append before break, the character is consumed
10962                            reindented_line.push(ch);
10963                            break;
10964                        }
10965                    }
10966                }
10967
10968                if !changed {
10969                    reindented_line.clear();
10970                    continue;
10971                }
10972                // Append the rest of the line and replace old reference with new one
10973                reindented_line.extend(chars);
10974                *line = Cow::Owned(reindented_line.clone());
10975                reindented_line.clear();
10976            }
10977        });
10978    }
10979
10980    pub fn convert_indentation_to_tabs(
10981        &mut self,
10982        _: &ConvertIndentationToTabs,
10983        window: &mut Window,
10984        cx: &mut Context<Self>,
10985    ) {
10986        let settings = self.buffer.read(cx).language_settings(cx);
10987        let tab_size = settings.tab_size.get() as usize;
10988
10989        self.manipulate_mutable_lines(window, cx, |lines| {
10990            // Allocates a reasonably sized buffer once for the whole loop
10991            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10992            // Avoids recomputing spaces that could be inserted many times
10993            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10994                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10995                .collect();
10996
10997            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10998                let mut chars = line.chars();
10999                let mut spaces_count = 0;
11000                let mut first_non_indent_char = None;
11001                let mut changed = false;
11002
11003                while let Some(ch) = chars.next() {
11004                    match ch {
11005                        ' ' => {
11006                            // Keep track of spaces. Append \t when we reach tab_size
11007                            spaces_count += 1;
11008                            changed = true;
11009                            if spaces_count == tab_size {
11010                                reindented_line.push('\t');
11011                                spaces_count = 0;
11012                            }
11013                        }
11014                        '\t' => {
11015                            reindented_line.push('\t');
11016                            spaces_count = 0;
11017                        }
11018                        _ => {
11019                            // Dont append it yet, we might have remaining spaces
11020                            first_non_indent_char = Some(ch);
11021                            break;
11022                        }
11023                    }
11024                }
11025
11026                if !changed {
11027                    reindented_line.clear();
11028                    continue;
11029                }
11030                // Remaining spaces that didn't make a full tab stop
11031                if spaces_count > 0 {
11032                    reindented_line.extend(&space_cache[spaces_count - 1]);
11033                }
11034                // If we consume an extra character that was not indentation, add it back
11035                if let Some(extra_char) = first_non_indent_char {
11036                    reindented_line.push(extra_char);
11037                }
11038                // Append the rest of the line and replace old reference with new one
11039                reindented_line.extend(chars);
11040                *line = Cow::Owned(reindented_line.clone());
11041                reindented_line.clear();
11042            }
11043        });
11044    }
11045
11046    pub fn convert_to_upper_case(
11047        &mut self,
11048        _: &ConvertToUpperCase,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        self.manipulate_text(window, cx, |text| text.to_uppercase())
11053    }
11054
11055    pub fn convert_to_lower_case(
11056        &mut self,
11057        _: &ConvertToLowerCase,
11058        window: &mut Window,
11059        cx: &mut Context<Self>,
11060    ) {
11061        self.manipulate_text(window, cx, |text| text.to_lowercase())
11062    }
11063
11064    pub fn convert_to_title_case(
11065        &mut self,
11066        _: &ConvertToTitleCase,
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::Title))
11073                .join("\n")
11074        })
11075    }
11076
11077    pub fn convert_to_snake_case(
11078        &mut self,
11079        _: &ConvertToSnakeCase,
11080        window: &mut Window,
11081        cx: &mut Context<Self>,
11082    ) {
11083        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11084    }
11085
11086    pub fn convert_to_kebab_case(
11087        &mut self,
11088        _: &ConvertToKebabCase,
11089        window: &mut Window,
11090        cx: &mut Context<Self>,
11091    ) {
11092        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11093    }
11094
11095    pub fn convert_to_upper_camel_case(
11096        &mut self,
11097        _: &ConvertToUpperCamelCase,
11098        window: &mut Window,
11099        cx: &mut Context<Self>,
11100    ) {
11101        self.manipulate_text(window, cx, |text| {
11102            text.split('\n')
11103                .map(|line| line.to_case(Case::UpperCamel))
11104                .join("\n")
11105        })
11106    }
11107
11108    pub fn convert_to_lower_camel_case(
11109        &mut self,
11110        _: &ConvertToLowerCamelCase,
11111        window: &mut Window,
11112        cx: &mut Context<Self>,
11113    ) {
11114        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11115    }
11116
11117    pub fn convert_to_opposite_case(
11118        &mut self,
11119        _: &ConvertToOppositeCase,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122    ) {
11123        self.manipulate_text(window, cx, |text| {
11124            text.chars()
11125                .fold(String::with_capacity(text.len()), |mut t, c| {
11126                    if c.is_uppercase() {
11127                        t.extend(c.to_lowercase());
11128                    } else {
11129                        t.extend(c.to_uppercase());
11130                    }
11131                    t
11132                })
11133        })
11134    }
11135
11136    pub fn convert_to_sentence_case(
11137        &mut self,
11138        _: &ConvertToSentenceCase,
11139        window: &mut Window,
11140        cx: &mut Context<Self>,
11141    ) {
11142        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11143    }
11144
11145    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11146        self.manipulate_text(window, cx, |text| {
11147            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11148            if has_upper_case_characters {
11149                text.to_lowercase()
11150            } else {
11151                text.to_uppercase()
11152            }
11153        })
11154    }
11155
11156    pub fn convert_to_rot13(
11157        &mut self,
11158        _: &ConvertToRot13,
11159        window: &mut Window,
11160        cx: &mut Context<Self>,
11161    ) {
11162        self.manipulate_text(window, cx, |text| {
11163            text.chars()
11164                .map(|c| match c {
11165                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11166                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11167                    _ => c,
11168                })
11169                .collect()
11170        })
11171    }
11172
11173    pub fn convert_to_rot47(
11174        &mut self,
11175        _: &ConvertToRot47,
11176        window: &mut Window,
11177        cx: &mut Context<Self>,
11178    ) {
11179        self.manipulate_text(window, cx, |text| {
11180            text.chars()
11181                .map(|c| {
11182                    let code_point = c as u32;
11183                    if code_point >= 33 && code_point <= 126 {
11184                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11185                    }
11186                    c
11187                })
11188                .collect()
11189        })
11190    }
11191
11192    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11193    where
11194        Fn: FnMut(&str) -> String,
11195    {
11196        let buffer = self.buffer.read(cx).snapshot(cx);
11197
11198        let mut new_selections = Vec::new();
11199        let mut edits = Vec::new();
11200        let mut selection_adjustment = 0i32;
11201
11202        for selection in self.selections.all::<usize>(cx) {
11203            let selection_is_empty = selection.is_empty();
11204
11205            let (start, end) = if selection_is_empty {
11206                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11207                (word_range.start, word_range.end)
11208            } else {
11209                (selection.start, selection.end)
11210            };
11211
11212            let text = buffer.text_for_range(start..end).collect::<String>();
11213            let old_length = text.len() as i32;
11214            let text = callback(&text);
11215
11216            new_selections.push(Selection {
11217                start: (start as i32 - selection_adjustment) as usize,
11218                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11219                goal: SelectionGoal::None,
11220                ..selection
11221            });
11222
11223            selection_adjustment += old_length - text.len() as i32;
11224
11225            edits.push((start..end, text));
11226        }
11227
11228        self.transact(window, cx, |this, window, cx| {
11229            this.buffer.update(cx, |buffer, cx| {
11230                buffer.edit(edits, None, cx);
11231            });
11232
11233            this.change_selections(Default::default(), window, cx, |s| {
11234                s.select(new_selections);
11235            });
11236
11237            this.request_autoscroll(Autoscroll::fit(), cx);
11238        });
11239    }
11240
11241    pub fn move_selection_on_drop(
11242        &mut self,
11243        selection: &Selection<Anchor>,
11244        target: DisplayPoint,
11245        is_cut: bool,
11246        window: &mut Window,
11247        cx: &mut Context<Self>,
11248    ) {
11249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11250        let buffer = &display_map.buffer_snapshot;
11251        let mut edits = Vec::new();
11252        let insert_point = display_map
11253            .clip_point(target, Bias::Left)
11254            .to_point(&display_map);
11255        let text = buffer
11256            .text_for_range(selection.start..selection.end)
11257            .collect::<String>();
11258        if is_cut {
11259            edits.push(((selection.start..selection.end), String::new()));
11260        }
11261        let insert_anchor = buffer.anchor_before(insert_point);
11262        edits.push(((insert_anchor..insert_anchor), text));
11263        let last_edit_start = insert_anchor.bias_left(buffer);
11264        let last_edit_end = insert_anchor.bias_right(buffer);
11265        self.transact(window, cx, |this, window, cx| {
11266            this.buffer.update(cx, |buffer, cx| {
11267                buffer.edit(edits, None, cx);
11268            });
11269            this.change_selections(Default::default(), window, cx, |s| {
11270                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11271            });
11272        });
11273    }
11274
11275    pub fn clear_selection_drag_state(&mut self) {
11276        self.selection_drag_state = SelectionDragState::None;
11277    }
11278
11279    pub fn duplicate(
11280        &mut self,
11281        upwards: bool,
11282        whole_lines: bool,
11283        window: &mut Window,
11284        cx: &mut Context<Self>,
11285    ) {
11286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11287
11288        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11289        let buffer = &display_map.buffer_snapshot;
11290        let selections = self.selections.all::<Point>(cx);
11291
11292        let mut edits = Vec::new();
11293        let mut selections_iter = selections.iter().peekable();
11294        while let Some(selection) = selections_iter.next() {
11295            let mut rows = selection.spanned_rows(false, &display_map);
11296            // duplicate line-wise
11297            if whole_lines || selection.start == selection.end {
11298                // Avoid duplicating the same lines twice.
11299                while let Some(next_selection) = selections_iter.peek() {
11300                    let next_rows = next_selection.spanned_rows(false, &display_map);
11301                    if next_rows.start < rows.end {
11302                        rows.end = next_rows.end;
11303                        selections_iter.next().unwrap();
11304                    } else {
11305                        break;
11306                    }
11307                }
11308
11309                // Copy the text from the selected row region and splice it either at the start
11310                // or end of the region.
11311                let start = Point::new(rows.start.0, 0);
11312                let end = Point::new(
11313                    rows.end.previous_row().0,
11314                    buffer.line_len(rows.end.previous_row()),
11315                );
11316                let text = buffer
11317                    .text_for_range(start..end)
11318                    .chain(Some("\n"))
11319                    .collect::<String>();
11320                let insert_location = if upwards {
11321                    Point::new(rows.end.0, 0)
11322                } else {
11323                    start
11324                };
11325                edits.push((insert_location..insert_location, text));
11326            } else {
11327                // duplicate character-wise
11328                let start = selection.start;
11329                let end = selection.end;
11330                let text = buffer.text_for_range(start..end).collect::<String>();
11331                edits.push((selection.end..selection.end, text));
11332            }
11333        }
11334
11335        self.transact(window, cx, |this, _, cx| {
11336            this.buffer.update(cx, |buffer, cx| {
11337                buffer.edit(edits, None, cx);
11338            });
11339
11340            this.request_autoscroll(Autoscroll::fit(), cx);
11341        });
11342    }
11343
11344    pub fn duplicate_line_up(
11345        &mut self,
11346        _: &DuplicateLineUp,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.duplicate(true, true, window, cx);
11351    }
11352
11353    pub fn duplicate_line_down(
11354        &mut self,
11355        _: &DuplicateLineDown,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.duplicate(false, true, window, cx);
11360    }
11361
11362    pub fn duplicate_selection(
11363        &mut self,
11364        _: &DuplicateSelection,
11365        window: &mut Window,
11366        cx: &mut Context<Self>,
11367    ) {
11368        self.duplicate(false, false, window, cx);
11369    }
11370
11371    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11372        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11373        if self.mode.is_single_line() {
11374            cx.propagate();
11375            return;
11376        }
11377
11378        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11379        let buffer = self.buffer.read(cx).snapshot(cx);
11380
11381        let mut edits = Vec::new();
11382        let mut unfold_ranges = Vec::new();
11383        let mut refold_creases = Vec::new();
11384
11385        let selections = self.selections.all::<Point>(cx);
11386        let mut selections = selections.iter().peekable();
11387        let mut contiguous_row_selections = Vec::new();
11388        let mut new_selections = Vec::new();
11389
11390        while let Some(selection) = selections.next() {
11391            // Find all the selections that span a contiguous row range
11392            let (start_row, end_row) = consume_contiguous_rows(
11393                &mut contiguous_row_selections,
11394                selection,
11395                &display_map,
11396                &mut selections,
11397            );
11398
11399            // Move the text spanned by the row range to be before the line preceding the row range
11400            if start_row.0 > 0 {
11401                let range_to_move = Point::new(
11402                    start_row.previous_row().0,
11403                    buffer.line_len(start_row.previous_row()),
11404                )
11405                    ..Point::new(
11406                        end_row.previous_row().0,
11407                        buffer.line_len(end_row.previous_row()),
11408                    );
11409                let insertion_point = display_map
11410                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11411                    .0;
11412
11413                // Don't move lines across excerpts
11414                if buffer
11415                    .excerpt_containing(insertion_point..range_to_move.end)
11416                    .is_some()
11417                {
11418                    let text = buffer
11419                        .text_for_range(range_to_move.clone())
11420                        .flat_map(|s| s.chars())
11421                        .skip(1)
11422                        .chain(['\n'])
11423                        .collect::<String>();
11424
11425                    edits.push((
11426                        buffer.anchor_after(range_to_move.start)
11427                            ..buffer.anchor_before(range_to_move.end),
11428                        String::new(),
11429                    ));
11430                    let insertion_anchor = buffer.anchor_after(insertion_point);
11431                    edits.push((insertion_anchor..insertion_anchor, text));
11432
11433                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11434
11435                    // Move selections up
11436                    new_selections.extend(contiguous_row_selections.drain(..).map(
11437                        |mut selection| {
11438                            selection.start.row -= row_delta;
11439                            selection.end.row -= row_delta;
11440                            selection
11441                        },
11442                    ));
11443
11444                    // Move folds up
11445                    unfold_ranges.push(range_to_move.clone());
11446                    for fold in display_map.folds_in_range(
11447                        buffer.anchor_before(range_to_move.start)
11448                            ..buffer.anchor_after(range_to_move.end),
11449                    ) {
11450                        let mut start = fold.range.start.to_point(&buffer);
11451                        let mut end = fold.range.end.to_point(&buffer);
11452                        start.row -= row_delta;
11453                        end.row -= row_delta;
11454                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11455                    }
11456                }
11457            }
11458
11459            // If we didn't move line(s), preserve the existing selections
11460            new_selections.append(&mut contiguous_row_selections);
11461        }
11462
11463        self.transact(window, cx, |this, window, cx| {
11464            this.unfold_ranges(&unfold_ranges, true, true, cx);
11465            this.buffer.update(cx, |buffer, cx| {
11466                for (range, text) in edits {
11467                    buffer.edit([(range, text)], None, cx);
11468                }
11469            });
11470            this.fold_creases(refold_creases, true, window, cx);
11471            this.change_selections(Default::default(), window, cx, |s| {
11472                s.select(new_selections);
11473            })
11474        });
11475    }
11476
11477    pub fn move_line_down(
11478        &mut self,
11479        _: &MoveLineDown,
11480        window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11484        if self.mode.is_single_line() {
11485            cx.propagate();
11486            return;
11487        }
11488
11489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11490        let buffer = self.buffer.read(cx).snapshot(cx);
11491
11492        let mut edits = Vec::new();
11493        let mut unfold_ranges = Vec::new();
11494        let mut refold_creases = Vec::new();
11495
11496        let selections = self.selections.all::<Point>(cx);
11497        let mut selections = selections.iter().peekable();
11498        let mut contiguous_row_selections = Vec::new();
11499        let mut new_selections = Vec::new();
11500
11501        while let Some(selection) = selections.next() {
11502            // Find all the selections that span a contiguous row range
11503            let (start_row, end_row) = consume_contiguous_rows(
11504                &mut contiguous_row_selections,
11505                selection,
11506                &display_map,
11507                &mut selections,
11508            );
11509
11510            // Move the text spanned by the row range to be after the last line of the row range
11511            if end_row.0 <= buffer.max_point().row {
11512                let range_to_move =
11513                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11514                let insertion_point = display_map
11515                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11516                    .0;
11517
11518                // Don't move lines across excerpt boundaries
11519                if buffer
11520                    .excerpt_containing(range_to_move.start..insertion_point)
11521                    .is_some()
11522                {
11523                    let mut text = String::from("\n");
11524                    text.extend(buffer.text_for_range(range_to_move.clone()));
11525                    text.pop(); // Drop trailing newline
11526                    edits.push((
11527                        buffer.anchor_after(range_to_move.start)
11528                            ..buffer.anchor_before(range_to_move.end),
11529                        String::new(),
11530                    ));
11531                    let insertion_anchor = buffer.anchor_after(insertion_point);
11532                    edits.push((insertion_anchor..insertion_anchor, text));
11533
11534                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11535
11536                    // Move selections down
11537                    new_selections.extend(contiguous_row_selections.drain(..).map(
11538                        |mut selection| {
11539                            selection.start.row += row_delta;
11540                            selection.end.row += row_delta;
11541                            selection
11542                        },
11543                    ));
11544
11545                    // Move folds down
11546                    unfold_ranges.push(range_to_move.clone());
11547                    for fold in display_map.folds_in_range(
11548                        buffer.anchor_before(range_to_move.start)
11549                            ..buffer.anchor_after(range_to_move.end),
11550                    ) {
11551                        let mut start = fold.range.start.to_point(&buffer);
11552                        let mut end = fold.range.end.to_point(&buffer);
11553                        start.row += row_delta;
11554                        end.row += row_delta;
11555                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11556                    }
11557                }
11558            }
11559
11560            // If we didn't move line(s), preserve the existing selections
11561            new_selections.append(&mut contiguous_row_selections);
11562        }
11563
11564        self.transact(window, cx, |this, window, cx| {
11565            this.unfold_ranges(&unfold_ranges, true, true, cx);
11566            this.buffer.update(cx, |buffer, cx| {
11567                for (range, text) in edits {
11568                    buffer.edit([(range, text)], None, cx);
11569                }
11570            });
11571            this.fold_creases(refold_creases, true, window, cx);
11572            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11573        });
11574    }
11575
11576    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11577        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11578        let text_layout_details = &self.text_layout_details(window);
11579        self.transact(window, cx, |this, window, cx| {
11580            let edits = this.change_selections(Default::default(), window, cx, |s| {
11581                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11582                s.move_with(|display_map, selection| {
11583                    if !selection.is_empty() {
11584                        return;
11585                    }
11586
11587                    let mut head = selection.head();
11588                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11589                    if head.column() == display_map.line_len(head.row()) {
11590                        transpose_offset = display_map
11591                            .buffer_snapshot
11592                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11593                    }
11594
11595                    if transpose_offset == 0 {
11596                        return;
11597                    }
11598
11599                    *head.column_mut() += 1;
11600                    head = display_map.clip_point(head, Bias::Right);
11601                    let goal = SelectionGoal::HorizontalPosition(
11602                        display_map
11603                            .x_for_display_point(head, text_layout_details)
11604                            .into(),
11605                    );
11606                    selection.collapse_to(head, goal);
11607
11608                    let transpose_start = display_map
11609                        .buffer_snapshot
11610                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11611                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11612                        let transpose_end = display_map
11613                            .buffer_snapshot
11614                            .clip_offset(transpose_offset + 1, Bias::Right);
11615                        if let Some(ch) =
11616                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11617                        {
11618                            edits.push((transpose_start..transpose_offset, String::new()));
11619                            edits.push((transpose_end..transpose_end, ch.to_string()));
11620                        }
11621                    }
11622                });
11623                edits
11624            });
11625            this.buffer
11626                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11627            let selections = this.selections.all::<usize>(cx);
11628            this.change_selections(Default::default(), window, cx, |s| {
11629                s.select(selections);
11630            });
11631        });
11632    }
11633
11634    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11635        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11636        if self.mode.is_single_line() {
11637            cx.propagate();
11638            return;
11639        }
11640
11641        self.rewrap_impl(RewrapOptions::default(), cx)
11642    }
11643
11644    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11645        let buffer = self.buffer.read(cx).snapshot(cx);
11646        let selections = self.selections.all::<Point>(cx);
11647
11648        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11649        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11650            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11651                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11652                .peekable();
11653
11654            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11655                row
11656            } else {
11657                return Vec::new();
11658            };
11659
11660            let language_settings = buffer.language_settings_at(selection.head(), cx);
11661            let language_scope = buffer.language_scope_at(selection.head());
11662
11663            let indent_and_prefix_for_row =
11664                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11665                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11666                    let (comment_prefix, rewrap_prefix) =
11667                        if let Some(language_scope) = &language_scope {
11668                            let indent_end = Point::new(row, indent.len);
11669                            let comment_prefix = language_scope
11670                                .line_comment_prefixes()
11671                                .iter()
11672                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11673                                .map(|prefix| prefix.to_string());
11674                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11675                            let line_text_after_indent = buffer
11676                                .text_for_range(indent_end..line_end)
11677                                .collect::<String>();
11678                            let rewrap_prefix = language_scope
11679                                .rewrap_prefixes()
11680                                .iter()
11681                                .find_map(|prefix_regex| {
11682                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11683                                        if mat.start() == 0 {
11684                                            Some(mat.as_str().to_string())
11685                                        } else {
11686                                            None
11687                                        }
11688                                    })
11689                                })
11690                                .flatten();
11691                            (comment_prefix, rewrap_prefix)
11692                        } else {
11693                            (None, None)
11694                        };
11695                    (indent, comment_prefix, rewrap_prefix)
11696                };
11697
11698            let mut ranges = Vec::new();
11699            let from_empty_selection = selection.is_empty();
11700
11701            let mut current_range_start = first_row;
11702            let mut prev_row = first_row;
11703            let (
11704                mut current_range_indent,
11705                mut current_range_comment_prefix,
11706                mut current_range_rewrap_prefix,
11707            ) = indent_and_prefix_for_row(first_row);
11708
11709            for row in non_blank_rows_iter.skip(1) {
11710                let has_paragraph_break = row > prev_row + 1;
11711
11712                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11713                    indent_and_prefix_for_row(row);
11714
11715                let has_indent_change = row_indent != current_range_indent;
11716                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11717
11718                let has_boundary_change = has_comment_change
11719                    || row_rewrap_prefix.is_some()
11720                    || (has_indent_change && current_range_comment_prefix.is_some());
11721
11722                if has_paragraph_break || has_boundary_change {
11723                    ranges.push((
11724                        language_settings.clone(),
11725                        Point::new(current_range_start, 0)
11726                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11727                        current_range_indent,
11728                        current_range_comment_prefix.clone(),
11729                        current_range_rewrap_prefix.clone(),
11730                        from_empty_selection,
11731                    ));
11732                    current_range_start = row;
11733                    current_range_indent = row_indent;
11734                    current_range_comment_prefix = row_comment_prefix;
11735                    current_range_rewrap_prefix = row_rewrap_prefix;
11736                }
11737                prev_row = row;
11738            }
11739
11740            ranges.push((
11741                language_settings.clone(),
11742                Point::new(current_range_start, 0)
11743                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11744                current_range_indent,
11745                current_range_comment_prefix,
11746                current_range_rewrap_prefix,
11747                from_empty_selection,
11748            ));
11749
11750            ranges
11751        });
11752
11753        let mut edits = Vec::new();
11754        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11755
11756        for (
11757            language_settings,
11758            wrap_range,
11759            indent_size,
11760            comment_prefix,
11761            rewrap_prefix,
11762            from_empty_selection,
11763        ) in wrap_ranges
11764        {
11765            let mut start_row = wrap_range.start.row;
11766            let mut end_row = wrap_range.end.row;
11767
11768            // Skip selections that overlap with a range that has already been rewrapped.
11769            let selection_range = start_row..end_row;
11770            if rewrapped_row_ranges
11771                .iter()
11772                .any(|range| range.overlaps(&selection_range))
11773            {
11774                continue;
11775            }
11776
11777            let tab_size = language_settings.tab_size;
11778
11779            let indent_prefix = indent_size.chars().collect::<String>();
11780            let mut line_prefix = indent_prefix.clone();
11781            let mut inside_comment = false;
11782            if let Some(prefix) = &comment_prefix {
11783                line_prefix.push_str(prefix);
11784                inside_comment = true;
11785            }
11786            if let Some(prefix) = &rewrap_prefix {
11787                line_prefix.push_str(prefix);
11788            }
11789
11790            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11791                RewrapBehavior::InComments => inside_comment,
11792                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11793                RewrapBehavior::Anywhere => true,
11794            };
11795
11796            let should_rewrap = options.override_language_settings
11797                || allow_rewrap_based_on_language
11798                || self.hard_wrap.is_some();
11799            if !should_rewrap {
11800                continue;
11801            }
11802
11803            if from_empty_selection {
11804                'expand_upwards: while start_row > 0 {
11805                    let prev_row = start_row - 1;
11806                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11807                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11808                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11809                    {
11810                        start_row = prev_row;
11811                    } else {
11812                        break 'expand_upwards;
11813                    }
11814                }
11815
11816                'expand_downwards: while end_row < buffer.max_point().row {
11817                    let next_row = end_row + 1;
11818                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11819                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11820                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11821                    {
11822                        end_row = next_row;
11823                    } else {
11824                        break 'expand_downwards;
11825                    }
11826                }
11827            }
11828
11829            let start = Point::new(start_row, 0);
11830            let start_offset = start.to_offset(&buffer);
11831            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11832            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11833            let Some(lines_without_prefixes) = selection_text
11834                .lines()
11835                .enumerate()
11836                .map(|(ix, line)| {
11837                    let line_trimmed = line.trim_start();
11838                    if rewrap_prefix.is_some() && ix > 0 {
11839                        Ok(line_trimmed)
11840                    } else {
11841                        line_trimmed
11842                            .strip_prefix(&line_prefix.trim_start())
11843                            .with_context(|| {
11844                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11845                            })
11846                    }
11847                })
11848                .collect::<Result<Vec<_>, _>>()
11849                .log_err()
11850            else {
11851                continue;
11852            };
11853
11854            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11855                buffer
11856                    .language_settings_at(Point::new(start_row, 0), cx)
11857                    .preferred_line_length as usize
11858            });
11859
11860            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11861                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11862            } else {
11863                line_prefix.clone()
11864            };
11865
11866            let wrapped_text = wrap_with_prefix(
11867                line_prefix,
11868                subsequent_lines_prefix,
11869                lines_without_prefixes.join("\n"),
11870                wrap_column,
11871                tab_size,
11872                options.preserve_existing_whitespace,
11873            );
11874
11875            // TODO: should always use char-based diff while still supporting cursor behavior that
11876            // matches vim.
11877            let mut diff_options = DiffOptions::default();
11878            if options.override_language_settings {
11879                diff_options.max_word_diff_len = 0;
11880                diff_options.max_word_diff_line_count = 0;
11881            } else {
11882                diff_options.max_word_diff_len = usize::MAX;
11883                diff_options.max_word_diff_line_count = usize::MAX;
11884            }
11885
11886            for (old_range, new_text) in
11887                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11888            {
11889                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11890                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11891                edits.push((edit_start..edit_end, new_text));
11892            }
11893
11894            rewrapped_row_ranges.push(start_row..=end_row);
11895        }
11896
11897        self.buffer
11898            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11899    }
11900
11901    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11902        let mut text = String::new();
11903        let buffer = self.buffer.read(cx).snapshot(cx);
11904        let mut selections = self.selections.all::<Point>(cx);
11905        let mut clipboard_selections = Vec::with_capacity(selections.len());
11906        {
11907            let max_point = buffer.max_point();
11908            let mut is_first = true;
11909            for selection in &mut selections {
11910                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11911                if is_entire_line {
11912                    selection.start = Point::new(selection.start.row, 0);
11913                    if !selection.is_empty() && selection.end.column == 0 {
11914                        selection.end = cmp::min(max_point, selection.end);
11915                    } else {
11916                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11917                    }
11918                    selection.goal = SelectionGoal::None;
11919                }
11920                if is_first {
11921                    is_first = false;
11922                } else {
11923                    text += "\n";
11924                }
11925                let mut len = 0;
11926                for chunk in buffer.text_for_range(selection.start..selection.end) {
11927                    text.push_str(chunk);
11928                    len += chunk.len();
11929                }
11930                clipboard_selections.push(ClipboardSelection {
11931                    len,
11932                    is_entire_line,
11933                    first_line_indent: buffer
11934                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11935                        .len,
11936                });
11937            }
11938        }
11939
11940        self.transact(window, cx, |this, window, cx| {
11941            this.change_selections(Default::default(), window, cx, |s| {
11942                s.select(selections);
11943            });
11944            this.insert("", window, cx);
11945        });
11946        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11947    }
11948
11949    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11950        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11951        let item = self.cut_common(window, cx);
11952        cx.write_to_clipboard(item);
11953    }
11954
11955    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11956        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11957        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11958            s.move_with(|snapshot, sel| {
11959                if sel.is_empty() {
11960                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11961                }
11962            });
11963        });
11964        let item = self.cut_common(window, cx);
11965        cx.set_global(KillRing(item))
11966    }
11967
11968    pub fn kill_ring_yank(
11969        &mut self,
11970        _: &KillRingYank,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11975        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11976            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11977                (kill_ring.text().to_string(), kill_ring.metadata_json())
11978            } else {
11979                return;
11980            }
11981        } else {
11982            return;
11983        };
11984        self.do_paste(&text, metadata, false, window, cx);
11985    }
11986
11987    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11988        self.do_copy(true, cx);
11989    }
11990
11991    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11992        self.do_copy(false, cx);
11993    }
11994
11995    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11996        let selections = self.selections.all::<Point>(cx);
11997        let buffer = self.buffer.read(cx).read(cx);
11998        let mut text = String::new();
11999
12000        let mut clipboard_selections = Vec::with_capacity(selections.len());
12001        {
12002            let max_point = buffer.max_point();
12003            let mut is_first = true;
12004            for selection in &selections {
12005                let mut start = selection.start;
12006                let mut end = selection.end;
12007                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12008                if is_entire_line {
12009                    start = Point::new(start.row, 0);
12010                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12011                }
12012
12013                let mut trimmed_selections = Vec::new();
12014                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12015                    let row = MultiBufferRow(start.row);
12016                    let first_indent = buffer.indent_size_for_line(row);
12017                    if first_indent.len == 0 || start.column > first_indent.len {
12018                        trimmed_selections.push(start..end);
12019                    } else {
12020                        trimmed_selections.push(
12021                            Point::new(row.0, first_indent.len)
12022                                ..Point::new(row.0, buffer.line_len(row)),
12023                        );
12024                        for row in start.row + 1..=end.row {
12025                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12026                            if row == end.row {
12027                                line_len = end.column;
12028                            }
12029                            if line_len == 0 {
12030                                trimmed_selections
12031                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12032                                continue;
12033                            }
12034                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12035                            if row_indent_size.len >= first_indent.len {
12036                                trimmed_selections.push(
12037                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12038                                );
12039                            } else {
12040                                trimmed_selections.clear();
12041                                trimmed_selections.push(start..end);
12042                                break;
12043                            }
12044                        }
12045                    }
12046                } else {
12047                    trimmed_selections.push(start..end);
12048                }
12049
12050                for trimmed_range in trimmed_selections {
12051                    if is_first {
12052                        is_first = false;
12053                    } else {
12054                        text += "\n";
12055                    }
12056                    let mut len = 0;
12057                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12058                        text.push_str(chunk);
12059                        len += chunk.len();
12060                    }
12061                    clipboard_selections.push(ClipboardSelection {
12062                        len,
12063                        is_entire_line,
12064                        first_line_indent: buffer
12065                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12066                            .len,
12067                    });
12068                }
12069            }
12070        }
12071
12072        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12073            text,
12074            clipboard_selections,
12075        ));
12076    }
12077
12078    pub fn do_paste(
12079        &mut self,
12080        text: &String,
12081        clipboard_selections: Option<Vec<ClipboardSelection>>,
12082        handle_entire_lines: bool,
12083        window: &mut Window,
12084        cx: &mut Context<Self>,
12085    ) {
12086        if self.read_only(cx) {
12087            return;
12088        }
12089
12090        let clipboard_text = Cow::Borrowed(text);
12091
12092        self.transact(window, cx, |this, window, cx| {
12093            if let Some(mut clipboard_selections) = clipboard_selections {
12094                let old_selections = this.selections.all::<usize>(cx);
12095                let all_selections_were_entire_line =
12096                    clipboard_selections.iter().all(|s| s.is_entire_line);
12097                let first_selection_indent_column =
12098                    clipboard_selections.first().map(|s| s.first_line_indent);
12099                if clipboard_selections.len() != old_selections.len() {
12100                    clipboard_selections.drain(..);
12101                }
12102                let cursor_offset = this.selections.last::<usize>(cx).head();
12103                let mut auto_indent_on_paste = true;
12104
12105                this.buffer.update(cx, |buffer, cx| {
12106                    let snapshot = buffer.read(cx);
12107                    auto_indent_on_paste = snapshot
12108                        .language_settings_at(cursor_offset, cx)
12109                        .auto_indent_on_paste;
12110
12111                    let mut start_offset = 0;
12112                    let mut edits = Vec::new();
12113                    let mut original_indent_columns = Vec::new();
12114                    for (ix, selection) in old_selections.iter().enumerate() {
12115                        let to_insert;
12116                        let entire_line;
12117                        let original_indent_column;
12118                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12119                            let end_offset = start_offset + clipboard_selection.len;
12120                            to_insert = &clipboard_text[start_offset..end_offset];
12121                            entire_line = clipboard_selection.is_entire_line;
12122                            start_offset = end_offset + 1;
12123                            original_indent_column = Some(clipboard_selection.first_line_indent);
12124                        } else {
12125                            to_insert = clipboard_text.as_str();
12126                            entire_line = all_selections_were_entire_line;
12127                            original_indent_column = first_selection_indent_column
12128                        }
12129
12130                        // If the corresponding selection was empty when this slice of the
12131                        // clipboard text was written, then the entire line containing the
12132                        // selection was copied. If this selection is also currently empty,
12133                        // then paste the line before the current line of the buffer.
12134                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12135                            let column = selection.start.to_point(&snapshot).column as usize;
12136                            let line_start = selection.start - column;
12137                            line_start..line_start
12138                        } else {
12139                            selection.range()
12140                        };
12141
12142                        edits.push((range, to_insert));
12143                        original_indent_columns.push(original_indent_column);
12144                    }
12145                    drop(snapshot);
12146
12147                    buffer.edit(
12148                        edits,
12149                        if auto_indent_on_paste {
12150                            Some(AutoindentMode::Block {
12151                                original_indent_columns,
12152                            })
12153                        } else {
12154                            None
12155                        },
12156                        cx,
12157                    );
12158                });
12159
12160                let selections = this.selections.all::<usize>(cx);
12161                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12162            } else {
12163                this.insert(&clipboard_text, window, cx);
12164            }
12165        });
12166    }
12167
12168    pub fn diff_clipboard_with_selection(
12169        &mut self,
12170        _: &DiffClipboardWithSelection,
12171        window: &mut Window,
12172        cx: &mut Context<Self>,
12173    ) {
12174        let selections = self.selections.all::<usize>(cx);
12175
12176        if selections.is_empty() {
12177            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12178            return;
12179        };
12180
12181        let clipboard_text = match cx.read_from_clipboard() {
12182            Some(item) => match item.entries().first() {
12183                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12184                _ => None,
12185            },
12186            None => None,
12187        };
12188
12189        let Some(clipboard_text) = clipboard_text else {
12190            log::warn!("Clipboard doesn't contain text.");
12191            return;
12192        };
12193
12194        window.dispatch_action(
12195            Box::new(DiffClipboardWithSelectionData {
12196                clipboard_text,
12197                editor: cx.entity(),
12198            }),
12199            cx,
12200        );
12201    }
12202
12203    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12204        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12205        if let Some(item) = cx.read_from_clipboard() {
12206            let entries = item.entries();
12207
12208            match entries.first() {
12209                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12210                // of all the pasted entries.
12211                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12212                    .do_paste(
12213                        clipboard_string.text(),
12214                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12215                        true,
12216                        window,
12217                        cx,
12218                    ),
12219                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12220            }
12221        }
12222    }
12223
12224    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12225        if self.read_only(cx) {
12226            return;
12227        }
12228
12229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12230
12231        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12232            if let Some((selections, _)) =
12233                self.selection_history.transaction(transaction_id).cloned()
12234            {
12235                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12236                    s.select_anchors(selections.to_vec());
12237                });
12238            } else {
12239                log::error!(
12240                    "No entry in selection_history found for undo. \
12241                     This may correspond to a bug where undo does not update the selection. \
12242                     If this is occurring, please add details to \
12243                     https://github.com/zed-industries/zed/issues/22692"
12244                );
12245            }
12246            self.request_autoscroll(Autoscroll::fit(), cx);
12247            self.unmark_text(window, cx);
12248            self.refresh_inline_completion(true, false, window, cx);
12249            cx.emit(EditorEvent::Edited { transaction_id });
12250            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12251        }
12252    }
12253
12254    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12255        if self.read_only(cx) {
12256            return;
12257        }
12258
12259        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12260
12261        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12262            if let Some((_, Some(selections))) =
12263                self.selection_history.transaction(transaction_id).cloned()
12264            {
12265                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12266                    s.select_anchors(selections.to_vec());
12267                });
12268            } else {
12269                log::error!(
12270                    "No entry in selection_history found for redo. \
12271                     This may correspond to a bug where undo does not update the selection. \
12272                     If this is occurring, please add details to \
12273                     https://github.com/zed-industries/zed/issues/22692"
12274                );
12275            }
12276            self.request_autoscroll(Autoscroll::fit(), cx);
12277            self.unmark_text(window, cx);
12278            self.refresh_inline_completion(true, false, window, cx);
12279            cx.emit(EditorEvent::Edited { transaction_id });
12280        }
12281    }
12282
12283    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12284        self.buffer
12285            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12286    }
12287
12288    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12289        self.buffer
12290            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12291    }
12292
12293    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12295        self.change_selections(Default::default(), window, cx, |s| {
12296            s.move_with(|map, selection| {
12297                let cursor = if selection.is_empty() {
12298                    movement::left(map, selection.start)
12299                } else {
12300                    selection.start
12301                };
12302                selection.collapse_to(cursor, SelectionGoal::None);
12303            });
12304        })
12305    }
12306
12307    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12309        self.change_selections(Default::default(), window, cx, |s| {
12310            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12311        })
12312    }
12313
12314    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12316        self.change_selections(Default::default(), window, cx, |s| {
12317            s.move_with(|map, selection| {
12318                let cursor = if selection.is_empty() {
12319                    movement::right(map, selection.end)
12320                } else {
12321                    selection.end
12322                };
12323                selection.collapse_to(cursor, SelectionGoal::None)
12324            });
12325        })
12326    }
12327
12328    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12330        self.change_selections(Default::default(), window, cx, |s| {
12331            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12332        })
12333    }
12334
12335    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12336        if self.take_rename(true, window, cx).is_some() {
12337            return;
12338        }
12339
12340        if self.mode.is_single_line() {
12341            cx.propagate();
12342            return;
12343        }
12344
12345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12346
12347        let text_layout_details = &self.text_layout_details(window);
12348        let selection_count = self.selections.count();
12349        let first_selection = self.selections.first_anchor();
12350
12351        self.change_selections(Default::default(), window, cx, |s| {
12352            s.move_with(|map, selection| {
12353                if !selection.is_empty() {
12354                    selection.goal = SelectionGoal::None;
12355                }
12356                let (cursor, goal) = movement::up(
12357                    map,
12358                    selection.start,
12359                    selection.goal,
12360                    false,
12361                    text_layout_details,
12362                );
12363                selection.collapse_to(cursor, goal);
12364            });
12365        });
12366
12367        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12368        {
12369            cx.propagate();
12370        }
12371    }
12372
12373    pub fn move_up_by_lines(
12374        &mut self,
12375        action: &MoveUpByLines,
12376        window: &mut Window,
12377        cx: &mut Context<Self>,
12378    ) {
12379        if self.take_rename(true, window, cx).is_some() {
12380            return;
12381        }
12382
12383        if self.mode.is_single_line() {
12384            cx.propagate();
12385            return;
12386        }
12387
12388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12389
12390        let text_layout_details = &self.text_layout_details(window);
12391
12392        self.change_selections(Default::default(), window, cx, |s| {
12393            s.move_with(|map, selection| {
12394                if !selection.is_empty() {
12395                    selection.goal = SelectionGoal::None;
12396                }
12397                let (cursor, goal) = movement::up_by_rows(
12398                    map,
12399                    selection.start,
12400                    action.lines,
12401                    selection.goal,
12402                    false,
12403                    text_layout_details,
12404                );
12405                selection.collapse_to(cursor, goal);
12406            });
12407        })
12408    }
12409
12410    pub fn move_down_by_lines(
12411        &mut self,
12412        action: &MoveDownByLines,
12413        window: &mut Window,
12414        cx: &mut Context<Self>,
12415    ) {
12416        if self.take_rename(true, window, cx).is_some() {
12417            return;
12418        }
12419
12420        if self.mode.is_single_line() {
12421            cx.propagate();
12422            return;
12423        }
12424
12425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12426
12427        let text_layout_details = &self.text_layout_details(window);
12428
12429        self.change_selections(Default::default(), window, cx, |s| {
12430            s.move_with(|map, selection| {
12431                if !selection.is_empty() {
12432                    selection.goal = SelectionGoal::None;
12433                }
12434                let (cursor, goal) = movement::down_by_rows(
12435                    map,
12436                    selection.start,
12437                    action.lines,
12438                    selection.goal,
12439                    false,
12440                    text_layout_details,
12441                );
12442                selection.collapse_to(cursor, goal);
12443            });
12444        })
12445    }
12446
12447    pub fn select_down_by_lines(
12448        &mut self,
12449        action: &SelectDownByLines,
12450        window: &mut Window,
12451        cx: &mut Context<Self>,
12452    ) {
12453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12454        let text_layout_details = &self.text_layout_details(window);
12455        self.change_selections(Default::default(), window, cx, |s| {
12456            s.move_heads_with(|map, head, goal| {
12457                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12458            })
12459        })
12460    }
12461
12462    pub fn select_up_by_lines(
12463        &mut self,
12464        action: &SelectUpByLines,
12465        window: &mut Window,
12466        cx: &mut Context<Self>,
12467    ) {
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12469        let text_layout_details = &self.text_layout_details(window);
12470        self.change_selections(Default::default(), window, cx, |s| {
12471            s.move_heads_with(|map, head, goal| {
12472                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12473            })
12474        })
12475    }
12476
12477    pub fn select_page_up(
12478        &mut self,
12479        _: &SelectPageUp,
12480        window: &mut Window,
12481        cx: &mut Context<Self>,
12482    ) {
12483        let Some(row_count) = self.visible_row_count() else {
12484            return;
12485        };
12486
12487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12488
12489        let text_layout_details = &self.text_layout_details(window);
12490
12491        self.change_selections(Default::default(), window, cx, |s| {
12492            s.move_heads_with(|map, head, goal| {
12493                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12494            })
12495        })
12496    }
12497
12498    pub fn move_page_up(
12499        &mut self,
12500        action: &MovePageUp,
12501        window: &mut Window,
12502        cx: &mut Context<Self>,
12503    ) {
12504        if self.take_rename(true, window, cx).is_some() {
12505            return;
12506        }
12507
12508        if self
12509            .context_menu
12510            .borrow_mut()
12511            .as_mut()
12512            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12513            .unwrap_or(false)
12514        {
12515            return;
12516        }
12517
12518        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12519            cx.propagate();
12520            return;
12521        }
12522
12523        let Some(row_count) = self.visible_row_count() else {
12524            return;
12525        };
12526
12527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12528
12529        let effects = if action.center_cursor {
12530            SelectionEffects::scroll(Autoscroll::center())
12531        } else {
12532            SelectionEffects::default()
12533        };
12534
12535        let text_layout_details = &self.text_layout_details(window);
12536
12537        self.change_selections(effects, window, cx, |s| {
12538            s.move_with(|map, selection| {
12539                if !selection.is_empty() {
12540                    selection.goal = SelectionGoal::None;
12541                }
12542                let (cursor, goal) = movement::up_by_rows(
12543                    map,
12544                    selection.end,
12545                    row_count,
12546                    selection.goal,
12547                    false,
12548                    text_layout_details,
12549                );
12550                selection.collapse_to(cursor, goal);
12551            });
12552        });
12553    }
12554
12555    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12557        let text_layout_details = &self.text_layout_details(window);
12558        self.change_selections(Default::default(), window, cx, |s| {
12559            s.move_heads_with(|map, head, goal| {
12560                movement::up(map, head, goal, false, text_layout_details)
12561            })
12562        })
12563    }
12564
12565    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12566        self.take_rename(true, window, cx);
12567
12568        if self.mode.is_single_line() {
12569            cx.propagate();
12570            return;
12571        }
12572
12573        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12574
12575        let text_layout_details = &self.text_layout_details(window);
12576        let selection_count = self.selections.count();
12577        let first_selection = self.selections.first_anchor();
12578
12579        self.change_selections(Default::default(), window, cx, |s| {
12580            s.move_with(|map, selection| {
12581                if !selection.is_empty() {
12582                    selection.goal = SelectionGoal::None;
12583                }
12584                let (cursor, goal) = movement::down(
12585                    map,
12586                    selection.end,
12587                    selection.goal,
12588                    false,
12589                    text_layout_details,
12590                );
12591                selection.collapse_to(cursor, goal);
12592            });
12593        });
12594
12595        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12596        {
12597            cx.propagate();
12598        }
12599    }
12600
12601    pub fn select_page_down(
12602        &mut self,
12603        _: &SelectPageDown,
12604        window: &mut Window,
12605        cx: &mut Context<Self>,
12606    ) {
12607        let Some(row_count) = self.visible_row_count() else {
12608            return;
12609        };
12610
12611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12612
12613        let text_layout_details = &self.text_layout_details(window);
12614
12615        self.change_selections(Default::default(), window, cx, |s| {
12616            s.move_heads_with(|map, head, goal| {
12617                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12618            })
12619        })
12620    }
12621
12622    pub fn move_page_down(
12623        &mut self,
12624        action: &MovePageDown,
12625        window: &mut Window,
12626        cx: &mut Context<Self>,
12627    ) {
12628        if self.take_rename(true, window, cx).is_some() {
12629            return;
12630        }
12631
12632        if self
12633            .context_menu
12634            .borrow_mut()
12635            .as_mut()
12636            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12637            .unwrap_or(false)
12638        {
12639            return;
12640        }
12641
12642        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12643            cx.propagate();
12644            return;
12645        }
12646
12647        let Some(row_count) = self.visible_row_count() else {
12648            return;
12649        };
12650
12651        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12652
12653        let effects = if action.center_cursor {
12654            SelectionEffects::scroll(Autoscroll::center())
12655        } else {
12656            SelectionEffects::default()
12657        };
12658
12659        let text_layout_details = &self.text_layout_details(window);
12660        self.change_selections(effects, window, cx, |s| {
12661            s.move_with(|map, selection| {
12662                if !selection.is_empty() {
12663                    selection.goal = SelectionGoal::None;
12664                }
12665                let (cursor, goal) = movement::down_by_rows(
12666                    map,
12667                    selection.end,
12668                    row_count,
12669                    selection.goal,
12670                    false,
12671                    text_layout_details,
12672                );
12673                selection.collapse_to(cursor, goal);
12674            });
12675        });
12676    }
12677
12678    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12680        let text_layout_details = &self.text_layout_details(window);
12681        self.change_selections(Default::default(), window, cx, |s| {
12682            s.move_heads_with(|map, head, goal| {
12683                movement::down(map, head, goal, false, text_layout_details)
12684            })
12685        });
12686    }
12687
12688    pub fn context_menu_first(
12689        &mut self,
12690        _: &ContextMenuFirst,
12691        window: &mut Window,
12692        cx: &mut Context<Self>,
12693    ) {
12694        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12695            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12696        }
12697    }
12698
12699    pub fn context_menu_prev(
12700        &mut self,
12701        _: &ContextMenuPrevious,
12702        window: &mut Window,
12703        cx: &mut Context<Self>,
12704    ) {
12705        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12706            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12707        }
12708    }
12709
12710    pub fn context_menu_next(
12711        &mut self,
12712        _: &ContextMenuNext,
12713        window: &mut Window,
12714        cx: &mut Context<Self>,
12715    ) {
12716        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12717            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12718        }
12719    }
12720
12721    pub fn context_menu_last(
12722        &mut self,
12723        _: &ContextMenuLast,
12724        window: &mut Window,
12725        cx: &mut Context<Self>,
12726    ) {
12727        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12728            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12729        }
12730    }
12731
12732    pub fn signature_help_prev(
12733        &mut self,
12734        _: &SignatureHelpPrevious,
12735        _: &mut Window,
12736        cx: &mut Context<Self>,
12737    ) {
12738        if let Some(popover) = self.signature_help_state.popover_mut() {
12739            if popover.current_signature == 0 {
12740                popover.current_signature = popover.signatures.len() - 1;
12741            } else {
12742                popover.current_signature -= 1;
12743            }
12744            cx.notify();
12745        }
12746    }
12747
12748    pub fn signature_help_next(
12749        &mut self,
12750        _: &SignatureHelpNext,
12751        _: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        if let Some(popover) = self.signature_help_state.popover_mut() {
12755            if popover.current_signature + 1 == popover.signatures.len() {
12756                popover.current_signature = 0;
12757            } else {
12758                popover.current_signature += 1;
12759            }
12760            cx.notify();
12761        }
12762    }
12763
12764    pub fn move_to_previous_word_start(
12765        &mut self,
12766        _: &MoveToPreviousWordStart,
12767        window: &mut Window,
12768        cx: &mut Context<Self>,
12769    ) {
12770        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12771        self.change_selections(Default::default(), window, cx, |s| {
12772            s.move_cursors_with(|map, head, _| {
12773                (
12774                    movement::previous_word_start(map, head),
12775                    SelectionGoal::None,
12776                )
12777            });
12778        })
12779    }
12780
12781    pub fn move_to_previous_subword_start(
12782        &mut self,
12783        _: &MoveToPreviousSubwordStart,
12784        window: &mut Window,
12785        cx: &mut Context<Self>,
12786    ) {
12787        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12788        self.change_selections(Default::default(), window, cx, |s| {
12789            s.move_cursors_with(|map, head, _| {
12790                (
12791                    movement::previous_subword_start(map, head),
12792                    SelectionGoal::None,
12793                )
12794            });
12795        })
12796    }
12797
12798    pub fn select_to_previous_word_start(
12799        &mut self,
12800        _: &SelectToPreviousWordStart,
12801        window: &mut Window,
12802        cx: &mut Context<Self>,
12803    ) {
12804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12805        self.change_selections(Default::default(), window, cx, |s| {
12806            s.move_heads_with(|map, head, _| {
12807                (
12808                    movement::previous_word_start(map, head),
12809                    SelectionGoal::None,
12810                )
12811            });
12812        })
12813    }
12814
12815    pub fn select_to_previous_subword_start(
12816        &mut self,
12817        _: &SelectToPreviousSubwordStart,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12822        self.change_selections(Default::default(), window, cx, |s| {
12823            s.move_heads_with(|map, head, _| {
12824                (
12825                    movement::previous_subword_start(map, head),
12826                    SelectionGoal::None,
12827                )
12828            });
12829        })
12830    }
12831
12832    pub fn delete_to_previous_word_start(
12833        &mut self,
12834        action: &DeleteToPreviousWordStart,
12835        window: &mut Window,
12836        cx: &mut Context<Self>,
12837    ) {
12838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12839        self.transact(window, cx, |this, window, cx| {
12840            this.select_autoclose_pair(window, cx);
12841            this.change_selections(Default::default(), window, cx, |s| {
12842                s.move_with(|map, selection| {
12843                    if selection.is_empty() {
12844                        let cursor = if action.ignore_newlines {
12845                            movement::previous_word_start(map, selection.head())
12846                        } else {
12847                            movement::previous_word_start_or_newline(map, selection.head())
12848                        };
12849                        selection.set_head(cursor, SelectionGoal::None);
12850                    }
12851                });
12852            });
12853            this.insert("", window, cx);
12854        });
12855    }
12856
12857    pub fn delete_to_previous_subword_start(
12858        &mut self,
12859        _: &DeleteToPreviousSubwordStart,
12860        window: &mut Window,
12861        cx: &mut Context<Self>,
12862    ) {
12863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12864        self.transact(window, cx, |this, window, cx| {
12865            this.select_autoclose_pair(window, cx);
12866            this.change_selections(Default::default(), window, cx, |s| {
12867                s.move_with(|map, selection| {
12868                    if selection.is_empty() {
12869                        let cursor = movement::previous_subword_start(map, selection.head());
12870                        selection.set_head(cursor, SelectionGoal::None);
12871                    }
12872                });
12873            });
12874            this.insert("", window, cx);
12875        });
12876    }
12877
12878    pub fn move_to_next_word_end(
12879        &mut self,
12880        _: &MoveToNextWordEnd,
12881        window: &mut Window,
12882        cx: &mut Context<Self>,
12883    ) {
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12885        self.change_selections(Default::default(), window, cx, |s| {
12886            s.move_cursors_with(|map, head, _| {
12887                (movement::next_word_end(map, head), SelectionGoal::None)
12888            });
12889        })
12890    }
12891
12892    pub fn move_to_next_subword_end(
12893        &mut self,
12894        _: &MoveToNextSubwordEnd,
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                (movement::next_subword_end(map, head), SelectionGoal::None)
12902            });
12903        })
12904    }
12905
12906    pub fn select_to_next_word_end(
12907        &mut self,
12908        _: &SelectToNextWordEnd,
12909        window: &mut Window,
12910        cx: &mut Context<Self>,
12911    ) {
12912        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_heads_with(|map, head, _| {
12915                (movement::next_word_end(map, head), SelectionGoal::None)
12916            });
12917        })
12918    }
12919
12920    pub fn select_to_next_subword_end(
12921        &mut self,
12922        _: &SelectToNextSubwordEnd,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) {
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_heads_with(|map, head, _| {
12929                (movement::next_subword_end(map, head), SelectionGoal::None)
12930            });
12931        })
12932    }
12933
12934    pub fn delete_to_next_word_end(
12935        &mut self,
12936        action: &DeleteToNextWordEnd,
12937        window: &mut Window,
12938        cx: &mut Context<Self>,
12939    ) {
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12941        self.transact(window, cx, |this, window, cx| {
12942            this.change_selections(Default::default(), window, cx, |s| {
12943                s.move_with(|map, selection| {
12944                    if selection.is_empty() {
12945                        let cursor = if action.ignore_newlines {
12946                            movement::next_word_end(map, selection.head())
12947                        } else {
12948                            movement::next_word_end_or_newline(map, selection.head())
12949                        };
12950                        selection.set_head(cursor, SelectionGoal::None);
12951                    }
12952                });
12953            });
12954            this.insert("", window, cx);
12955        });
12956    }
12957
12958    pub fn delete_to_next_subword_end(
12959        &mut self,
12960        _: &DeleteToNextSubwordEnd,
12961        window: &mut Window,
12962        cx: &mut Context<Self>,
12963    ) {
12964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12965        self.transact(window, cx, |this, window, cx| {
12966            this.change_selections(Default::default(), window, cx, |s| {
12967                s.move_with(|map, selection| {
12968                    if selection.is_empty() {
12969                        let cursor = movement::next_subword_end(map, selection.head());
12970                        selection.set_head(cursor, SelectionGoal::None);
12971                    }
12972                });
12973            });
12974            this.insert("", window, cx);
12975        });
12976    }
12977
12978    pub fn move_to_beginning_of_line(
12979        &mut self,
12980        action: &MoveToBeginningOfLine,
12981        window: &mut Window,
12982        cx: &mut Context<Self>,
12983    ) {
12984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12985        self.change_selections(Default::default(), window, cx, |s| {
12986            s.move_cursors_with(|map, head, _| {
12987                (
12988                    movement::indented_line_beginning(
12989                        map,
12990                        head,
12991                        action.stop_at_soft_wraps,
12992                        action.stop_at_indent,
12993                    ),
12994                    SelectionGoal::None,
12995                )
12996            });
12997        })
12998    }
12999
13000    pub fn select_to_beginning_of_line(
13001        &mut self,
13002        action: &SelectToBeginningOfLine,
13003        window: &mut Window,
13004        cx: &mut Context<Self>,
13005    ) {
13006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_heads_with(|map, head, _| {
13009                (
13010                    movement::indented_line_beginning(
13011                        map,
13012                        head,
13013                        action.stop_at_soft_wraps,
13014                        action.stop_at_indent,
13015                    ),
13016                    SelectionGoal::None,
13017                )
13018            });
13019        });
13020    }
13021
13022    pub fn delete_to_beginning_of_line(
13023        &mut self,
13024        action: &DeleteToBeginningOfLine,
13025        window: &mut Window,
13026        cx: &mut Context<Self>,
13027    ) {
13028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13029        self.transact(window, cx, |this, window, cx| {
13030            this.change_selections(Default::default(), window, cx, |s| {
13031                s.move_with(|_, selection| {
13032                    selection.reversed = true;
13033                });
13034            });
13035
13036            this.select_to_beginning_of_line(
13037                &SelectToBeginningOfLine {
13038                    stop_at_soft_wraps: false,
13039                    stop_at_indent: action.stop_at_indent,
13040                },
13041                window,
13042                cx,
13043            );
13044            this.backspace(&Backspace, window, cx);
13045        });
13046    }
13047
13048    pub fn move_to_end_of_line(
13049        &mut self,
13050        action: &MoveToEndOfLine,
13051        window: &mut Window,
13052        cx: &mut Context<Self>,
13053    ) {
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13055        self.change_selections(Default::default(), window, cx, |s| {
13056            s.move_cursors_with(|map, head, _| {
13057                (
13058                    movement::line_end(map, head, action.stop_at_soft_wraps),
13059                    SelectionGoal::None,
13060                )
13061            });
13062        })
13063    }
13064
13065    pub fn select_to_end_of_line(
13066        &mut self,
13067        action: &SelectToEndOfLine,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13072        self.change_selections(Default::default(), window, cx, |s| {
13073            s.move_heads_with(|map, head, _| {
13074                (
13075                    movement::line_end(map, head, action.stop_at_soft_wraps),
13076                    SelectionGoal::None,
13077                )
13078            });
13079        })
13080    }
13081
13082    pub fn delete_to_end_of_line(
13083        &mut self,
13084        _: &DeleteToEndOfLine,
13085        window: &mut Window,
13086        cx: &mut Context<Self>,
13087    ) {
13088        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13089        self.transact(window, cx, |this, window, cx| {
13090            this.select_to_end_of_line(
13091                &SelectToEndOfLine {
13092                    stop_at_soft_wraps: false,
13093                },
13094                window,
13095                cx,
13096            );
13097            this.delete(&Delete, window, cx);
13098        });
13099    }
13100
13101    pub fn cut_to_end_of_line(
13102        &mut self,
13103        _: &CutToEndOfLine,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13108        self.transact(window, cx, |this, window, cx| {
13109            this.select_to_end_of_line(
13110                &SelectToEndOfLine {
13111                    stop_at_soft_wraps: false,
13112                },
13113                window,
13114                cx,
13115            );
13116            this.cut(&Cut, window, cx);
13117        });
13118    }
13119
13120    pub fn move_to_start_of_paragraph(
13121        &mut self,
13122        _: &MoveToStartOfParagraph,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13127            cx.propagate();
13128            return;
13129        }
13130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13131        self.change_selections(Default::default(), window, cx, |s| {
13132            s.move_with(|map, selection| {
13133                selection.collapse_to(
13134                    movement::start_of_paragraph(map, selection.head(), 1),
13135                    SelectionGoal::None,
13136                )
13137            });
13138        })
13139    }
13140
13141    pub fn move_to_end_of_paragraph(
13142        &mut self,
13143        _: &MoveToEndOfParagraph,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) {
13147        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13148            cx.propagate();
13149            return;
13150        }
13151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13152        self.change_selections(Default::default(), window, cx, |s| {
13153            s.move_with(|map, selection| {
13154                selection.collapse_to(
13155                    movement::end_of_paragraph(map, selection.head(), 1),
13156                    SelectionGoal::None,
13157                )
13158            });
13159        })
13160    }
13161
13162    pub fn select_to_start_of_paragraph(
13163        &mut self,
13164        _: &SelectToStartOfParagraph,
13165        window: &mut Window,
13166        cx: &mut Context<Self>,
13167    ) {
13168        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13169            cx.propagate();
13170            return;
13171        }
13172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13173        self.change_selections(Default::default(), window, cx, |s| {
13174            s.move_heads_with(|map, head, _| {
13175                (
13176                    movement::start_of_paragraph(map, head, 1),
13177                    SelectionGoal::None,
13178                )
13179            });
13180        })
13181    }
13182
13183    pub fn select_to_end_of_paragraph(
13184        &mut self,
13185        _: &SelectToEndOfParagraph,
13186        window: &mut Window,
13187        cx: &mut Context<Self>,
13188    ) {
13189        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13190            cx.propagate();
13191            return;
13192        }
13193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13194        self.change_selections(Default::default(), window, cx, |s| {
13195            s.move_heads_with(|map, head, _| {
13196                (
13197                    movement::end_of_paragraph(map, head, 1),
13198                    SelectionGoal::None,
13199                )
13200            });
13201        })
13202    }
13203
13204    pub fn move_to_start_of_excerpt(
13205        &mut self,
13206        _: &MoveToStartOfExcerpt,
13207        window: &mut Window,
13208        cx: &mut Context<Self>,
13209    ) {
13210        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13211            cx.propagate();
13212            return;
13213        }
13214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13215        self.change_selections(Default::default(), window, cx, |s| {
13216            s.move_with(|map, selection| {
13217                selection.collapse_to(
13218                    movement::start_of_excerpt(
13219                        map,
13220                        selection.head(),
13221                        workspace::searchable::Direction::Prev,
13222                    ),
13223                    SelectionGoal::None,
13224                )
13225            });
13226        })
13227    }
13228
13229    pub fn move_to_start_of_next_excerpt(
13230        &mut self,
13231        _: &MoveToStartOfNextExcerpt,
13232        window: &mut Window,
13233        cx: &mut Context<Self>,
13234    ) {
13235        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13236            cx.propagate();
13237            return;
13238        }
13239
13240        self.change_selections(Default::default(), window, cx, |s| {
13241            s.move_with(|map, selection| {
13242                selection.collapse_to(
13243                    movement::start_of_excerpt(
13244                        map,
13245                        selection.head(),
13246                        workspace::searchable::Direction::Next,
13247                    ),
13248                    SelectionGoal::None,
13249                )
13250            });
13251        })
13252    }
13253
13254    pub fn move_to_end_of_excerpt(
13255        &mut self,
13256        _: &MoveToEndOfExcerpt,
13257        window: &mut Window,
13258        cx: &mut Context<Self>,
13259    ) {
13260        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13261            cx.propagate();
13262            return;
13263        }
13264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13265        self.change_selections(Default::default(), window, cx, |s| {
13266            s.move_with(|map, selection| {
13267                selection.collapse_to(
13268                    movement::end_of_excerpt(
13269                        map,
13270                        selection.head(),
13271                        workspace::searchable::Direction::Next,
13272                    ),
13273                    SelectionGoal::None,
13274                )
13275            });
13276        })
13277    }
13278
13279    pub fn move_to_end_of_previous_excerpt(
13280        &mut self,
13281        _: &MoveToEndOfPreviousExcerpt,
13282        window: &mut Window,
13283        cx: &mut Context<Self>,
13284    ) {
13285        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13286            cx.propagate();
13287            return;
13288        }
13289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13290        self.change_selections(Default::default(), window, cx, |s| {
13291            s.move_with(|map, selection| {
13292                selection.collapse_to(
13293                    movement::end_of_excerpt(
13294                        map,
13295                        selection.head(),
13296                        workspace::searchable::Direction::Prev,
13297                    ),
13298                    SelectionGoal::None,
13299                )
13300            });
13301        })
13302    }
13303
13304    pub fn select_to_start_of_excerpt(
13305        &mut self,
13306        _: &SelectToStartOfExcerpt,
13307        window: &mut Window,
13308        cx: &mut Context<Self>,
13309    ) {
13310        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13311            cx.propagate();
13312            return;
13313        }
13314        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13315        self.change_selections(Default::default(), window, cx, |s| {
13316            s.move_heads_with(|map, head, _| {
13317                (
13318                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13319                    SelectionGoal::None,
13320                )
13321            });
13322        })
13323    }
13324
13325    pub fn select_to_start_of_next_excerpt(
13326        &mut self,
13327        _: &SelectToStartOfNextExcerpt,
13328        window: &mut Window,
13329        cx: &mut Context<Self>,
13330    ) {
13331        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13332            cx.propagate();
13333            return;
13334        }
13335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_heads_with(|map, head, _| {
13338                (
13339                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13340                    SelectionGoal::None,
13341                )
13342            });
13343        })
13344    }
13345
13346    pub fn select_to_end_of_excerpt(
13347        &mut self,
13348        _: &SelectToEndOfExcerpt,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13353            cx.propagate();
13354            return;
13355        }
13356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13357        self.change_selections(Default::default(), window, cx, |s| {
13358            s.move_heads_with(|map, head, _| {
13359                (
13360                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13361                    SelectionGoal::None,
13362                )
13363            });
13364        })
13365    }
13366
13367    pub fn select_to_end_of_previous_excerpt(
13368        &mut self,
13369        _: &SelectToEndOfPreviousExcerpt,
13370        window: &mut Window,
13371        cx: &mut Context<Self>,
13372    ) {
13373        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13374            cx.propagate();
13375            return;
13376        }
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (
13381                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13382                    SelectionGoal::None,
13383                )
13384            });
13385        })
13386    }
13387
13388    pub fn move_to_beginning(
13389        &mut self,
13390        _: &MoveToBeginning,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13395            cx.propagate();
13396            return;
13397        }
13398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13399        self.change_selections(Default::default(), window, cx, |s| {
13400            s.select_ranges(vec![0..0]);
13401        });
13402    }
13403
13404    pub fn select_to_beginning(
13405        &mut self,
13406        _: &SelectToBeginning,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        let mut selection = self.selections.last::<Point>(cx);
13411        selection.set_head(Point::zero(), SelectionGoal::None);
13412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13413        self.change_selections(Default::default(), window, cx, |s| {
13414            s.select(vec![selection]);
13415        });
13416    }
13417
13418    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13419        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13420            cx.propagate();
13421            return;
13422        }
13423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13424        let cursor = self.buffer.read(cx).read(cx).len();
13425        self.change_selections(Default::default(), window, cx, |s| {
13426            s.select_ranges(vec![cursor..cursor])
13427        });
13428    }
13429
13430    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13431        self.nav_history = nav_history;
13432    }
13433
13434    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13435        self.nav_history.as_ref()
13436    }
13437
13438    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13439        self.push_to_nav_history(
13440            self.selections.newest_anchor().head(),
13441            None,
13442            false,
13443            true,
13444            cx,
13445        );
13446    }
13447
13448    fn push_to_nav_history(
13449        &mut self,
13450        cursor_anchor: Anchor,
13451        new_position: Option<Point>,
13452        is_deactivate: bool,
13453        always: bool,
13454        cx: &mut Context<Self>,
13455    ) {
13456        if let Some(nav_history) = self.nav_history.as_mut() {
13457            let buffer = self.buffer.read(cx).read(cx);
13458            let cursor_position = cursor_anchor.to_point(&buffer);
13459            let scroll_state = self.scroll_manager.anchor();
13460            let scroll_top_row = scroll_state.top_row(&buffer);
13461            drop(buffer);
13462
13463            if let Some(new_position) = new_position {
13464                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13465                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13466                    return;
13467                }
13468            }
13469
13470            nav_history.push(
13471                Some(NavigationData {
13472                    cursor_anchor,
13473                    cursor_position,
13474                    scroll_anchor: scroll_state,
13475                    scroll_top_row,
13476                }),
13477                cx,
13478            );
13479            cx.emit(EditorEvent::PushedToNavHistory {
13480                anchor: cursor_anchor,
13481                is_deactivate,
13482            })
13483        }
13484    }
13485
13486    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13488        let buffer = self.buffer.read(cx).snapshot(cx);
13489        let mut selection = self.selections.first::<usize>(cx);
13490        selection.set_head(buffer.len(), SelectionGoal::None);
13491        self.change_selections(Default::default(), window, cx, |s| {
13492            s.select(vec![selection]);
13493        });
13494    }
13495
13496    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13498        let end = self.buffer.read(cx).read(cx).len();
13499        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13500            s.select_ranges(vec![0..end]);
13501        });
13502    }
13503
13504    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13507        let mut selections = self.selections.all::<Point>(cx);
13508        let max_point = display_map.buffer_snapshot.max_point();
13509        for selection in &mut selections {
13510            let rows = selection.spanned_rows(true, &display_map);
13511            selection.start = Point::new(rows.start.0, 0);
13512            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13513            selection.reversed = false;
13514        }
13515        self.change_selections(Default::default(), window, cx, |s| {
13516            s.select(selections);
13517        });
13518    }
13519
13520    pub fn split_selection_into_lines(
13521        &mut self,
13522        _: &SplitSelectionIntoLines,
13523        window: &mut Window,
13524        cx: &mut Context<Self>,
13525    ) {
13526        let selections = self
13527            .selections
13528            .all::<Point>(cx)
13529            .into_iter()
13530            .map(|selection| selection.start..selection.end)
13531            .collect::<Vec<_>>();
13532        self.unfold_ranges(&selections, true, true, cx);
13533
13534        let mut new_selection_ranges = Vec::new();
13535        {
13536            let buffer = self.buffer.read(cx).read(cx);
13537            for selection in selections {
13538                for row in selection.start.row..selection.end.row {
13539                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13540                    new_selection_ranges.push(cursor..cursor);
13541                }
13542
13543                let is_multiline_selection = selection.start.row != selection.end.row;
13544                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13545                // so this action feels more ergonomic when paired with other selection operations
13546                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13547                if !should_skip_last {
13548                    new_selection_ranges.push(selection.end..selection.end);
13549                }
13550            }
13551        }
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.select_ranges(new_selection_ranges);
13554        });
13555    }
13556
13557    pub fn add_selection_above(
13558        &mut self,
13559        _: &AddSelectionAbove,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        self.add_selection(true, window, cx);
13564    }
13565
13566    pub fn add_selection_below(
13567        &mut self,
13568        _: &AddSelectionBelow,
13569        window: &mut Window,
13570        cx: &mut Context<Self>,
13571    ) {
13572        self.add_selection(false, window, cx);
13573    }
13574
13575    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13577
13578        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13579        let all_selections = self.selections.all::<Point>(cx);
13580        let text_layout_details = self.text_layout_details(window);
13581
13582        let (mut columnar_selections, new_selections_to_columnarize) = {
13583            if let Some(state) = self.add_selections_state.as_ref() {
13584                let columnar_selection_ids: HashSet<_> = state
13585                    .groups
13586                    .iter()
13587                    .flat_map(|group| group.stack.iter())
13588                    .copied()
13589                    .collect();
13590
13591                all_selections
13592                    .into_iter()
13593                    .partition(|s| columnar_selection_ids.contains(&s.id))
13594            } else {
13595                (Vec::new(), all_selections)
13596            }
13597        };
13598
13599        let mut state = self
13600            .add_selections_state
13601            .take()
13602            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13603
13604        for selection in new_selections_to_columnarize {
13605            let range = selection.display_range(&display_map).sorted();
13606            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13607            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13608            let positions = start_x.min(end_x)..start_x.max(end_x);
13609            let mut stack = Vec::new();
13610            for row in range.start.row().0..=range.end.row().0 {
13611                if let Some(selection) = self.selections.build_columnar_selection(
13612                    &display_map,
13613                    DisplayRow(row),
13614                    &positions,
13615                    selection.reversed,
13616                    &text_layout_details,
13617                ) {
13618                    stack.push(selection.id);
13619                    columnar_selections.push(selection);
13620                }
13621            }
13622            if !stack.is_empty() {
13623                if above {
13624                    stack.reverse();
13625                }
13626                state.groups.push(AddSelectionsGroup { above, stack });
13627            }
13628        }
13629
13630        let mut final_selections = Vec::new();
13631        let end_row = if above {
13632            DisplayRow(0)
13633        } else {
13634            display_map.max_point().row()
13635        };
13636
13637        let mut last_added_item_per_group = HashMap::default();
13638        for group in state.groups.iter_mut() {
13639            if let Some(last_id) = group.stack.last() {
13640                last_added_item_per_group.insert(*last_id, group);
13641            }
13642        }
13643
13644        for selection in columnar_selections {
13645            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13646                if above == group.above {
13647                    let range = selection.display_range(&display_map).sorted();
13648                    debug_assert_eq!(range.start.row(), range.end.row());
13649                    let mut row = range.start.row();
13650                    let positions =
13651                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13652                            px(start)..px(end)
13653                        } else {
13654                            let start_x =
13655                                display_map.x_for_display_point(range.start, &text_layout_details);
13656                            let end_x =
13657                                display_map.x_for_display_point(range.end, &text_layout_details);
13658                            start_x.min(end_x)..start_x.max(end_x)
13659                        };
13660
13661                    let mut maybe_new_selection = None;
13662                    while row != end_row {
13663                        if above {
13664                            row.0 -= 1;
13665                        } else {
13666                            row.0 += 1;
13667                        }
13668                        if let Some(new_selection) = self.selections.build_columnar_selection(
13669                            &display_map,
13670                            row,
13671                            &positions,
13672                            selection.reversed,
13673                            &text_layout_details,
13674                        ) {
13675                            maybe_new_selection = Some(new_selection);
13676                            break;
13677                        }
13678                    }
13679
13680                    if let Some(new_selection) = maybe_new_selection {
13681                        group.stack.push(new_selection.id);
13682                        if above {
13683                            final_selections.push(new_selection);
13684                            final_selections.push(selection);
13685                        } else {
13686                            final_selections.push(selection);
13687                            final_selections.push(new_selection);
13688                        }
13689                    } else {
13690                        final_selections.push(selection);
13691                    }
13692                } else {
13693                    group.stack.pop();
13694                }
13695            } else {
13696                final_selections.push(selection);
13697            }
13698        }
13699
13700        self.change_selections(Default::default(), window, cx, |s| {
13701            s.select(final_selections);
13702        });
13703
13704        let final_selection_ids: HashSet<_> = self
13705            .selections
13706            .all::<Point>(cx)
13707            .iter()
13708            .map(|s| s.id)
13709            .collect();
13710        state.groups.retain_mut(|group| {
13711            // selections might get merged above so we remove invalid items from stacks
13712            group.stack.retain(|id| final_selection_ids.contains(id));
13713
13714            // single selection in stack can be treated as initial state
13715            group.stack.len() > 1
13716        });
13717
13718        if !state.groups.is_empty() {
13719            self.add_selections_state = Some(state);
13720        }
13721    }
13722
13723    fn select_match_ranges(
13724        &mut self,
13725        range: Range<usize>,
13726        reversed: bool,
13727        replace_newest: bool,
13728        auto_scroll: Option<Autoscroll>,
13729        window: &mut Window,
13730        cx: &mut Context<Editor>,
13731    ) {
13732        self.unfold_ranges(
13733            std::slice::from_ref(&range),
13734            false,
13735            auto_scroll.is_some(),
13736            cx,
13737        );
13738        let effects = if let Some(scroll) = auto_scroll {
13739            SelectionEffects::scroll(scroll)
13740        } else {
13741            SelectionEffects::no_scroll()
13742        };
13743        self.change_selections(effects, window, cx, |s| {
13744            if replace_newest {
13745                s.delete(s.newest_anchor().id);
13746            }
13747            if reversed {
13748                s.insert_range(range.end..range.start);
13749            } else {
13750                s.insert_range(range);
13751            }
13752        });
13753    }
13754
13755    pub fn select_next_match_internal(
13756        &mut self,
13757        display_map: &DisplaySnapshot,
13758        replace_newest: bool,
13759        autoscroll: Option<Autoscroll>,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) -> Result<()> {
13763        let buffer = &display_map.buffer_snapshot;
13764        let mut selections = self.selections.all::<usize>(cx);
13765        if let Some(mut select_next_state) = self.select_next_state.take() {
13766            let query = &select_next_state.query;
13767            if !select_next_state.done {
13768                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13769                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13770                let mut next_selected_range = None;
13771
13772                let bytes_after_last_selection =
13773                    buffer.bytes_in_range(last_selection.end..buffer.len());
13774                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13775                let query_matches = query
13776                    .stream_find_iter(bytes_after_last_selection)
13777                    .map(|result| (last_selection.end, result))
13778                    .chain(
13779                        query
13780                            .stream_find_iter(bytes_before_first_selection)
13781                            .map(|result| (0, result)),
13782                    );
13783
13784                for (start_offset, query_match) in query_matches {
13785                    let query_match = query_match.unwrap(); // can only fail due to I/O
13786                    let offset_range =
13787                        start_offset + query_match.start()..start_offset + query_match.end();
13788
13789                    if !select_next_state.wordwise
13790                        || (!buffer.is_inside_word(offset_range.start, false)
13791                            && !buffer.is_inside_word(offset_range.end, false))
13792                    {
13793                        // TODO: This is n^2, because we might check all the selections
13794                        if !selections
13795                            .iter()
13796                            .any(|selection| selection.range().overlaps(&offset_range))
13797                        {
13798                            next_selected_range = Some(offset_range);
13799                            break;
13800                        }
13801                    }
13802                }
13803
13804                if let Some(next_selected_range) = next_selected_range {
13805                    self.select_match_ranges(
13806                        next_selected_range,
13807                        last_selection.reversed,
13808                        replace_newest,
13809                        autoscroll,
13810                        window,
13811                        cx,
13812                    );
13813                } else {
13814                    select_next_state.done = true;
13815                }
13816            }
13817
13818            self.select_next_state = Some(select_next_state);
13819        } else {
13820            let mut only_carets = true;
13821            let mut same_text_selected = true;
13822            let mut selected_text = None;
13823
13824            let mut selections_iter = selections.iter().peekable();
13825            while let Some(selection) = selections_iter.next() {
13826                if selection.start != selection.end {
13827                    only_carets = false;
13828                }
13829
13830                if same_text_selected {
13831                    if selected_text.is_none() {
13832                        selected_text =
13833                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13834                    }
13835
13836                    if let Some(next_selection) = selections_iter.peek() {
13837                        if next_selection.range().len() == selection.range().len() {
13838                            let next_selected_text = buffer
13839                                .text_for_range(next_selection.range())
13840                                .collect::<String>();
13841                            if Some(next_selected_text) != selected_text {
13842                                same_text_selected = false;
13843                                selected_text = None;
13844                            }
13845                        } else {
13846                            same_text_selected = false;
13847                            selected_text = None;
13848                        }
13849                    }
13850                }
13851            }
13852
13853            if only_carets {
13854                for selection in &mut selections {
13855                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13856                    selection.start = word_range.start;
13857                    selection.end = word_range.end;
13858                    selection.goal = SelectionGoal::None;
13859                    selection.reversed = false;
13860                    self.select_match_ranges(
13861                        selection.start..selection.end,
13862                        selection.reversed,
13863                        replace_newest,
13864                        autoscroll,
13865                        window,
13866                        cx,
13867                    );
13868                }
13869
13870                if selections.len() == 1 {
13871                    let selection = selections
13872                        .last()
13873                        .expect("ensured that there's only one selection");
13874                    let query = buffer
13875                        .text_for_range(selection.start..selection.end)
13876                        .collect::<String>();
13877                    let is_empty = query.is_empty();
13878                    let select_state = SelectNextState {
13879                        query: AhoCorasick::new(&[query])?,
13880                        wordwise: true,
13881                        done: is_empty,
13882                    };
13883                    self.select_next_state = Some(select_state);
13884                } else {
13885                    self.select_next_state = None;
13886                }
13887            } else if let Some(selected_text) = selected_text {
13888                self.select_next_state = Some(SelectNextState {
13889                    query: AhoCorasick::new(&[selected_text])?,
13890                    wordwise: false,
13891                    done: false,
13892                });
13893                self.select_next_match_internal(
13894                    display_map,
13895                    replace_newest,
13896                    autoscroll,
13897                    window,
13898                    cx,
13899                )?;
13900            }
13901        }
13902        Ok(())
13903    }
13904
13905    pub fn select_all_matches(
13906        &mut self,
13907        _action: &SelectAllMatches,
13908        window: &mut Window,
13909        cx: &mut Context<Self>,
13910    ) -> Result<()> {
13911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13912
13913        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13914
13915        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13916        let Some(select_next_state) = self.select_next_state.as_mut() else {
13917            return Ok(());
13918        };
13919        if select_next_state.done {
13920            return Ok(());
13921        }
13922
13923        let mut new_selections = Vec::new();
13924
13925        let reversed = self.selections.oldest::<usize>(cx).reversed;
13926        let buffer = &display_map.buffer_snapshot;
13927        let query_matches = select_next_state
13928            .query
13929            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13930
13931        for query_match in query_matches.into_iter() {
13932            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13933            let offset_range = if reversed {
13934                query_match.end()..query_match.start()
13935            } else {
13936                query_match.start()..query_match.end()
13937            };
13938
13939            if !select_next_state.wordwise
13940                || (!buffer.is_inside_word(offset_range.start, false)
13941                    && !buffer.is_inside_word(offset_range.end, false))
13942            {
13943                new_selections.push(offset_range.start..offset_range.end);
13944            }
13945        }
13946
13947        select_next_state.done = true;
13948
13949        if new_selections.is_empty() {
13950            log::error!("bug: new_selections is empty in select_all_matches");
13951            return Ok(());
13952        }
13953
13954        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13955        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
13956            selections.select_ranges(new_selections)
13957        });
13958
13959        Ok(())
13960    }
13961
13962    pub fn select_next(
13963        &mut self,
13964        action: &SelectNext,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) -> Result<()> {
13968        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13969        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13970        self.select_next_match_internal(
13971            &display_map,
13972            action.replace_newest,
13973            Some(Autoscroll::newest()),
13974            window,
13975            cx,
13976        )?;
13977        Ok(())
13978    }
13979
13980    pub fn select_previous(
13981        &mut self,
13982        action: &SelectPrevious,
13983        window: &mut Window,
13984        cx: &mut Context<Self>,
13985    ) -> Result<()> {
13986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13987        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13988        let buffer = &display_map.buffer_snapshot;
13989        let mut selections = self.selections.all::<usize>(cx);
13990        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13991            let query = &select_prev_state.query;
13992            if !select_prev_state.done {
13993                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13994                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13995                let mut next_selected_range = None;
13996                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13997                let bytes_before_last_selection =
13998                    buffer.reversed_bytes_in_range(0..last_selection.start);
13999                let bytes_after_first_selection =
14000                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14001                let query_matches = query
14002                    .stream_find_iter(bytes_before_last_selection)
14003                    .map(|result| (last_selection.start, result))
14004                    .chain(
14005                        query
14006                            .stream_find_iter(bytes_after_first_selection)
14007                            .map(|result| (buffer.len(), result)),
14008                    );
14009                for (end_offset, query_match) in query_matches {
14010                    let query_match = query_match.unwrap(); // can only fail due to I/O
14011                    let offset_range =
14012                        end_offset - query_match.end()..end_offset - query_match.start();
14013
14014                    if !select_prev_state.wordwise
14015                        || (!buffer.is_inside_word(offset_range.start, false)
14016                            && !buffer.is_inside_word(offset_range.end, false))
14017                    {
14018                        next_selected_range = Some(offset_range);
14019                        break;
14020                    }
14021                }
14022
14023                if let Some(next_selected_range) = next_selected_range {
14024                    self.select_match_ranges(
14025                        next_selected_range,
14026                        last_selection.reversed,
14027                        action.replace_newest,
14028                        Some(Autoscroll::newest()),
14029                        window,
14030                        cx,
14031                    );
14032                } else {
14033                    select_prev_state.done = true;
14034                }
14035            }
14036
14037            self.select_prev_state = Some(select_prev_state);
14038        } else {
14039            let mut only_carets = true;
14040            let mut same_text_selected = true;
14041            let mut selected_text = None;
14042
14043            let mut selections_iter = selections.iter().peekable();
14044            while let Some(selection) = selections_iter.next() {
14045                if selection.start != selection.end {
14046                    only_carets = false;
14047                }
14048
14049                if same_text_selected {
14050                    if selected_text.is_none() {
14051                        selected_text =
14052                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14053                    }
14054
14055                    if let Some(next_selection) = selections_iter.peek() {
14056                        if next_selection.range().len() == selection.range().len() {
14057                            let next_selected_text = buffer
14058                                .text_for_range(next_selection.range())
14059                                .collect::<String>();
14060                            if Some(next_selected_text) != selected_text {
14061                                same_text_selected = false;
14062                                selected_text = None;
14063                            }
14064                        } else {
14065                            same_text_selected = false;
14066                            selected_text = None;
14067                        }
14068                    }
14069                }
14070            }
14071
14072            if only_carets {
14073                for selection in &mut selections {
14074                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14075                    selection.start = word_range.start;
14076                    selection.end = word_range.end;
14077                    selection.goal = SelectionGoal::None;
14078                    selection.reversed = false;
14079                    self.select_match_ranges(
14080                        selection.start..selection.end,
14081                        selection.reversed,
14082                        action.replace_newest,
14083                        Some(Autoscroll::newest()),
14084                        window,
14085                        cx,
14086                    );
14087                }
14088                if selections.len() == 1 {
14089                    let selection = selections
14090                        .last()
14091                        .expect("ensured that there's only one selection");
14092                    let query = buffer
14093                        .text_for_range(selection.start..selection.end)
14094                        .collect::<String>();
14095                    let is_empty = query.is_empty();
14096                    let select_state = SelectNextState {
14097                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14098                        wordwise: true,
14099                        done: is_empty,
14100                    };
14101                    self.select_prev_state = Some(select_state);
14102                } else {
14103                    self.select_prev_state = None;
14104                }
14105            } else if let Some(selected_text) = selected_text {
14106                self.select_prev_state = Some(SelectNextState {
14107                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14108                    wordwise: false,
14109                    done: false,
14110                });
14111                self.select_previous(action, window, cx)?;
14112            }
14113        }
14114        Ok(())
14115    }
14116
14117    pub fn find_next_match(
14118        &mut self,
14119        _: &FindNextMatch,
14120        window: &mut Window,
14121        cx: &mut Context<Self>,
14122    ) -> Result<()> {
14123        let selections = self.selections.disjoint_anchors();
14124        match selections.first() {
14125            Some(first) if selections.len() >= 2 => {
14126                self.change_selections(Default::default(), window, cx, |s| {
14127                    s.select_ranges([first.range()]);
14128                });
14129            }
14130            _ => self.select_next(
14131                &SelectNext {
14132                    replace_newest: true,
14133                },
14134                window,
14135                cx,
14136            )?,
14137        }
14138        Ok(())
14139    }
14140
14141    pub fn find_previous_match(
14142        &mut self,
14143        _: &FindPreviousMatch,
14144        window: &mut Window,
14145        cx: &mut Context<Self>,
14146    ) -> Result<()> {
14147        let selections = self.selections.disjoint_anchors();
14148        match selections.last() {
14149            Some(last) if selections.len() >= 2 => {
14150                self.change_selections(Default::default(), window, cx, |s| {
14151                    s.select_ranges([last.range()]);
14152                });
14153            }
14154            _ => self.select_previous(
14155                &SelectPrevious {
14156                    replace_newest: true,
14157                },
14158                window,
14159                cx,
14160            )?,
14161        }
14162        Ok(())
14163    }
14164
14165    pub fn toggle_comments(
14166        &mut self,
14167        action: &ToggleComments,
14168        window: &mut Window,
14169        cx: &mut Context<Self>,
14170    ) {
14171        if self.read_only(cx) {
14172            return;
14173        }
14174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14175        let text_layout_details = &self.text_layout_details(window);
14176        self.transact(window, cx, |this, window, cx| {
14177            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14178            let mut edits = Vec::new();
14179            let mut selection_edit_ranges = Vec::new();
14180            let mut last_toggled_row = None;
14181            let snapshot = this.buffer.read(cx).read(cx);
14182            let empty_str: Arc<str> = Arc::default();
14183            let mut suffixes_inserted = Vec::new();
14184            let ignore_indent = action.ignore_indent;
14185
14186            fn comment_prefix_range(
14187                snapshot: &MultiBufferSnapshot,
14188                row: MultiBufferRow,
14189                comment_prefix: &str,
14190                comment_prefix_whitespace: &str,
14191                ignore_indent: bool,
14192            ) -> Range<Point> {
14193                let indent_size = if ignore_indent {
14194                    0
14195                } else {
14196                    snapshot.indent_size_for_line(row).len
14197                };
14198
14199                let start = Point::new(row.0, indent_size);
14200
14201                let mut line_bytes = snapshot
14202                    .bytes_in_range(start..snapshot.max_point())
14203                    .flatten()
14204                    .copied();
14205
14206                // If this line currently begins with the line comment prefix, then record
14207                // the range containing the prefix.
14208                if line_bytes
14209                    .by_ref()
14210                    .take(comment_prefix.len())
14211                    .eq(comment_prefix.bytes())
14212                {
14213                    // Include any whitespace that matches the comment prefix.
14214                    let matching_whitespace_len = line_bytes
14215                        .zip(comment_prefix_whitespace.bytes())
14216                        .take_while(|(a, b)| a == b)
14217                        .count() as u32;
14218                    let end = Point::new(
14219                        start.row,
14220                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14221                    );
14222                    start..end
14223                } else {
14224                    start..start
14225                }
14226            }
14227
14228            fn comment_suffix_range(
14229                snapshot: &MultiBufferSnapshot,
14230                row: MultiBufferRow,
14231                comment_suffix: &str,
14232                comment_suffix_has_leading_space: bool,
14233            ) -> Range<Point> {
14234                let end = Point::new(row.0, snapshot.line_len(row));
14235                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14236
14237                let mut line_end_bytes = snapshot
14238                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14239                    .flatten()
14240                    .copied();
14241
14242                let leading_space_len = if suffix_start_column > 0
14243                    && line_end_bytes.next() == Some(b' ')
14244                    && comment_suffix_has_leading_space
14245                {
14246                    1
14247                } else {
14248                    0
14249                };
14250
14251                // If this line currently begins with the line comment prefix, then record
14252                // the range containing the prefix.
14253                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14254                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14255                    start..end
14256                } else {
14257                    end..end
14258                }
14259            }
14260
14261            // TODO: Handle selections that cross excerpts
14262            for selection in &mut selections {
14263                let start_column = snapshot
14264                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14265                    .len;
14266                let language = if let Some(language) =
14267                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14268                {
14269                    language
14270                } else {
14271                    continue;
14272                };
14273
14274                selection_edit_ranges.clear();
14275
14276                // If multiple selections contain a given row, avoid processing that
14277                // row more than once.
14278                let mut start_row = MultiBufferRow(selection.start.row);
14279                if last_toggled_row == Some(start_row) {
14280                    start_row = start_row.next_row();
14281                }
14282                let end_row =
14283                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14284                        MultiBufferRow(selection.end.row - 1)
14285                    } else {
14286                        MultiBufferRow(selection.end.row)
14287                    };
14288                last_toggled_row = Some(end_row);
14289
14290                if start_row > end_row {
14291                    continue;
14292                }
14293
14294                // If the language has line comments, toggle those.
14295                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14296
14297                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14298                if ignore_indent {
14299                    full_comment_prefixes = full_comment_prefixes
14300                        .into_iter()
14301                        .map(|s| Arc::from(s.trim_end()))
14302                        .collect();
14303                }
14304
14305                if !full_comment_prefixes.is_empty() {
14306                    let first_prefix = full_comment_prefixes
14307                        .first()
14308                        .expect("prefixes is non-empty");
14309                    let prefix_trimmed_lengths = full_comment_prefixes
14310                        .iter()
14311                        .map(|p| p.trim_end_matches(' ').len())
14312                        .collect::<SmallVec<[usize; 4]>>();
14313
14314                    let mut all_selection_lines_are_comments = true;
14315
14316                    for row in start_row.0..=end_row.0 {
14317                        let row = MultiBufferRow(row);
14318                        if start_row < end_row && snapshot.is_line_blank(row) {
14319                            continue;
14320                        }
14321
14322                        let prefix_range = full_comment_prefixes
14323                            .iter()
14324                            .zip(prefix_trimmed_lengths.iter().copied())
14325                            .map(|(prefix, trimmed_prefix_len)| {
14326                                comment_prefix_range(
14327                                    snapshot.deref(),
14328                                    row,
14329                                    &prefix[..trimmed_prefix_len],
14330                                    &prefix[trimmed_prefix_len..],
14331                                    ignore_indent,
14332                                )
14333                            })
14334                            .max_by_key(|range| range.end.column - range.start.column)
14335                            .expect("prefixes is non-empty");
14336
14337                        if prefix_range.is_empty() {
14338                            all_selection_lines_are_comments = false;
14339                        }
14340
14341                        selection_edit_ranges.push(prefix_range);
14342                    }
14343
14344                    if all_selection_lines_are_comments {
14345                        edits.extend(
14346                            selection_edit_ranges
14347                                .iter()
14348                                .cloned()
14349                                .map(|range| (range, empty_str.clone())),
14350                        );
14351                    } else {
14352                        let min_column = selection_edit_ranges
14353                            .iter()
14354                            .map(|range| range.start.column)
14355                            .min()
14356                            .unwrap_or(0);
14357                        edits.extend(selection_edit_ranges.iter().map(|range| {
14358                            let position = Point::new(range.start.row, min_column);
14359                            (position..position, first_prefix.clone())
14360                        }));
14361                    }
14362                } else if let Some(BlockCommentConfig {
14363                    start: full_comment_prefix,
14364                    end: comment_suffix,
14365                    ..
14366                }) = language.block_comment()
14367                {
14368                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14369                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14370                    let prefix_range = comment_prefix_range(
14371                        snapshot.deref(),
14372                        start_row,
14373                        comment_prefix,
14374                        comment_prefix_whitespace,
14375                        ignore_indent,
14376                    );
14377                    let suffix_range = comment_suffix_range(
14378                        snapshot.deref(),
14379                        end_row,
14380                        comment_suffix.trim_start_matches(' '),
14381                        comment_suffix.starts_with(' '),
14382                    );
14383
14384                    if prefix_range.is_empty() || suffix_range.is_empty() {
14385                        edits.push((
14386                            prefix_range.start..prefix_range.start,
14387                            full_comment_prefix.clone(),
14388                        ));
14389                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14390                        suffixes_inserted.push((end_row, comment_suffix.len()));
14391                    } else {
14392                        edits.push((prefix_range, empty_str.clone()));
14393                        edits.push((suffix_range, empty_str.clone()));
14394                    }
14395                } else {
14396                    continue;
14397                }
14398            }
14399
14400            drop(snapshot);
14401            this.buffer.update(cx, |buffer, cx| {
14402                buffer.edit(edits, None, cx);
14403            });
14404
14405            // Adjust selections so that they end before any comment suffixes that
14406            // were inserted.
14407            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14408            let mut selections = this.selections.all::<Point>(cx);
14409            let snapshot = this.buffer.read(cx).read(cx);
14410            for selection in &mut selections {
14411                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14412                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14413                        Ordering::Less => {
14414                            suffixes_inserted.next();
14415                            continue;
14416                        }
14417                        Ordering::Greater => break,
14418                        Ordering::Equal => {
14419                            if selection.end.column == snapshot.line_len(row) {
14420                                if selection.is_empty() {
14421                                    selection.start.column -= suffix_len as u32;
14422                                }
14423                                selection.end.column -= suffix_len as u32;
14424                            }
14425                            break;
14426                        }
14427                    }
14428                }
14429            }
14430
14431            drop(snapshot);
14432            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14433
14434            let selections = this.selections.all::<Point>(cx);
14435            let selections_on_single_row = selections.windows(2).all(|selections| {
14436                selections[0].start.row == selections[1].start.row
14437                    && selections[0].end.row == selections[1].end.row
14438                    && selections[0].start.row == selections[0].end.row
14439            });
14440            let selections_selecting = selections
14441                .iter()
14442                .any(|selection| selection.start != selection.end);
14443            let advance_downwards = action.advance_downwards
14444                && selections_on_single_row
14445                && !selections_selecting
14446                && !matches!(this.mode, EditorMode::SingleLine { .. });
14447
14448            if advance_downwards {
14449                let snapshot = this.buffer.read(cx).snapshot(cx);
14450
14451                this.change_selections(Default::default(), window, cx, |s| {
14452                    s.move_cursors_with(|display_snapshot, display_point, _| {
14453                        let mut point = display_point.to_point(display_snapshot);
14454                        point.row += 1;
14455                        point = snapshot.clip_point(point, Bias::Left);
14456                        let display_point = point.to_display_point(display_snapshot);
14457                        let goal = SelectionGoal::HorizontalPosition(
14458                            display_snapshot
14459                                .x_for_display_point(display_point, text_layout_details)
14460                                .into(),
14461                        );
14462                        (display_point, goal)
14463                    })
14464                });
14465            }
14466        });
14467    }
14468
14469    pub fn select_enclosing_symbol(
14470        &mut self,
14471        _: &SelectEnclosingSymbol,
14472        window: &mut Window,
14473        cx: &mut Context<Self>,
14474    ) {
14475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14476
14477        let buffer = self.buffer.read(cx).snapshot(cx);
14478        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14479
14480        fn update_selection(
14481            selection: &Selection<usize>,
14482            buffer_snap: &MultiBufferSnapshot,
14483        ) -> Option<Selection<usize>> {
14484            let cursor = selection.head();
14485            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14486            for symbol in symbols.iter().rev() {
14487                let start = symbol.range.start.to_offset(buffer_snap);
14488                let end = symbol.range.end.to_offset(buffer_snap);
14489                let new_range = start..end;
14490                if start < selection.start || end > selection.end {
14491                    return Some(Selection {
14492                        id: selection.id,
14493                        start: new_range.start,
14494                        end: new_range.end,
14495                        goal: SelectionGoal::None,
14496                        reversed: selection.reversed,
14497                    });
14498                }
14499            }
14500            None
14501        }
14502
14503        let mut selected_larger_symbol = false;
14504        let new_selections = old_selections
14505            .iter()
14506            .map(|selection| match update_selection(selection, &buffer) {
14507                Some(new_selection) => {
14508                    if new_selection.range() != selection.range() {
14509                        selected_larger_symbol = true;
14510                    }
14511                    new_selection
14512                }
14513                None => selection.clone(),
14514            })
14515            .collect::<Vec<_>>();
14516
14517        if selected_larger_symbol {
14518            self.change_selections(Default::default(), window, cx, |s| {
14519                s.select(new_selections);
14520            });
14521        }
14522    }
14523
14524    pub fn select_larger_syntax_node(
14525        &mut self,
14526        _: &SelectLargerSyntaxNode,
14527        window: &mut Window,
14528        cx: &mut Context<Self>,
14529    ) {
14530        let Some(visible_row_count) = self.visible_row_count() else {
14531            return;
14532        };
14533        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14534        if old_selections.is_empty() {
14535            return;
14536        }
14537
14538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14539
14540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14541        let buffer = self.buffer.read(cx).snapshot(cx);
14542
14543        let mut selected_larger_node = false;
14544        let mut new_selections = old_selections
14545            .iter()
14546            .map(|selection| {
14547                let old_range = selection.start..selection.end;
14548
14549                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14550                    // manually select word at selection
14551                    if ["string_content", "inline"].contains(&node.kind()) {
14552                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14553                        // ignore if word is already selected
14554                        if !word_range.is_empty() && old_range != word_range {
14555                            let (last_word_range, _) =
14556                                buffer.surrounding_word(old_range.end, false);
14557                            // only select word if start and end point belongs to same word
14558                            if word_range == last_word_range {
14559                                selected_larger_node = true;
14560                                return Selection {
14561                                    id: selection.id,
14562                                    start: word_range.start,
14563                                    end: word_range.end,
14564                                    goal: SelectionGoal::None,
14565                                    reversed: selection.reversed,
14566                                };
14567                            }
14568                        }
14569                    }
14570                }
14571
14572                let mut new_range = old_range.clone();
14573                while let Some((_node, containing_range)) =
14574                    buffer.syntax_ancestor(new_range.clone())
14575                {
14576                    new_range = match containing_range {
14577                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14578                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14579                    };
14580                    if !display_map.intersects_fold(new_range.start)
14581                        && !display_map.intersects_fold(new_range.end)
14582                    {
14583                        break;
14584                    }
14585                }
14586
14587                selected_larger_node |= new_range != old_range;
14588                Selection {
14589                    id: selection.id,
14590                    start: new_range.start,
14591                    end: new_range.end,
14592                    goal: SelectionGoal::None,
14593                    reversed: selection.reversed,
14594                }
14595            })
14596            .collect::<Vec<_>>();
14597
14598        if !selected_larger_node {
14599            return; // don't put this call in the history
14600        }
14601
14602        // scroll based on transformation done to the last selection created by the user
14603        let (last_old, last_new) = old_selections
14604            .last()
14605            .zip(new_selections.last().cloned())
14606            .expect("old_selections isn't empty");
14607
14608        // revert selection
14609        let is_selection_reversed = {
14610            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14611            new_selections.last_mut().expect("checked above").reversed =
14612                should_newest_selection_be_reversed;
14613            should_newest_selection_be_reversed
14614        };
14615
14616        if selected_larger_node {
14617            self.select_syntax_node_history.disable_clearing = true;
14618            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14619                s.select(new_selections.clone());
14620            });
14621            self.select_syntax_node_history.disable_clearing = false;
14622        }
14623
14624        let start_row = last_new.start.to_display_point(&display_map).row().0;
14625        let end_row = last_new.end.to_display_point(&display_map).row().0;
14626        let selection_height = end_row - start_row + 1;
14627        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14628
14629        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14630        let scroll_behavior = if fits_on_the_screen {
14631            self.request_autoscroll(Autoscroll::fit(), cx);
14632            SelectSyntaxNodeScrollBehavior::FitSelection
14633        } else if is_selection_reversed {
14634            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14635            SelectSyntaxNodeScrollBehavior::CursorTop
14636        } else {
14637            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14638            SelectSyntaxNodeScrollBehavior::CursorBottom
14639        };
14640
14641        self.select_syntax_node_history.push((
14642            old_selections,
14643            scroll_behavior,
14644            is_selection_reversed,
14645        ));
14646    }
14647
14648    pub fn select_smaller_syntax_node(
14649        &mut self,
14650        _: &SelectSmallerSyntaxNode,
14651        window: &mut Window,
14652        cx: &mut Context<Self>,
14653    ) {
14654        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14655
14656        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14657            self.select_syntax_node_history.pop()
14658        {
14659            if let Some(selection) = selections.last_mut() {
14660                selection.reversed = is_selection_reversed;
14661            }
14662
14663            self.select_syntax_node_history.disable_clearing = true;
14664            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14665                s.select(selections.to_vec());
14666            });
14667            self.select_syntax_node_history.disable_clearing = false;
14668
14669            match scroll_behavior {
14670                SelectSyntaxNodeScrollBehavior::CursorTop => {
14671                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14672                }
14673                SelectSyntaxNodeScrollBehavior::FitSelection => {
14674                    self.request_autoscroll(Autoscroll::fit(), cx);
14675                }
14676                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14677                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14678                }
14679            }
14680        }
14681    }
14682
14683    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14684        if !EditorSettings::get_global(cx).gutter.runnables {
14685            self.clear_tasks();
14686            return Task::ready(());
14687        }
14688        let project = self.project.as_ref().map(Entity::downgrade);
14689        let task_sources = self.lsp_task_sources(cx);
14690        let multi_buffer = self.buffer.downgrade();
14691        cx.spawn_in(window, async move |editor, cx| {
14692            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14693            let Some(project) = project.and_then(|p| p.upgrade()) else {
14694                return;
14695            };
14696            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14697                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14698            }) else {
14699                return;
14700            };
14701
14702            let hide_runnables = project
14703                .update(cx, |project, cx| {
14704                    // Do not display any test indicators in non-dev server remote projects.
14705                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14706                })
14707                .unwrap_or(true);
14708            if hide_runnables {
14709                return;
14710            }
14711            let new_rows =
14712                cx.background_spawn({
14713                    let snapshot = display_snapshot.clone();
14714                    async move {
14715                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14716                    }
14717                })
14718                    .await;
14719            let Ok(lsp_tasks) =
14720                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14721            else {
14722                return;
14723            };
14724            let lsp_tasks = lsp_tasks.await;
14725
14726            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14727                lsp_tasks
14728                    .into_iter()
14729                    .flat_map(|(kind, tasks)| {
14730                        tasks.into_iter().filter_map(move |(location, task)| {
14731                            Some((kind.clone(), location?, task))
14732                        })
14733                    })
14734                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14735                        let buffer = location.target.buffer;
14736                        let buffer_snapshot = buffer.read(cx).snapshot();
14737                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14738                            |(excerpt_id, snapshot, _)| {
14739                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14740                                    display_snapshot
14741                                        .buffer_snapshot
14742                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14743                                } else {
14744                                    None
14745                                }
14746                            },
14747                        );
14748                        if let Some(offset) = offset {
14749                            let task_buffer_range =
14750                                location.target.range.to_point(&buffer_snapshot);
14751                            let context_buffer_range =
14752                                task_buffer_range.to_offset(&buffer_snapshot);
14753                            let context_range = BufferOffset(context_buffer_range.start)
14754                                ..BufferOffset(context_buffer_range.end);
14755
14756                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14757                                .or_insert_with(|| RunnableTasks {
14758                                    templates: Vec::new(),
14759                                    offset,
14760                                    column: task_buffer_range.start.column,
14761                                    extra_variables: HashMap::default(),
14762                                    context_range,
14763                                })
14764                                .templates
14765                                .push((kind, task.original_task().clone()));
14766                        }
14767
14768                        acc
14769                    })
14770            }) else {
14771                return;
14772            };
14773
14774            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14775                buffer.language_settings(cx).tasks.prefer_lsp
14776            }) else {
14777                return;
14778            };
14779
14780            let rows = Self::runnable_rows(
14781                project,
14782                display_snapshot,
14783                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14784                new_rows,
14785                cx.clone(),
14786            )
14787            .await;
14788            editor
14789                .update(cx, |editor, _| {
14790                    editor.clear_tasks();
14791                    for (key, mut value) in rows {
14792                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14793                            value.templates.extend(lsp_tasks.templates);
14794                        }
14795
14796                        editor.insert_tasks(key, value);
14797                    }
14798                    for (key, value) in lsp_tasks_by_rows {
14799                        editor.insert_tasks(key, value);
14800                    }
14801                })
14802                .ok();
14803        })
14804    }
14805    fn fetch_runnable_ranges(
14806        snapshot: &DisplaySnapshot,
14807        range: Range<Anchor>,
14808    ) -> Vec<language::RunnableRange> {
14809        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14810    }
14811
14812    fn runnable_rows(
14813        project: Entity<Project>,
14814        snapshot: DisplaySnapshot,
14815        prefer_lsp: bool,
14816        runnable_ranges: Vec<RunnableRange>,
14817        cx: AsyncWindowContext,
14818    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14819        cx.spawn(async move |cx| {
14820            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14821            for mut runnable in runnable_ranges {
14822                let Some(tasks) = cx
14823                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14824                    .ok()
14825                else {
14826                    continue;
14827                };
14828                let mut tasks = tasks.await;
14829
14830                if prefer_lsp {
14831                    tasks.retain(|(task_kind, _)| {
14832                        !matches!(task_kind, TaskSourceKind::Language { .. })
14833                    });
14834                }
14835                if tasks.is_empty() {
14836                    continue;
14837                }
14838
14839                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14840                let Some(row) = snapshot
14841                    .buffer_snapshot
14842                    .buffer_line_for_row(MultiBufferRow(point.row))
14843                    .map(|(_, range)| range.start.row)
14844                else {
14845                    continue;
14846                };
14847
14848                let context_range =
14849                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14850                runnable_rows.push((
14851                    (runnable.buffer_id, row),
14852                    RunnableTasks {
14853                        templates: tasks,
14854                        offset: snapshot
14855                            .buffer_snapshot
14856                            .anchor_before(runnable.run_range.start),
14857                        context_range,
14858                        column: point.column,
14859                        extra_variables: runnable.extra_captures,
14860                    },
14861                ));
14862            }
14863            runnable_rows
14864        })
14865    }
14866
14867    fn templates_with_tags(
14868        project: &Entity<Project>,
14869        runnable: &mut Runnable,
14870        cx: &mut App,
14871    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14872        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14873            let (worktree_id, file) = project
14874                .buffer_for_id(runnable.buffer, cx)
14875                .and_then(|buffer| buffer.read(cx).file())
14876                .map(|file| (file.worktree_id(cx), file.clone()))
14877                .unzip();
14878
14879            (
14880                project.task_store().read(cx).task_inventory().cloned(),
14881                worktree_id,
14882                file,
14883            )
14884        });
14885
14886        let tags = mem::take(&mut runnable.tags);
14887        let language = runnable.language.clone();
14888        cx.spawn(async move |cx| {
14889            let mut templates_with_tags = Vec::new();
14890            if let Some(inventory) = inventory {
14891                for RunnableTag(tag) in tags {
14892                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14893                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14894                    }) else {
14895                        return templates_with_tags;
14896                    };
14897                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14898                        move |(_, template)| {
14899                            template.tags.iter().any(|source_tag| source_tag == &tag)
14900                        },
14901                    ));
14902                }
14903            }
14904            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14905
14906            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14907                // Strongest source wins; if we have worktree tag binding, prefer that to
14908                // global and language bindings;
14909                // if we have a global binding, prefer that to language binding.
14910                let first_mismatch = templates_with_tags
14911                    .iter()
14912                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14913                if let Some(index) = first_mismatch {
14914                    templates_with_tags.truncate(index);
14915                }
14916            }
14917
14918            templates_with_tags
14919        })
14920    }
14921
14922    pub fn move_to_enclosing_bracket(
14923        &mut self,
14924        _: &MoveToEnclosingBracket,
14925        window: &mut Window,
14926        cx: &mut Context<Self>,
14927    ) {
14928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14929        self.change_selections(Default::default(), window, cx, |s| {
14930            s.move_offsets_with(|snapshot, selection| {
14931                let Some(enclosing_bracket_ranges) =
14932                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14933                else {
14934                    return;
14935                };
14936
14937                let mut best_length = usize::MAX;
14938                let mut best_inside = false;
14939                let mut best_in_bracket_range = false;
14940                let mut best_destination = None;
14941                for (open, close) in enclosing_bracket_ranges {
14942                    let close = close.to_inclusive();
14943                    let length = close.end() - open.start;
14944                    let inside = selection.start >= open.end && selection.end <= *close.start();
14945                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14946                        || close.contains(&selection.head());
14947
14948                    // If best is next to a bracket and current isn't, skip
14949                    if !in_bracket_range && best_in_bracket_range {
14950                        continue;
14951                    }
14952
14953                    // Prefer smaller lengths unless best is inside and current isn't
14954                    if length > best_length && (best_inside || !inside) {
14955                        continue;
14956                    }
14957
14958                    best_length = length;
14959                    best_inside = inside;
14960                    best_in_bracket_range = in_bracket_range;
14961                    best_destination = Some(
14962                        if close.contains(&selection.start) && close.contains(&selection.end) {
14963                            if inside { open.end } else { open.start }
14964                        } else if inside {
14965                            *close.start()
14966                        } else {
14967                            *close.end()
14968                        },
14969                    );
14970                }
14971
14972                if let Some(destination) = best_destination {
14973                    selection.collapse_to(destination, SelectionGoal::None);
14974                }
14975            })
14976        });
14977    }
14978
14979    pub fn undo_selection(
14980        &mut self,
14981        _: &UndoSelection,
14982        window: &mut Window,
14983        cx: &mut Context<Self>,
14984    ) {
14985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14986        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14987            self.selection_history.mode = SelectionHistoryMode::Undoing;
14988            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14989                this.end_selection(window, cx);
14990                this.change_selections(
14991                    SelectionEffects::scroll(Autoscroll::newest()),
14992                    window,
14993                    cx,
14994                    |s| s.select_anchors(entry.selections.to_vec()),
14995                );
14996            });
14997            self.selection_history.mode = SelectionHistoryMode::Normal;
14998
14999            self.select_next_state = entry.select_next_state;
15000            self.select_prev_state = entry.select_prev_state;
15001            self.add_selections_state = entry.add_selections_state;
15002        }
15003    }
15004
15005    pub fn redo_selection(
15006        &mut self,
15007        _: &RedoSelection,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) {
15011        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15012        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15013            self.selection_history.mode = SelectionHistoryMode::Redoing;
15014            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15015                this.end_selection(window, cx);
15016                this.change_selections(
15017                    SelectionEffects::scroll(Autoscroll::newest()),
15018                    window,
15019                    cx,
15020                    |s| s.select_anchors(entry.selections.to_vec()),
15021                );
15022            });
15023            self.selection_history.mode = SelectionHistoryMode::Normal;
15024
15025            self.select_next_state = entry.select_next_state;
15026            self.select_prev_state = entry.select_prev_state;
15027            self.add_selections_state = entry.add_selections_state;
15028        }
15029    }
15030
15031    pub fn expand_excerpts(
15032        &mut self,
15033        action: &ExpandExcerpts,
15034        _: &mut Window,
15035        cx: &mut Context<Self>,
15036    ) {
15037        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15038    }
15039
15040    pub fn expand_excerpts_down(
15041        &mut self,
15042        action: &ExpandExcerptsDown,
15043        _: &mut Window,
15044        cx: &mut Context<Self>,
15045    ) {
15046        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15047    }
15048
15049    pub fn expand_excerpts_up(
15050        &mut self,
15051        action: &ExpandExcerptsUp,
15052        _: &mut Window,
15053        cx: &mut Context<Self>,
15054    ) {
15055        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15056    }
15057
15058    pub fn expand_excerpts_for_direction(
15059        &mut self,
15060        lines: u32,
15061        direction: ExpandExcerptDirection,
15062
15063        cx: &mut Context<Self>,
15064    ) {
15065        let selections = self.selections.disjoint_anchors();
15066
15067        let lines = if lines == 0 {
15068            EditorSettings::get_global(cx).expand_excerpt_lines
15069        } else {
15070            lines
15071        };
15072
15073        self.buffer.update(cx, |buffer, cx| {
15074            let snapshot = buffer.snapshot(cx);
15075            let mut excerpt_ids = selections
15076                .iter()
15077                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15078                .collect::<Vec<_>>();
15079            excerpt_ids.sort();
15080            excerpt_ids.dedup();
15081            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15082        })
15083    }
15084
15085    pub fn expand_excerpt(
15086        &mut self,
15087        excerpt: ExcerptId,
15088        direction: ExpandExcerptDirection,
15089        window: &mut Window,
15090        cx: &mut Context<Self>,
15091    ) {
15092        let current_scroll_position = self.scroll_position(cx);
15093        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15094        let mut should_scroll_up = false;
15095
15096        if direction == ExpandExcerptDirection::Down {
15097            let multi_buffer = self.buffer.read(cx);
15098            let snapshot = multi_buffer.snapshot(cx);
15099            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15100                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15101                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15102                        let buffer_snapshot = buffer.read(cx).snapshot();
15103                        let excerpt_end_row =
15104                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15105                        let last_row = buffer_snapshot.max_point().row;
15106                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15107                        should_scroll_up = lines_below >= lines_to_expand;
15108                    }
15109                }
15110            }
15111        }
15112
15113        self.buffer.update(cx, |buffer, cx| {
15114            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15115        });
15116
15117        if should_scroll_up {
15118            let new_scroll_position =
15119                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15120            self.set_scroll_position(new_scroll_position, window, cx);
15121        }
15122    }
15123
15124    pub fn go_to_singleton_buffer_point(
15125        &mut self,
15126        point: Point,
15127        window: &mut Window,
15128        cx: &mut Context<Self>,
15129    ) {
15130        self.go_to_singleton_buffer_range(point..point, window, cx);
15131    }
15132
15133    pub fn go_to_singleton_buffer_range(
15134        &mut self,
15135        range: Range<Point>,
15136        window: &mut Window,
15137        cx: &mut Context<Self>,
15138    ) {
15139        let multibuffer = self.buffer().read(cx);
15140        let Some(buffer) = multibuffer.as_singleton() else {
15141            return;
15142        };
15143        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15144            return;
15145        };
15146        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15147            return;
15148        };
15149        self.change_selections(
15150            SelectionEffects::default().nav_history(true),
15151            window,
15152            cx,
15153            |s| s.select_anchor_ranges([start..end]),
15154        );
15155    }
15156
15157    pub fn go_to_diagnostic(
15158        &mut self,
15159        action: &GoToDiagnostic,
15160        window: &mut Window,
15161        cx: &mut Context<Self>,
15162    ) {
15163        if !self.diagnostics_enabled() {
15164            return;
15165        }
15166        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15167        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15168    }
15169
15170    pub fn go_to_prev_diagnostic(
15171        &mut self,
15172        action: &GoToPreviousDiagnostic,
15173        window: &mut Window,
15174        cx: &mut Context<Self>,
15175    ) {
15176        if !self.diagnostics_enabled() {
15177            return;
15178        }
15179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15180        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15181    }
15182
15183    pub fn go_to_diagnostic_impl(
15184        &mut self,
15185        direction: Direction,
15186        severity: GoToDiagnosticSeverityFilter,
15187        window: &mut Window,
15188        cx: &mut Context<Self>,
15189    ) {
15190        let buffer = self.buffer.read(cx).snapshot(cx);
15191        let selection = self.selections.newest::<usize>(cx);
15192
15193        let mut active_group_id = None;
15194        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15195            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15196                active_group_id = Some(active_group.group_id);
15197            }
15198        }
15199
15200        fn filtered(
15201            snapshot: EditorSnapshot,
15202            severity: GoToDiagnosticSeverityFilter,
15203            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15204        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15205            diagnostics
15206                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15207                .filter(|entry| entry.range.start != entry.range.end)
15208                .filter(|entry| !entry.diagnostic.is_unnecessary)
15209                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15210        }
15211
15212        let snapshot = self.snapshot(window, cx);
15213        let before = filtered(
15214            snapshot.clone(),
15215            severity,
15216            buffer
15217                .diagnostics_in_range(0..selection.start)
15218                .filter(|entry| entry.range.start <= selection.start),
15219        );
15220        let after = filtered(
15221            snapshot,
15222            severity,
15223            buffer
15224                .diagnostics_in_range(selection.start..buffer.len())
15225                .filter(|entry| entry.range.start >= selection.start),
15226        );
15227
15228        let mut found: Option<DiagnosticEntry<usize>> = None;
15229        if direction == Direction::Prev {
15230            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15231            {
15232                for diagnostic in prev_diagnostics.into_iter().rev() {
15233                    if diagnostic.range.start != selection.start
15234                        || active_group_id
15235                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15236                    {
15237                        found = Some(diagnostic);
15238                        break 'outer;
15239                    }
15240                }
15241            }
15242        } else {
15243            for diagnostic in after.chain(before) {
15244                if diagnostic.range.start != selection.start
15245                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15246                {
15247                    found = Some(diagnostic);
15248                    break;
15249                }
15250            }
15251        }
15252        let Some(next_diagnostic) = found else {
15253            return;
15254        };
15255
15256        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15257            return;
15258        };
15259        self.change_selections(Default::default(), window, cx, |s| {
15260            s.select_ranges(vec![
15261                next_diagnostic.range.start..next_diagnostic.range.start,
15262            ])
15263        });
15264        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15265        self.refresh_inline_completion(false, true, window, cx);
15266    }
15267
15268    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15270        let snapshot = self.snapshot(window, cx);
15271        let selection = self.selections.newest::<Point>(cx);
15272        self.go_to_hunk_before_or_after_position(
15273            &snapshot,
15274            selection.head(),
15275            Direction::Next,
15276            window,
15277            cx,
15278        );
15279    }
15280
15281    pub fn go_to_hunk_before_or_after_position(
15282        &mut self,
15283        snapshot: &EditorSnapshot,
15284        position: Point,
15285        direction: Direction,
15286        window: &mut Window,
15287        cx: &mut Context<Editor>,
15288    ) {
15289        let row = if direction == Direction::Next {
15290            self.hunk_after_position(snapshot, position)
15291                .map(|hunk| hunk.row_range.start)
15292        } else {
15293            self.hunk_before_position(snapshot, position)
15294        };
15295
15296        if let Some(row) = row {
15297            let destination = Point::new(row.0, 0);
15298            let autoscroll = Autoscroll::center();
15299
15300            self.unfold_ranges(&[destination..destination], false, false, cx);
15301            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15302                s.select_ranges([destination..destination]);
15303            });
15304        }
15305    }
15306
15307    fn hunk_after_position(
15308        &mut self,
15309        snapshot: &EditorSnapshot,
15310        position: Point,
15311    ) -> Option<MultiBufferDiffHunk> {
15312        snapshot
15313            .buffer_snapshot
15314            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15315            .find(|hunk| hunk.row_range.start.0 > position.row)
15316            .or_else(|| {
15317                snapshot
15318                    .buffer_snapshot
15319                    .diff_hunks_in_range(Point::zero()..position)
15320                    .find(|hunk| hunk.row_range.end.0 < position.row)
15321            })
15322    }
15323
15324    fn go_to_prev_hunk(
15325        &mut self,
15326        _: &GoToPreviousHunk,
15327        window: &mut Window,
15328        cx: &mut Context<Self>,
15329    ) {
15330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15331        let snapshot = self.snapshot(window, cx);
15332        let selection = self.selections.newest::<Point>(cx);
15333        self.go_to_hunk_before_or_after_position(
15334            &snapshot,
15335            selection.head(),
15336            Direction::Prev,
15337            window,
15338            cx,
15339        );
15340    }
15341
15342    fn hunk_before_position(
15343        &mut self,
15344        snapshot: &EditorSnapshot,
15345        position: Point,
15346    ) -> Option<MultiBufferRow> {
15347        snapshot
15348            .buffer_snapshot
15349            .diff_hunk_before(position)
15350            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15351    }
15352
15353    fn go_to_next_change(
15354        &mut self,
15355        _: &GoToNextChange,
15356        window: &mut Window,
15357        cx: &mut Context<Self>,
15358    ) {
15359        if let Some(selections) = self
15360            .change_list
15361            .next_change(1, Direction::Next)
15362            .map(|s| s.to_vec())
15363        {
15364            self.change_selections(Default::default(), window, cx, |s| {
15365                let map = s.display_map();
15366                s.select_display_ranges(selections.iter().map(|a| {
15367                    let point = a.to_display_point(&map);
15368                    point..point
15369                }))
15370            })
15371        }
15372    }
15373
15374    fn go_to_previous_change(
15375        &mut self,
15376        _: &GoToPreviousChange,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        if let Some(selections) = self
15381            .change_list
15382            .next_change(1, Direction::Prev)
15383            .map(|s| s.to_vec())
15384        {
15385            self.change_selections(Default::default(), window, cx, |s| {
15386                let map = s.display_map();
15387                s.select_display_ranges(selections.iter().map(|a| {
15388                    let point = a.to_display_point(&map);
15389                    point..point
15390                }))
15391            })
15392        }
15393    }
15394
15395    fn go_to_line<T: 'static>(
15396        &mut self,
15397        position: Anchor,
15398        highlight_color: Option<Hsla>,
15399        window: &mut Window,
15400        cx: &mut Context<Self>,
15401    ) {
15402        let snapshot = self.snapshot(window, cx).display_snapshot;
15403        let position = position.to_point(&snapshot.buffer_snapshot);
15404        let start = snapshot
15405            .buffer_snapshot
15406            .clip_point(Point::new(position.row, 0), Bias::Left);
15407        let end = start + Point::new(1, 0);
15408        let start = snapshot.buffer_snapshot.anchor_before(start);
15409        let end = snapshot.buffer_snapshot.anchor_before(end);
15410
15411        self.highlight_rows::<T>(
15412            start..end,
15413            highlight_color
15414                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15415            Default::default(),
15416            cx,
15417        );
15418
15419        if self.buffer.read(cx).is_singleton() {
15420            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15421        }
15422    }
15423
15424    pub fn go_to_definition(
15425        &mut self,
15426        _: &GoToDefinition,
15427        window: &mut Window,
15428        cx: &mut Context<Self>,
15429    ) -> Task<Result<Navigated>> {
15430        let definition =
15431            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15432        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15433        cx.spawn_in(window, async move |editor, cx| {
15434            if definition.await? == Navigated::Yes {
15435                return Ok(Navigated::Yes);
15436            }
15437            match fallback_strategy {
15438                GoToDefinitionFallback::None => Ok(Navigated::No),
15439                GoToDefinitionFallback::FindAllReferences => {
15440                    match editor.update_in(cx, |editor, window, cx| {
15441                        editor.find_all_references(&FindAllReferences, window, cx)
15442                    })? {
15443                        Some(references) => references.await,
15444                        None => Ok(Navigated::No),
15445                    }
15446                }
15447            }
15448        })
15449    }
15450
15451    pub fn go_to_declaration(
15452        &mut self,
15453        _: &GoToDeclaration,
15454        window: &mut Window,
15455        cx: &mut Context<Self>,
15456    ) -> Task<Result<Navigated>> {
15457        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15458    }
15459
15460    pub fn go_to_declaration_split(
15461        &mut self,
15462        _: &GoToDeclaration,
15463        window: &mut Window,
15464        cx: &mut Context<Self>,
15465    ) -> Task<Result<Navigated>> {
15466        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15467    }
15468
15469    pub fn go_to_implementation(
15470        &mut self,
15471        _: &GoToImplementation,
15472        window: &mut Window,
15473        cx: &mut Context<Self>,
15474    ) -> Task<Result<Navigated>> {
15475        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15476    }
15477
15478    pub fn go_to_implementation_split(
15479        &mut self,
15480        _: &GoToImplementationSplit,
15481        window: &mut Window,
15482        cx: &mut Context<Self>,
15483    ) -> Task<Result<Navigated>> {
15484        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15485    }
15486
15487    pub fn go_to_type_definition(
15488        &mut self,
15489        _: &GoToTypeDefinition,
15490        window: &mut Window,
15491        cx: &mut Context<Self>,
15492    ) -> Task<Result<Navigated>> {
15493        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15494    }
15495
15496    pub fn go_to_definition_split(
15497        &mut self,
15498        _: &GoToDefinitionSplit,
15499        window: &mut Window,
15500        cx: &mut Context<Self>,
15501    ) -> Task<Result<Navigated>> {
15502        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15503    }
15504
15505    pub fn go_to_type_definition_split(
15506        &mut self,
15507        _: &GoToTypeDefinitionSplit,
15508        window: &mut Window,
15509        cx: &mut Context<Self>,
15510    ) -> Task<Result<Navigated>> {
15511        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15512    }
15513
15514    fn go_to_definition_of_kind(
15515        &mut self,
15516        kind: GotoDefinitionKind,
15517        split: bool,
15518        window: &mut Window,
15519        cx: &mut Context<Self>,
15520    ) -> Task<Result<Navigated>> {
15521        let Some(provider) = self.semantics_provider.clone() else {
15522            return Task::ready(Ok(Navigated::No));
15523        };
15524        let head = self.selections.newest::<usize>(cx).head();
15525        let buffer = self.buffer.read(cx);
15526        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15527            text_anchor
15528        } else {
15529            return Task::ready(Ok(Navigated::No));
15530        };
15531
15532        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15533            return Task::ready(Ok(Navigated::No));
15534        };
15535
15536        cx.spawn_in(window, async move |editor, cx| {
15537            let definitions = definitions.await?;
15538            let navigated = editor
15539                .update_in(cx, |editor, window, cx| {
15540                    editor.navigate_to_hover_links(
15541                        Some(kind),
15542                        definitions
15543                            .into_iter()
15544                            .filter(|location| {
15545                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15546                            })
15547                            .map(HoverLink::Text)
15548                            .collect::<Vec<_>>(),
15549                        split,
15550                        window,
15551                        cx,
15552                    )
15553                })?
15554                .await?;
15555            anyhow::Ok(navigated)
15556        })
15557    }
15558
15559    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15560        let selection = self.selections.newest_anchor();
15561        let head = selection.head();
15562        let tail = selection.tail();
15563
15564        let Some((buffer, start_position)) =
15565            self.buffer.read(cx).text_anchor_for_position(head, cx)
15566        else {
15567            return;
15568        };
15569
15570        let end_position = if head != tail {
15571            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15572                return;
15573            };
15574            Some(pos)
15575        } else {
15576            None
15577        };
15578
15579        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15580            let url = if let Some(end_pos) = end_position {
15581                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15582            } else {
15583                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15584            };
15585
15586            if let Some(url) = url {
15587                editor.update(cx, |_, cx| {
15588                    cx.open_url(&url);
15589                })
15590            } else {
15591                Ok(())
15592            }
15593        });
15594
15595        url_finder.detach();
15596    }
15597
15598    pub fn open_selected_filename(
15599        &mut self,
15600        _: &OpenSelectedFilename,
15601        window: &mut Window,
15602        cx: &mut Context<Self>,
15603    ) {
15604        let Some(workspace) = self.workspace() else {
15605            return;
15606        };
15607
15608        let position = self.selections.newest_anchor().head();
15609
15610        let Some((buffer, buffer_position)) =
15611            self.buffer.read(cx).text_anchor_for_position(position, cx)
15612        else {
15613            return;
15614        };
15615
15616        let project = self.project.clone();
15617
15618        cx.spawn_in(window, async move |_, cx| {
15619            let result = find_file(&buffer, project, buffer_position, cx).await;
15620
15621            if let Some((_, path)) = result {
15622                workspace
15623                    .update_in(cx, |workspace, window, cx| {
15624                        workspace.open_resolved_path(path, window, cx)
15625                    })?
15626                    .await?;
15627            }
15628            anyhow::Ok(())
15629        })
15630        .detach();
15631    }
15632
15633    pub(crate) fn navigate_to_hover_links(
15634        &mut self,
15635        kind: Option<GotoDefinitionKind>,
15636        mut definitions: Vec<HoverLink>,
15637        split: bool,
15638        window: &mut Window,
15639        cx: &mut Context<Editor>,
15640    ) -> Task<Result<Navigated>> {
15641        // If there is one definition, just open it directly
15642        if definitions.len() == 1 {
15643            let definition = definitions.pop().unwrap();
15644
15645            enum TargetTaskResult {
15646                Location(Option<Location>),
15647                AlreadyNavigated,
15648            }
15649
15650            let target_task = match definition {
15651                HoverLink::Text(link) => {
15652                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15653                }
15654                HoverLink::InlayHint(lsp_location, server_id) => {
15655                    let computation =
15656                        self.compute_target_location(lsp_location, server_id, window, cx);
15657                    cx.background_spawn(async move {
15658                        let location = computation.await?;
15659                        Ok(TargetTaskResult::Location(location))
15660                    })
15661                }
15662                HoverLink::Url(url) => {
15663                    cx.open_url(&url);
15664                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15665                }
15666                HoverLink::File(path) => {
15667                    if let Some(workspace) = self.workspace() {
15668                        cx.spawn_in(window, async move |_, cx| {
15669                            workspace
15670                                .update_in(cx, |workspace, window, cx| {
15671                                    workspace.open_resolved_path(path, window, cx)
15672                                })?
15673                                .await
15674                                .map(|_| TargetTaskResult::AlreadyNavigated)
15675                        })
15676                    } else {
15677                        Task::ready(Ok(TargetTaskResult::Location(None)))
15678                    }
15679                }
15680            };
15681            cx.spawn_in(window, async move |editor, cx| {
15682                let target = match target_task.await.context("target resolution task")? {
15683                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15684                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15685                    TargetTaskResult::Location(Some(target)) => target,
15686                };
15687
15688                editor.update_in(cx, |editor, window, cx| {
15689                    let Some(workspace) = editor.workspace() else {
15690                        return Navigated::No;
15691                    };
15692                    let pane = workspace.read(cx).active_pane().clone();
15693
15694                    let range = target.range.to_point(target.buffer.read(cx));
15695                    let range = editor.range_for_match(&range);
15696                    let range = collapse_multiline_range(range);
15697
15698                    if !split
15699                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15700                    {
15701                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15702                    } else {
15703                        window.defer(cx, move |window, cx| {
15704                            let target_editor: Entity<Self> =
15705                                workspace.update(cx, |workspace, cx| {
15706                                    let pane = if split {
15707                                        workspace.adjacent_pane(window, cx)
15708                                    } else {
15709                                        workspace.active_pane().clone()
15710                                    };
15711
15712                                    workspace.open_project_item(
15713                                        pane,
15714                                        target.buffer.clone(),
15715                                        true,
15716                                        true,
15717                                        window,
15718                                        cx,
15719                                    )
15720                                });
15721                            target_editor.update(cx, |target_editor, cx| {
15722                                // When selecting a definition in a different buffer, disable the nav history
15723                                // to avoid creating a history entry at the previous cursor location.
15724                                pane.update(cx, |pane, _| pane.disable_history());
15725                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15726                                pane.update(cx, |pane, _| pane.enable_history());
15727                            });
15728                        });
15729                    }
15730                    Navigated::Yes
15731                })
15732            })
15733        } else if !definitions.is_empty() {
15734            cx.spawn_in(window, async move |editor, cx| {
15735                let (title, location_tasks, workspace) = editor
15736                    .update_in(cx, |editor, window, cx| {
15737                        let tab_kind = match kind {
15738                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15739                            _ => "Definitions",
15740                        };
15741                        let title = definitions
15742                            .iter()
15743                            .find_map(|definition| match definition {
15744                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15745                                    let buffer = origin.buffer.read(cx);
15746                                    format!(
15747                                        "{} for {}",
15748                                        tab_kind,
15749                                        buffer
15750                                            .text_for_range(origin.range.clone())
15751                                            .collect::<String>()
15752                                    )
15753                                }),
15754                                HoverLink::InlayHint(_, _) => None,
15755                                HoverLink::Url(_) => None,
15756                                HoverLink::File(_) => None,
15757                            })
15758                            .unwrap_or(tab_kind.to_string());
15759                        let location_tasks = definitions
15760                            .into_iter()
15761                            .map(|definition| match definition {
15762                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15763                                HoverLink::InlayHint(lsp_location, server_id) => editor
15764                                    .compute_target_location(lsp_location, server_id, window, cx),
15765                                HoverLink::Url(_) => Task::ready(Ok(None)),
15766                                HoverLink::File(_) => Task::ready(Ok(None)),
15767                            })
15768                            .collect::<Vec<_>>();
15769                        (title, location_tasks, editor.workspace().clone())
15770                    })
15771                    .context("location tasks preparation")?;
15772
15773                let locations: Vec<Location> = future::join_all(location_tasks)
15774                    .await
15775                    .into_iter()
15776                    .filter_map(|location| location.transpose())
15777                    .collect::<Result<_>>()
15778                    .context("location tasks")?;
15779
15780                if locations.is_empty() {
15781                    return Ok(Navigated::No);
15782                }
15783
15784                let Some(workspace) = workspace else {
15785                    return Ok(Navigated::No);
15786                };
15787
15788                let opened = workspace
15789                    .update_in(cx, |workspace, window, cx| {
15790                        Self::open_locations_in_multibuffer(
15791                            workspace,
15792                            locations,
15793                            title,
15794                            split,
15795                            MultibufferSelectionMode::First,
15796                            window,
15797                            cx,
15798                        )
15799                    })
15800                    .ok();
15801
15802                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15803            })
15804        } else {
15805            Task::ready(Ok(Navigated::No))
15806        }
15807    }
15808
15809    fn compute_target_location(
15810        &self,
15811        lsp_location: lsp::Location,
15812        server_id: LanguageServerId,
15813        window: &mut Window,
15814        cx: &mut Context<Self>,
15815    ) -> Task<anyhow::Result<Option<Location>>> {
15816        let Some(project) = self.project.clone() else {
15817            return Task::ready(Ok(None));
15818        };
15819
15820        cx.spawn_in(window, async move |editor, cx| {
15821            let location_task = editor.update(cx, |_, cx| {
15822                project.update(cx, |project, cx| {
15823                    let language_server_name = project
15824                        .language_server_statuses(cx)
15825                        .find(|(id, _)| server_id == *id)
15826                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15827                    language_server_name.map(|language_server_name| {
15828                        project.open_local_buffer_via_lsp(
15829                            lsp_location.uri.clone(),
15830                            server_id,
15831                            language_server_name,
15832                            cx,
15833                        )
15834                    })
15835                })
15836            })?;
15837            let location = match location_task {
15838                Some(task) => Some({
15839                    let target_buffer_handle = task.await.context("open local buffer")?;
15840                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15841                        let target_start = target_buffer
15842                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15843                        let target_end = target_buffer
15844                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15845                        target_buffer.anchor_after(target_start)
15846                            ..target_buffer.anchor_before(target_end)
15847                    })?;
15848                    Location {
15849                        buffer: target_buffer_handle,
15850                        range,
15851                    }
15852                }),
15853                None => None,
15854            };
15855            Ok(location)
15856        })
15857    }
15858
15859    pub fn find_all_references(
15860        &mut self,
15861        _: &FindAllReferences,
15862        window: &mut Window,
15863        cx: &mut Context<Self>,
15864    ) -> Option<Task<Result<Navigated>>> {
15865        let selection = self.selections.newest::<usize>(cx);
15866        let multi_buffer = self.buffer.read(cx);
15867        let head = selection.head();
15868
15869        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15870        let head_anchor = multi_buffer_snapshot.anchor_at(
15871            head,
15872            if head < selection.tail() {
15873                Bias::Right
15874            } else {
15875                Bias::Left
15876            },
15877        );
15878
15879        match self
15880            .find_all_references_task_sources
15881            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15882        {
15883            Ok(_) => {
15884                log::info!(
15885                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15886                );
15887                return None;
15888            }
15889            Err(i) => {
15890                self.find_all_references_task_sources.insert(i, head_anchor);
15891            }
15892        }
15893
15894        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15895        let workspace = self.workspace()?;
15896        let project = workspace.read(cx).project().clone();
15897        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15898        Some(cx.spawn_in(window, async move |editor, cx| {
15899            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15900                if let Ok(i) = editor
15901                    .find_all_references_task_sources
15902                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15903                {
15904                    editor.find_all_references_task_sources.remove(i);
15905                }
15906            });
15907
15908            let locations = references.await?;
15909            if locations.is_empty() {
15910                return anyhow::Ok(Navigated::No);
15911            }
15912
15913            workspace.update_in(cx, |workspace, window, cx| {
15914                let title = locations
15915                    .first()
15916                    .as_ref()
15917                    .map(|location| {
15918                        let buffer = location.buffer.read(cx);
15919                        format!(
15920                            "References to `{}`",
15921                            buffer
15922                                .text_for_range(location.range.clone())
15923                                .collect::<String>()
15924                        )
15925                    })
15926                    .unwrap();
15927                Self::open_locations_in_multibuffer(
15928                    workspace,
15929                    locations,
15930                    title,
15931                    false,
15932                    MultibufferSelectionMode::First,
15933                    window,
15934                    cx,
15935                );
15936                Navigated::Yes
15937            })
15938        }))
15939    }
15940
15941    /// Opens a multibuffer with the given project locations in it
15942    pub fn open_locations_in_multibuffer(
15943        workspace: &mut Workspace,
15944        mut locations: Vec<Location>,
15945        title: String,
15946        split: bool,
15947        multibuffer_selection_mode: MultibufferSelectionMode,
15948        window: &mut Window,
15949        cx: &mut Context<Workspace>,
15950    ) {
15951        if locations.is_empty() {
15952            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15953            return;
15954        }
15955
15956        // If there are multiple definitions, open them in a multibuffer
15957        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15958        let mut locations = locations.into_iter().peekable();
15959        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15960        let capability = workspace.project().read(cx).capability();
15961
15962        let excerpt_buffer = cx.new(|cx| {
15963            let mut multibuffer = MultiBuffer::new(capability);
15964            while let Some(location) = locations.next() {
15965                let buffer = location.buffer.read(cx);
15966                let mut ranges_for_buffer = Vec::new();
15967                let range = location.range.to_point(buffer);
15968                ranges_for_buffer.push(range.clone());
15969
15970                while let Some(next_location) = locations.peek() {
15971                    if next_location.buffer == location.buffer {
15972                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15973                        locations.next();
15974                    } else {
15975                        break;
15976                    }
15977                }
15978
15979                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15980                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15981                    PathKey::for_buffer(&location.buffer, cx),
15982                    location.buffer.clone(),
15983                    ranges_for_buffer,
15984                    DEFAULT_MULTIBUFFER_CONTEXT,
15985                    cx,
15986                );
15987                ranges.extend(new_ranges)
15988            }
15989
15990            multibuffer.with_title(title)
15991        });
15992
15993        let editor = cx.new(|cx| {
15994            Editor::for_multibuffer(
15995                excerpt_buffer,
15996                Some(workspace.project().clone()),
15997                window,
15998                cx,
15999            )
16000        });
16001        editor.update(cx, |editor, cx| {
16002            match multibuffer_selection_mode {
16003                MultibufferSelectionMode::First => {
16004                    if let Some(first_range) = ranges.first() {
16005                        editor.change_selections(
16006                            SelectionEffects::no_scroll(),
16007                            window,
16008                            cx,
16009                            |selections| {
16010                                selections.clear_disjoint();
16011                                selections
16012                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16013                            },
16014                        );
16015                    }
16016                    editor.highlight_background::<Self>(
16017                        &ranges,
16018                        |theme| theme.colors().editor_highlighted_line_background,
16019                        cx,
16020                    );
16021                }
16022                MultibufferSelectionMode::All => {
16023                    editor.change_selections(
16024                        SelectionEffects::no_scroll(),
16025                        window,
16026                        cx,
16027                        |selections| {
16028                            selections.clear_disjoint();
16029                            selections.select_anchor_ranges(ranges);
16030                        },
16031                    );
16032                }
16033            }
16034            editor.register_buffers_with_language_servers(cx);
16035        });
16036
16037        let item = Box::new(editor);
16038        let item_id = item.item_id();
16039
16040        if split {
16041            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16042        } else {
16043            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16044                let (preview_item_id, preview_item_idx) =
16045                    workspace.active_pane().read_with(cx, |pane, _| {
16046                        (pane.preview_item_id(), pane.preview_item_idx())
16047                    });
16048
16049                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16050
16051                if let Some(preview_item_id) = preview_item_id {
16052                    workspace.active_pane().update(cx, |pane, cx| {
16053                        pane.remove_item(preview_item_id, false, false, window, cx);
16054                    });
16055                }
16056            } else {
16057                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16058            }
16059        }
16060        workspace.active_pane().update(cx, |pane, cx| {
16061            pane.set_preview_item_id(Some(item_id), cx);
16062        });
16063    }
16064
16065    pub fn rename(
16066        &mut self,
16067        _: &Rename,
16068        window: &mut Window,
16069        cx: &mut Context<Self>,
16070    ) -> Option<Task<Result<()>>> {
16071        use language::ToOffset as _;
16072
16073        let provider = self.semantics_provider.clone()?;
16074        let selection = self.selections.newest_anchor().clone();
16075        let (cursor_buffer, cursor_buffer_position) = self
16076            .buffer
16077            .read(cx)
16078            .text_anchor_for_position(selection.head(), cx)?;
16079        let (tail_buffer, cursor_buffer_position_end) = self
16080            .buffer
16081            .read(cx)
16082            .text_anchor_for_position(selection.tail(), cx)?;
16083        if tail_buffer != cursor_buffer {
16084            return None;
16085        }
16086
16087        let snapshot = cursor_buffer.read(cx).snapshot();
16088        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16089        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16090        let prepare_rename = provider
16091            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16092            .unwrap_or_else(|| Task::ready(Ok(None)));
16093        drop(snapshot);
16094
16095        Some(cx.spawn_in(window, async move |this, cx| {
16096            let rename_range = if let Some(range) = prepare_rename.await? {
16097                Some(range)
16098            } else {
16099                this.update(cx, |this, cx| {
16100                    let buffer = this.buffer.read(cx).snapshot(cx);
16101                    let mut buffer_highlights = this
16102                        .document_highlights_for_position(selection.head(), &buffer)
16103                        .filter(|highlight| {
16104                            highlight.start.excerpt_id == selection.head().excerpt_id
16105                                && highlight.end.excerpt_id == selection.head().excerpt_id
16106                        });
16107                    buffer_highlights
16108                        .next()
16109                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16110                })?
16111            };
16112            if let Some(rename_range) = rename_range {
16113                this.update_in(cx, |this, window, cx| {
16114                    let snapshot = cursor_buffer.read(cx).snapshot();
16115                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16116                    let cursor_offset_in_rename_range =
16117                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16118                    let cursor_offset_in_rename_range_end =
16119                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16120
16121                    this.take_rename(false, window, cx);
16122                    let buffer = this.buffer.read(cx).read(cx);
16123                    let cursor_offset = selection.head().to_offset(&buffer);
16124                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16125                    let rename_end = rename_start + rename_buffer_range.len();
16126                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16127                    let mut old_highlight_id = None;
16128                    let old_name: Arc<str> = buffer
16129                        .chunks(rename_start..rename_end, true)
16130                        .map(|chunk| {
16131                            if old_highlight_id.is_none() {
16132                                old_highlight_id = chunk.syntax_highlight_id;
16133                            }
16134                            chunk.text
16135                        })
16136                        .collect::<String>()
16137                        .into();
16138
16139                    drop(buffer);
16140
16141                    // Position the selection in the rename editor so that it matches the current selection.
16142                    this.show_local_selections = false;
16143                    let rename_editor = cx.new(|cx| {
16144                        let mut editor = Editor::single_line(window, cx);
16145                        editor.buffer.update(cx, |buffer, cx| {
16146                            buffer.edit([(0..0, old_name.clone())], None, cx)
16147                        });
16148                        let rename_selection_range = match cursor_offset_in_rename_range
16149                            .cmp(&cursor_offset_in_rename_range_end)
16150                        {
16151                            Ordering::Equal => {
16152                                editor.select_all(&SelectAll, window, cx);
16153                                return editor;
16154                            }
16155                            Ordering::Less => {
16156                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16157                            }
16158                            Ordering::Greater => {
16159                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16160                            }
16161                        };
16162                        if rename_selection_range.end > old_name.len() {
16163                            editor.select_all(&SelectAll, window, cx);
16164                        } else {
16165                            editor.change_selections(Default::default(), window, cx, |s| {
16166                                s.select_ranges([rename_selection_range]);
16167                            });
16168                        }
16169                        editor
16170                    });
16171                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16172                        if e == &EditorEvent::Focused {
16173                            cx.emit(EditorEvent::FocusedIn)
16174                        }
16175                    })
16176                    .detach();
16177
16178                    let write_highlights =
16179                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16180                    let read_highlights =
16181                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16182                    let ranges = write_highlights
16183                        .iter()
16184                        .flat_map(|(_, ranges)| ranges.iter())
16185                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16186                        .cloned()
16187                        .collect();
16188
16189                    this.highlight_text::<Rename>(
16190                        ranges,
16191                        HighlightStyle {
16192                            fade_out: Some(0.6),
16193                            ..Default::default()
16194                        },
16195                        cx,
16196                    );
16197                    let rename_focus_handle = rename_editor.focus_handle(cx);
16198                    window.focus(&rename_focus_handle);
16199                    let block_id = this.insert_blocks(
16200                        [BlockProperties {
16201                            style: BlockStyle::Flex,
16202                            placement: BlockPlacement::Below(range.start),
16203                            height: Some(1),
16204                            render: Arc::new({
16205                                let rename_editor = rename_editor.clone();
16206                                move |cx: &mut BlockContext| {
16207                                    let mut text_style = cx.editor_style.text.clone();
16208                                    if let Some(highlight_style) = old_highlight_id
16209                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16210                                    {
16211                                        text_style = text_style.highlight(highlight_style);
16212                                    }
16213                                    div()
16214                                        .block_mouse_except_scroll()
16215                                        .pl(cx.anchor_x)
16216                                        .child(EditorElement::new(
16217                                            &rename_editor,
16218                                            EditorStyle {
16219                                                background: cx.theme().system().transparent,
16220                                                local_player: cx.editor_style.local_player,
16221                                                text: text_style,
16222                                                scrollbar_width: cx.editor_style.scrollbar_width,
16223                                                syntax: cx.editor_style.syntax.clone(),
16224                                                status: cx.editor_style.status.clone(),
16225                                                inlay_hints_style: HighlightStyle {
16226                                                    font_weight: Some(FontWeight::BOLD),
16227                                                    ..make_inlay_hints_style(cx.app)
16228                                                },
16229                                                inline_completion_styles: make_suggestion_styles(
16230                                                    cx.app,
16231                                                ),
16232                                                ..EditorStyle::default()
16233                                            },
16234                                        ))
16235                                        .into_any_element()
16236                                }
16237                            }),
16238                            priority: 0,
16239                        }],
16240                        Some(Autoscroll::fit()),
16241                        cx,
16242                    )[0];
16243                    this.pending_rename = Some(RenameState {
16244                        range,
16245                        old_name,
16246                        editor: rename_editor,
16247                        block_id,
16248                    });
16249                })?;
16250            }
16251
16252            Ok(())
16253        }))
16254    }
16255
16256    pub fn confirm_rename(
16257        &mut self,
16258        _: &ConfirmRename,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) -> Option<Task<Result<()>>> {
16262        let rename = self.take_rename(false, window, cx)?;
16263        let workspace = self.workspace()?.downgrade();
16264        let (buffer, start) = self
16265            .buffer
16266            .read(cx)
16267            .text_anchor_for_position(rename.range.start, cx)?;
16268        let (end_buffer, _) = self
16269            .buffer
16270            .read(cx)
16271            .text_anchor_for_position(rename.range.end, cx)?;
16272        if buffer != end_buffer {
16273            return None;
16274        }
16275
16276        let old_name = rename.old_name;
16277        let new_name = rename.editor.read(cx).text(cx);
16278
16279        let rename = self.semantics_provider.as_ref()?.perform_rename(
16280            &buffer,
16281            start,
16282            new_name.clone(),
16283            cx,
16284        )?;
16285
16286        Some(cx.spawn_in(window, async move |editor, cx| {
16287            let project_transaction = rename.await?;
16288            Self::open_project_transaction(
16289                &editor,
16290                workspace,
16291                project_transaction,
16292                format!("Rename: {}{}", old_name, new_name),
16293                cx,
16294            )
16295            .await?;
16296
16297            editor.update(cx, |editor, cx| {
16298                editor.refresh_document_highlights(cx);
16299            })?;
16300            Ok(())
16301        }))
16302    }
16303
16304    fn take_rename(
16305        &mut self,
16306        moving_cursor: bool,
16307        window: &mut Window,
16308        cx: &mut Context<Self>,
16309    ) -> Option<RenameState> {
16310        let rename = self.pending_rename.take()?;
16311        if rename.editor.focus_handle(cx).is_focused(window) {
16312            window.focus(&self.focus_handle);
16313        }
16314
16315        self.remove_blocks(
16316            [rename.block_id].into_iter().collect(),
16317            Some(Autoscroll::fit()),
16318            cx,
16319        );
16320        self.clear_highlights::<Rename>(cx);
16321        self.show_local_selections = true;
16322
16323        if moving_cursor {
16324            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16325                editor.selections.newest::<usize>(cx).head()
16326            });
16327
16328            // Update the selection to match the position of the selection inside
16329            // the rename editor.
16330            let snapshot = self.buffer.read(cx).read(cx);
16331            let rename_range = rename.range.to_offset(&snapshot);
16332            let cursor_in_editor = snapshot
16333                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16334                .min(rename_range.end);
16335            drop(snapshot);
16336
16337            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16338                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16339            });
16340        } else {
16341            self.refresh_document_highlights(cx);
16342        }
16343
16344        Some(rename)
16345    }
16346
16347    pub fn pending_rename(&self) -> Option<&RenameState> {
16348        self.pending_rename.as_ref()
16349    }
16350
16351    fn format(
16352        &mut self,
16353        _: &Format,
16354        window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) -> Option<Task<Result<()>>> {
16357        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16358
16359        let project = match &self.project {
16360            Some(project) => project.clone(),
16361            None => return None,
16362        };
16363
16364        Some(self.perform_format(
16365            project,
16366            FormatTrigger::Manual,
16367            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16368            window,
16369            cx,
16370        ))
16371    }
16372
16373    fn format_selections(
16374        &mut self,
16375        _: &FormatSelections,
16376        window: &mut Window,
16377        cx: &mut Context<Self>,
16378    ) -> Option<Task<Result<()>>> {
16379        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16380
16381        let project = match &self.project {
16382            Some(project) => project.clone(),
16383            None => return None,
16384        };
16385
16386        let ranges = self
16387            .selections
16388            .all_adjusted(cx)
16389            .into_iter()
16390            .map(|selection| selection.range())
16391            .collect_vec();
16392
16393        Some(self.perform_format(
16394            project,
16395            FormatTrigger::Manual,
16396            FormatTarget::Ranges(ranges),
16397            window,
16398            cx,
16399        ))
16400    }
16401
16402    fn perform_format(
16403        &mut self,
16404        project: Entity<Project>,
16405        trigger: FormatTrigger,
16406        target: FormatTarget,
16407        window: &mut Window,
16408        cx: &mut Context<Self>,
16409    ) -> Task<Result<()>> {
16410        let buffer = self.buffer.clone();
16411        let (buffers, target) = match target {
16412            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16413            FormatTarget::Ranges(selection_ranges) => {
16414                let multi_buffer = buffer.read(cx);
16415                let snapshot = multi_buffer.read(cx);
16416                let mut buffers = HashSet::default();
16417                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16418                    BTreeMap::new();
16419                for selection_range in selection_ranges {
16420                    for (buffer, buffer_range, _) in
16421                        snapshot.range_to_buffer_ranges(selection_range)
16422                    {
16423                        let buffer_id = buffer.remote_id();
16424                        let start = buffer.anchor_before(buffer_range.start);
16425                        let end = buffer.anchor_after(buffer_range.end);
16426                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16427                        buffer_id_to_ranges
16428                            .entry(buffer_id)
16429                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16430                            .or_insert_with(|| vec![start..end]);
16431                    }
16432                }
16433                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16434            }
16435        };
16436
16437        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16438        let selections_prev = transaction_id_prev
16439            .and_then(|transaction_id_prev| {
16440                // default to selections as they were after the last edit, if we have them,
16441                // instead of how they are now.
16442                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16443                // will take you back to where you made the last edit, instead of staying where you scrolled
16444                self.selection_history
16445                    .transaction(transaction_id_prev)
16446                    .map(|t| t.0.clone())
16447            })
16448            .unwrap_or_else(|| {
16449                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16450                self.selections.disjoint_anchors()
16451            });
16452
16453        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16454        let format = project.update(cx, |project, cx| {
16455            project.format(buffers, target, true, trigger, cx)
16456        });
16457
16458        cx.spawn_in(window, async move |editor, cx| {
16459            let transaction = futures::select_biased! {
16460                transaction = format.log_err().fuse() => transaction,
16461                () = timeout => {
16462                    log::warn!("timed out waiting for formatting");
16463                    None
16464                }
16465            };
16466
16467            buffer
16468                .update(cx, |buffer, cx| {
16469                    if let Some(transaction) = transaction {
16470                        if !buffer.is_singleton() {
16471                            buffer.push_transaction(&transaction.0, cx);
16472                        }
16473                    }
16474                    cx.notify();
16475                })
16476                .ok();
16477
16478            if let Some(transaction_id_now) =
16479                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16480            {
16481                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16482                if has_new_transaction {
16483                    _ = editor.update(cx, |editor, _| {
16484                        editor
16485                            .selection_history
16486                            .insert_transaction(transaction_id_now, selections_prev);
16487                    });
16488                }
16489            }
16490
16491            Ok(())
16492        })
16493    }
16494
16495    fn organize_imports(
16496        &mut self,
16497        _: &OrganizeImports,
16498        window: &mut Window,
16499        cx: &mut Context<Self>,
16500    ) -> Option<Task<Result<()>>> {
16501        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16502        let project = match &self.project {
16503            Some(project) => project.clone(),
16504            None => return None,
16505        };
16506        Some(self.perform_code_action_kind(
16507            project,
16508            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16509            window,
16510            cx,
16511        ))
16512    }
16513
16514    fn perform_code_action_kind(
16515        &mut self,
16516        project: Entity<Project>,
16517        kind: CodeActionKind,
16518        window: &mut Window,
16519        cx: &mut Context<Self>,
16520    ) -> Task<Result<()>> {
16521        let buffer = self.buffer.clone();
16522        let buffers = buffer.read(cx).all_buffers();
16523        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16524        let apply_action = project.update(cx, |project, cx| {
16525            project.apply_code_action_kind(buffers, kind, true, cx)
16526        });
16527        cx.spawn_in(window, async move |_, cx| {
16528            let transaction = futures::select_biased! {
16529                () = timeout => {
16530                    log::warn!("timed out waiting for executing code action");
16531                    None
16532                }
16533                transaction = apply_action.log_err().fuse() => transaction,
16534            };
16535            buffer
16536                .update(cx, |buffer, cx| {
16537                    // check if we need this
16538                    if let Some(transaction) = transaction {
16539                        if !buffer.is_singleton() {
16540                            buffer.push_transaction(&transaction.0, cx);
16541                        }
16542                    }
16543                    cx.notify();
16544                })
16545                .ok();
16546            Ok(())
16547        })
16548    }
16549
16550    pub fn restart_language_server(
16551        &mut self,
16552        _: &RestartLanguageServer,
16553        _: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) {
16556        if let Some(project) = self.project.clone() {
16557            self.buffer.update(cx, |multi_buffer, cx| {
16558                project.update(cx, |project, cx| {
16559                    project.restart_language_servers_for_buffers(
16560                        multi_buffer.all_buffers().into_iter().collect(),
16561                        HashSet::default(),
16562                        cx,
16563                    );
16564                });
16565            })
16566        }
16567    }
16568
16569    pub fn stop_language_server(
16570        &mut self,
16571        _: &StopLanguageServer,
16572        _: &mut Window,
16573        cx: &mut Context<Self>,
16574    ) {
16575        if let Some(project) = self.project.clone() {
16576            self.buffer.update(cx, |multi_buffer, cx| {
16577                project.update(cx, |project, cx| {
16578                    project.stop_language_servers_for_buffers(
16579                        multi_buffer.all_buffers().into_iter().collect(),
16580                        HashSet::default(),
16581                        cx,
16582                    );
16583                    cx.emit(project::Event::RefreshInlayHints);
16584                });
16585            });
16586        }
16587    }
16588
16589    fn cancel_language_server_work(
16590        workspace: &mut Workspace,
16591        _: &actions::CancelLanguageServerWork,
16592        _: &mut Window,
16593        cx: &mut Context<Workspace>,
16594    ) {
16595        let project = workspace.project();
16596        let buffers = workspace
16597            .active_item(cx)
16598            .and_then(|item| item.act_as::<Editor>(cx))
16599            .map_or(HashSet::default(), |editor| {
16600                editor.read(cx).buffer.read(cx).all_buffers()
16601            });
16602        project.update(cx, |project, cx| {
16603            project.cancel_language_server_work_for_buffers(buffers, cx);
16604        });
16605    }
16606
16607    fn show_character_palette(
16608        &mut self,
16609        _: &ShowCharacterPalette,
16610        window: &mut Window,
16611        _: &mut Context<Self>,
16612    ) {
16613        window.show_character_palette();
16614    }
16615
16616    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16617        if !self.diagnostics_enabled() {
16618            return;
16619        }
16620
16621        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16622            let buffer = self.buffer.read(cx).snapshot(cx);
16623            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16624            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16625            let is_valid = buffer
16626                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16627                .any(|entry| {
16628                    entry.diagnostic.is_primary
16629                        && !entry.range.is_empty()
16630                        && entry.range.start == primary_range_start
16631                        && entry.diagnostic.message == active_diagnostics.active_message
16632                });
16633
16634            if !is_valid {
16635                self.dismiss_diagnostics(cx);
16636            }
16637        }
16638    }
16639
16640    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16641        match &self.active_diagnostics {
16642            ActiveDiagnostic::Group(group) => Some(group),
16643            _ => None,
16644        }
16645    }
16646
16647    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16648        if !self.diagnostics_enabled() {
16649            return;
16650        }
16651        self.dismiss_diagnostics(cx);
16652        self.active_diagnostics = ActiveDiagnostic::All;
16653    }
16654
16655    fn activate_diagnostics(
16656        &mut self,
16657        buffer_id: BufferId,
16658        diagnostic: DiagnosticEntry<usize>,
16659        window: &mut Window,
16660        cx: &mut Context<Self>,
16661    ) {
16662        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16663            return;
16664        }
16665        self.dismiss_diagnostics(cx);
16666        let snapshot = self.snapshot(window, cx);
16667        let buffer = self.buffer.read(cx).snapshot(cx);
16668        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16669            return;
16670        };
16671
16672        let diagnostic_group = buffer
16673            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16674            .collect::<Vec<_>>();
16675
16676        let blocks =
16677            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16678
16679        let blocks = self.display_map.update(cx, |display_map, cx| {
16680            display_map.insert_blocks(blocks, cx).into_iter().collect()
16681        });
16682        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16683            active_range: buffer.anchor_before(diagnostic.range.start)
16684                ..buffer.anchor_after(diagnostic.range.end),
16685            active_message: diagnostic.diagnostic.message.clone(),
16686            group_id: diagnostic.diagnostic.group_id,
16687            blocks,
16688        });
16689        cx.notify();
16690    }
16691
16692    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16693        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16694            return;
16695        };
16696
16697        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16698        if let ActiveDiagnostic::Group(group) = prev {
16699            self.display_map.update(cx, |display_map, cx| {
16700                display_map.remove_blocks(group.blocks, cx);
16701            });
16702            cx.notify();
16703        }
16704    }
16705
16706    /// Disable inline diagnostics rendering for this editor.
16707    pub fn disable_inline_diagnostics(&mut self) {
16708        self.inline_diagnostics_enabled = false;
16709        self.inline_diagnostics_update = Task::ready(());
16710        self.inline_diagnostics.clear();
16711    }
16712
16713    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16714        self.diagnostics_enabled = false;
16715        self.dismiss_diagnostics(cx);
16716        self.inline_diagnostics_update = Task::ready(());
16717        self.inline_diagnostics.clear();
16718    }
16719
16720    pub fn diagnostics_enabled(&self) -> bool {
16721        self.diagnostics_enabled && self.mode.is_full()
16722    }
16723
16724    pub fn inline_diagnostics_enabled(&self) -> bool {
16725        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16726    }
16727
16728    pub fn show_inline_diagnostics(&self) -> bool {
16729        self.show_inline_diagnostics
16730    }
16731
16732    pub fn toggle_inline_diagnostics(
16733        &mut self,
16734        _: &ToggleInlineDiagnostics,
16735        window: &mut Window,
16736        cx: &mut Context<Editor>,
16737    ) {
16738        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16739        self.refresh_inline_diagnostics(false, window, cx);
16740    }
16741
16742    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16743        self.diagnostics_max_severity = severity;
16744        self.display_map.update(cx, |display_map, _| {
16745            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16746        });
16747    }
16748
16749    pub fn toggle_diagnostics(
16750        &mut self,
16751        _: &ToggleDiagnostics,
16752        window: &mut Window,
16753        cx: &mut Context<Editor>,
16754    ) {
16755        if !self.diagnostics_enabled() {
16756            return;
16757        }
16758
16759        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16760            EditorSettings::get_global(cx)
16761                .diagnostics_max_severity
16762                .filter(|severity| severity != &DiagnosticSeverity::Off)
16763                .unwrap_or(DiagnosticSeverity::Hint)
16764        } else {
16765            DiagnosticSeverity::Off
16766        };
16767        self.set_max_diagnostics_severity(new_severity, cx);
16768        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16769            self.active_diagnostics = ActiveDiagnostic::None;
16770            self.inline_diagnostics_update = Task::ready(());
16771            self.inline_diagnostics.clear();
16772        } else {
16773            self.refresh_inline_diagnostics(false, window, cx);
16774        }
16775
16776        cx.notify();
16777    }
16778
16779    pub fn toggle_minimap(
16780        &mut self,
16781        _: &ToggleMinimap,
16782        window: &mut Window,
16783        cx: &mut Context<Editor>,
16784    ) {
16785        if self.supports_minimap(cx) {
16786            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16787        }
16788    }
16789
16790    fn refresh_inline_diagnostics(
16791        &mut self,
16792        debounce: bool,
16793        window: &mut Window,
16794        cx: &mut Context<Self>,
16795    ) {
16796        let max_severity = ProjectSettings::get_global(cx)
16797            .diagnostics
16798            .inline
16799            .max_severity
16800            .unwrap_or(self.diagnostics_max_severity);
16801
16802        if !self.inline_diagnostics_enabled()
16803            || !self.show_inline_diagnostics
16804            || max_severity == DiagnosticSeverity::Off
16805        {
16806            self.inline_diagnostics_update = Task::ready(());
16807            self.inline_diagnostics.clear();
16808            return;
16809        }
16810
16811        let debounce_ms = ProjectSettings::get_global(cx)
16812            .diagnostics
16813            .inline
16814            .update_debounce_ms;
16815        let debounce = if debounce && debounce_ms > 0 {
16816            Some(Duration::from_millis(debounce_ms))
16817        } else {
16818            None
16819        };
16820        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16821            if let Some(debounce) = debounce {
16822                cx.background_executor().timer(debounce).await;
16823            }
16824            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16825                editor
16826                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16827                    .ok()
16828            }) else {
16829                return;
16830            };
16831
16832            let new_inline_diagnostics = cx
16833                .background_spawn(async move {
16834                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16835                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16836                        let message = diagnostic_entry
16837                            .diagnostic
16838                            .message
16839                            .split_once('\n')
16840                            .map(|(line, _)| line)
16841                            .map(SharedString::new)
16842                            .unwrap_or_else(|| {
16843                                SharedString::from(diagnostic_entry.diagnostic.message)
16844                            });
16845                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16846                        let (Ok(i) | Err(i)) = inline_diagnostics
16847                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16848                        inline_diagnostics.insert(
16849                            i,
16850                            (
16851                                start_anchor,
16852                                InlineDiagnostic {
16853                                    message,
16854                                    group_id: diagnostic_entry.diagnostic.group_id,
16855                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16856                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16857                                    severity: diagnostic_entry.diagnostic.severity,
16858                                },
16859                            ),
16860                        );
16861                    }
16862                    inline_diagnostics
16863                })
16864                .await;
16865
16866            editor
16867                .update(cx, |editor, cx| {
16868                    editor.inline_diagnostics = new_inline_diagnostics;
16869                    cx.notify();
16870                })
16871                .ok();
16872        });
16873    }
16874
16875    fn pull_diagnostics(
16876        &mut self,
16877        buffer_id: Option<BufferId>,
16878        window: &Window,
16879        cx: &mut Context<Self>,
16880    ) -> Option<()> {
16881        if !self.mode().is_full() {
16882            return None;
16883        }
16884        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16885            .diagnostics
16886            .lsp_pull_diagnostics;
16887        if !pull_diagnostics_settings.enabled {
16888            return None;
16889        }
16890        let project = self.project.as_ref()?.downgrade();
16891        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16892        let mut buffers = self.buffer.read(cx).all_buffers();
16893        if let Some(buffer_id) = buffer_id {
16894            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16895        }
16896
16897        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16898            cx.background_executor().timer(debounce).await;
16899
16900            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16901                buffers
16902                    .into_iter()
16903                    .filter_map(|buffer| {
16904                        project
16905                            .update(cx, |project, cx| {
16906                                project.lsp_store().update(cx, |lsp_store, cx| {
16907                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16908                                })
16909                            })
16910                            .ok()
16911                    })
16912                    .collect::<FuturesUnordered<_>>()
16913            }) else {
16914                return;
16915            };
16916
16917            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16918                match pull_task {
16919                    Ok(()) => {
16920                        if editor
16921                            .update_in(cx, |editor, window, cx| {
16922                                editor.update_diagnostics_state(window, cx);
16923                            })
16924                            .is_err()
16925                        {
16926                            return;
16927                        }
16928                    }
16929                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16930                }
16931            }
16932        });
16933
16934        Some(())
16935    }
16936
16937    pub fn set_selections_from_remote(
16938        &mut self,
16939        selections: Vec<Selection<Anchor>>,
16940        pending_selection: Option<Selection<Anchor>>,
16941        window: &mut Window,
16942        cx: &mut Context<Self>,
16943    ) {
16944        let old_cursor_position = self.selections.newest_anchor().head();
16945        self.selections.change_with(cx, |s| {
16946            s.select_anchors(selections);
16947            if let Some(pending_selection) = pending_selection {
16948                s.set_pending(pending_selection, SelectMode::Character);
16949            } else {
16950                s.clear_pending();
16951            }
16952        });
16953        self.selections_did_change(
16954            false,
16955            &old_cursor_position,
16956            SelectionEffects::default(),
16957            window,
16958            cx,
16959        );
16960    }
16961
16962    pub fn transact(
16963        &mut self,
16964        window: &mut Window,
16965        cx: &mut Context<Self>,
16966        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16967    ) -> Option<TransactionId> {
16968        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16969            this.start_transaction_at(Instant::now(), window, cx);
16970            update(this, window, cx);
16971            this.end_transaction_at(Instant::now(), cx)
16972        })
16973    }
16974
16975    pub fn start_transaction_at(
16976        &mut self,
16977        now: Instant,
16978        window: &mut Window,
16979        cx: &mut Context<Self>,
16980    ) -> Option<TransactionId> {
16981        self.end_selection(window, cx);
16982        if let Some(tx_id) = self
16983            .buffer
16984            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16985        {
16986            self.selection_history
16987                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16988            cx.emit(EditorEvent::TransactionBegun {
16989                transaction_id: tx_id,
16990            });
16991            Some(tx_id)
16992        } else {
16993            None
16994        }
16995    }
16996
16997    pub fn end_transaction_at(
16998        &mut self,
16999        now: Instant,
17000        cx: &mut Context<Self>,
17001    ) -> Option<TransactionId> {
17002        if let Some(transaction_id) = self
17003            .buffer
17004            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17005        {
17006            if let Some((_, end_selections)) =
17007                self.selection_history.transaction_mut(transaction_id)
17008            {
17009                *end_selections = Some(self.selections.disjoint_anchors());
17010            } else {
17011                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17012            }
17013
17014            cx.emit(EditorEvent::Edited { transaction_id });
17015            Some(transaction_id)
17016        } else {
17017            None
17018        }
17019    }
17020
17021    pub fn modify_transaction_selection_history(
17022        &mut self,
17023        transaction_id: TransactionId,
17024        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17025    ) -> bool {
17026        self.selection_history
17027            .transaction_mut(transaction_id)
17028            .map(modify)
17029            .is_some()
17030    }
17031
17032    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17033        if self.selection_mark_mode {
17034            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17035                s.move_with(|_, sel| {
17036                    sel.collapse_to(sel.head(), SelectionGoal::None);
17037                });
17038            })
17039        }
17040        self.selection_mark_mode = true;
17041        cx.notify();
17042    }
17043
17044    pub fn swap_selection_ends(
17045        &mut self,
17046        _: &actions::SwapSelectionEnds,
17047        window: &mut Window,
17048        cx: &mut Context<Self>,
17049    ) {
17050        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17051            s.move_with(|_, sel| {
17052                if sel.start != sel.end {
17053                    sel.reversed = !sel.reversed
17054                }
17055            });
17056        });
17057        self.request_autoscroll(Autoscroll::newest(), cx);
17058        cx.notify();
17059    }
17060
17061    pub fn toggle_focus(
17062        workspace: &mut Workspace,
17063        _: &actions::ToggleFocus,
17064        window: &mut Window,
17065        cx: &mut Context<Workspace>,
17066    ) {
17067        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17068            return;
17069        };
17070        workspace.activate_item(&item, true, true, window, cx);
17071    }
17072
17073    pub fn toggle_fold(
17074        &mut self,
17075        _: &actions::ToggleFold,
17076        window: &mut Window,
17077        cx: &mut Context<Self>,
17078    ) {
17079        if self.is_singleton(cx) {
17080            let selection = self.selections.newest::<Point>(cx);
17081
17082            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17083            let range = if selection.is_empty() {
17084                let point = selection.head().to_display_point(&display_map);
17085                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17086                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17087                    .to_point(&display_map);
17088                start..end
17089            } else {
17090                selection.range()
17091            };
17092            if display_map.folds_in_range(range).next().is_some() {
17093                self.unfold_lines(&Default::default(), window, cx)
17094            } else {
17095                self.fold(&Default::default(), window, cx)
17096            }
17097        } else {
17098            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17099            let buffer_ids: HashSet<_> = self
17100                .selections
17101                .disjoint_anchor_ranges()
17102                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17103                .collect();
17104
17105            let should_unfold = buffer_ids
17106                .iter()
17107                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17108
17109            for buffer_id in buffer_ids {
17110                if should_unfold {
17111                    self.unfold_buffer(buffer_id, cx);
17112                } else {
17113                    self.fold_buffer(buffer_id, cx);
17114                }
17115            }
17116        }
17117    }
17118
17119    pub fn toggle_fold_recursive(
17120        &mut self,
17121        _: &actions::ToggleFoldRecursive,
17122        window: &mut Window,
17123        cx: &mut Context<Self>,
17124    ) {
17125        let selection = self.selections.newest::<Point>(cx);
17126
17127        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17128        let range = if selection.is_empty() {
17129            let point = selection.head().to_display_point(&display_map);
17130            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17131            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17132                .to_point(&display_map);
17133            start..end
17134        } else {
17135            selection.range()
17136        };
17137        if display_map.folds_in_range(range).next().is_some() {
17138            self.unfold_recursive(&Default::default(), window, cx)
17139        } else {
17140            self.fold_recursive(&Default::default(), window, cx)
17141        }
17142    }
17143
17144    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17145        if self.is_singleton(cx) {
17146            let mut to_fold = Vec::new();
17147            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17148            let selections = self.selections.all_adjusted(cx);
17149
17150            for selection in selections {
17151                let range = selection.range().sorted();
17152                let buffer_start_row = range.start.row;
17153
17154                if range.start.row != range.end.row {
17155                    let mut found = false;
17156                    let mut row = range.start.row;
17157                    while row <= range.end.row {
17158                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17159                        {
17160                            found = true;
17161                            row = crease.range().end.row + 1;
17162                            to_fold.push(crease);
17163                        } else {
17164                            row += 1
17165                        }
17166                    }
17167                    if found {
17168                        continue;
17169                    }
17170                }
17171
17172                for row in (0..=range.start.row).rev() {
17173                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17174                        if crease.range().end.row >= buffer_start_row {
17175                            to_fold.push(crease);
17176                            if row <= range.start.row {
17177                                break;
17178                            }
17179                        }
17180                    }
17181                }
17182            }
17183
17184            self.fold_creases(to_fold, true, window, cx);
17185        } else {
17186            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17187            let buffer_ids = self
17188                .selections
17189                .disjoint_anchor_ranges()
17190                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17191                .collect::<HashSet<_>>();
17192            for buffer_id in buffer_ids {
17193                self.fold_buffer(buffer_id, cx);
17194            }
17195        }
17196    }
17197
17198    pub fn toggle_fold_all(
17199        &mut self,
17200        _: &actions::ToggleFoldAll,
17201        window: &mut Window,
17202        cx: &mut Context<Self>,
17203    ) {
17204        if self.buffer.read(cx).is_singleton() {
17205            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17206            let has_folds = display_map
17207                .folds_in_range(0..display_map.buffer_snapshot.len())
17208                .next()
17209                .is_some();
17210
17211            if has_folds {
17212                self.unfold_all(&actions::UnfoldAll, window, cx);
17213            } else {
17214                self.fold_all(&actions::FoldAll, window, cx);
17215            }
17216        } else {
17217            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17218            let should_unfold = buffer_ids
17219                .iter()
17220                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17221
17222            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17223                editor
17224                    .update_in(cx, |editor, _, cx| {
17225                        for buffer_id in buffer_ids {
17226                            if should_unfold {
17227                                editor.unfold_buffer(buffer_id, cx);
17228                            } else {
17229                                editor.fold_buffer(buffer_id, cx);
17230                            }
17231                        }
17232                    })
17233                    .ok();
17234            });
17235        }
17236    }
17237
17238    fn fold_at_level(
17239        &mut self,
17240        fold_at: &FoldAtLevel,
17241        window: &mut Window,
17242        cx: &mut Context<Self>,
17243    ) {
17244        if !self.buffer.read(cx).is_singleton() {
17245            return;
17246        }
17247
17248        let fold_at_level = fold_at.0;
17249        let snapshot = self.buffer.read(cx).snapshot(cx);
17250        let mut to_fold = Vec::new();
17251        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17252
17253        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17254            while start_row < end_row {
17255                match self
17256                    .snapshot(window, cx)
17257                    .crease_for_buffer_row(MultiBufferRow(start_row))
17258                {
17259                    Some(crease) => {
17260                        let nested_start_row = crease.range().start.row + 1;
17261                        let nested_end_row = crease.range().end.row;
17262
17263                        if current_level < fold_at_level {
17264                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17265                        } else if current_level == fold_at_level {
17266                            to_fold.push(crease);
17267                        }
17268
17269                        start_row = nested_end_row + 1;
17270                    }
17271                    None => start_row += 1,
17272                }
17273            }
17274        }
17275
17276        self.fold_creases(to_fold, true, window, cx);
17277    }
17278
17279    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17280        if self.buffer.read(cx).is_singleton() {
17281            let mut fold_ranges = Vec::new();
17282            let snapshot = self.buffer.read(cx).snapshot(cx);
17283
17284            for row in 0..snapshot.max_row().0 {
17285                if let Some(foldable_range) = self
17286                    .snapshot(window, cx)
17287                    .crease_for_buffer_row(MultiBufferRow(row))
17288                {
17289                    fold_ranges.push(foldable_range);
17290                }
17291            }
17292
17293            self.fold_creases(fold_ranges, true, window, cx);
17294        } else {
17295            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17296                editor
17297                    .update_in(cx, |editor, _, cx| {
17298                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17299                            editor.fold_buffer(buffer_id, cx);
17300                        }
17301                    })
17302                    .ok();
17303            });
17304        }
17305    }
17306
17307    pub fn fold_function_bodies(
17308        &mut self,
17309        _: &actions::FoldFunctionBodies,
17310        window: &mut Window,
17311        cx: &mut Context<Self>,
17312    ) {
17313        let snapshot = self.buffer.read(cx).snapshot(cx);
17314
17315        let ranges = snapshot
17316            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17317            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17318            .collect::<Vec<_>>();
17319
17320        let creases = ranges
17321            .into_iter()
17322            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17323            .collect();
17324
17325        self.fold_creases(creases, true, window, cx);
17326    }
17327
17328    pub fn fold_recursive(
17329        &mut self,
17330        _: &actions::FoldRecursive,
17331        window: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) {
17334        let mut to_fold = Vec::new();
17335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17336        let selections = self.selections.all_adjusted(cx);
17337
17338        for selection in selections {
17339            let range = selection.range().sorted();
17340            let buffer_start_row = range.start.row;
17341
17342            if range.start.row != range.end.row {
17343                let mut found = false;
17344                for row in range.start.row..=range.end.row {
17345                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17346                        found = true;
17347                        to_fold.push(crease);
17348                    }
17349                }
17350                if found {
17351                    continue;
17352                }
17353            }
17354
17355            for row in (0..=range.start.row).rev() {
17356                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17357                    if crease.range().end.row >= buffer_start_row {
17358                        to_fold.push(crease);
17359                    } else {
17360                        break;
17361                    }
17362                }
17363            }
17364        }
17365
17366        self.fold_creases(to_fold, true, window, cx);
17367    }
17368
17369    pub fn fold_at(
17370        &mut self,
17371        buffer_row: MultiBufferRow,
17372        window: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17376
17377        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17378            let autoscroll = self
17379                .selections
17380                .all::<Point>(cx)
17381                .iter()
17382                .any(|selection| crease.range().overlaps(&selection.range()));
17383
17384            self.fold_creases(vec![crease], autoscroll, window, cx);
17385        }
17386    }
17387
17388    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17389        if self.is_singleton(cx) {
17390            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17391            let buffer = &display_map.buffer_snapshot;
17392            let selections = self.selections.all::<Point>(cx);
17393            let ranges = selections
17394                .iter()
17395                .map(|s| {
17396                    let range = s.display_range(&display_map).sorted();
17397                    let mut start = range.start.to_point(&display_map);
17398                    let mut end = range.end.to_point(&display_map);
17399                    start.column = 0;
17400                    end.column = buffer.line_len(MultiBufferRow(end.row));
17401                    start..end
17402                })
17403                .collect::<Vec<_>>();
17404
17405            self.unfold_ranges(&ranges, true, true, cx);
17406        } else {
17407            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17408            let buffer_ids = self
17409                .selections
17410                .disjoint_anchor_ranges()
17411                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17412                .collect::<HashSet<_>>();
17413            for buffer_id in buffer_ids {
17414                self.unfold_buffer(buffer_id, cx);
17415            }
17416        }
17417    }
17418
17419    pub fn unfold_recursive(
17420        &mut self,
17421        _: &UnfoldRecursive,
17422        _window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) {
17425        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17426        let selections = self.selections.all::<Point>(cx);
17427        let ranges = selections
17428            .iter()
17429            .map(|s| {
17430                let mut range = s.display_range(&display_map).sorted();
17431                *range.start.column_mut() = 0;
17432                *range.end.column_mut() = display_map.line_len(range.end.row());
17433                let start = range.start.to_point(&display_map);
17434                let end = range.end.to_point(&display_map);
17435                start..end
17436            })
17437            .collect::<Vec<_>>();
17438
17439        self.unfold_ranges(&ranges, true, true, cx);
17440    }
17441
17442    pub fn unfold_at(
17443        &mut self,
17444        buffer_row: MultiBufferRow,
17445        _window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17449
17450        let intersection_range = Point::new(buffer_row.0, 0)
17451            ..Point::new(
17452                buffer_row.0,
17453                display_map.buffer_snapshot.line_len(buffer_row),
17454            );
17455
17456        let autoscroll = self
17457            .selections
17458            .all::<Point>(cx)
17459            .iter()
17460            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17461
17462        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17463    }
17464
17465    pub fn unfold_all(
17466        &mut self,
17467        _: &actions::UnfoldAll,
17468        _window: &mut Window,
17469        cx: &mut Context<Self>,
17470    ) {
17471        if self.buffer.read(cx).is_singleton() {
17472            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17473            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17474        } else {
17475            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17476                editor
17477                    .update(cx, |editor, cx| {
17478                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17479                            editor.unfold_buffer(buffer_id, cx);
17480                        }
17481                    })
17482                    .ok();
17483            });
17484        }
17485    }
17486
17487    pub fn fold_selected_ranges(
17488        &mut self,
17489        _: &FoldSelectedRanges,
17490        window: &mut Window,
17491        cx: &mut Context<Self>,
17492    ) {
17493        let selections = self.selections.all_adjusted(cx);
17494        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17495        let ranges = selections
17496            .into_iter()
17497            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17498            .collect::<Vec<_>>();
17499        self.fold_creases(ranges, true, window, cx);
17500    }
17501
17502    pub fn fold_ranges<T: ToOffset + Clone>(
17503        &mut self,
17504        ranges: Vec<Range<T>>,
17505        auto_scroll: bool,
17506        window: &mut Window,
17507        cx: &mut Context<Self>,
17508    ) {
17509        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17510        let ranges = ranges
17511            .into_iter()
17512            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17513            .collect::<Vec<_>>();
17514        self.fold_creases(ranges, auto_scroll, window, cx);
17515    }
17516
17517    pub fn fold_creases<T: ToOffset + Clone>(
17518        &mut self,
17519        creases: Vec<Crease<T>>,
17520        auto_scroll: bool,
17521        _window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) {
17524        if creases.is_empty() {
17525            return;
17526        }
17527
17528        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17529
17530        if auto_scroll {
17531            self.request_autoscroll(Autoscroll::fit(), cx);
17532        }
17533
17534        cx.notify();
17535
17536        self.scrollbar_marker_state.dirty = true;
17537        self.folds_did_change(cx);
17538    }
17539
17540    /// Removes any folds whose ranges intersect any of the given ranges.
17541    pub fn unfold_ranges<T: ToOffset + Clone>(
17542        &mut self,
17543        ranges: &[Range<T>],
17544        inclusive: bool,
17545        auto_scroll: bool,
17546        cx: &mut Context<Self>,
17547    ) {
17548        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17549            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17550        });
17551        self.folds_did_change(cx);
17552    }
17553
17554    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17555        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17556            return;
17557        }
17558        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17559        self.display_map.update(cx, |display_map, cx| {
17560            display_map.fold_buffers([buffer_id], cx)
17561        });
17562        cx.emit(EditorEvent::BufferFoldToggled {
17563            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17564            folded: true,
17565        });
17566        cx.notify();
17567    }
17568
17569    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17570        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17571            return;
17572        }
17573        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17574        self.display_map.update(cx, |display_map, cx| {
17575            display_map.unfold_buffers([buffer_id], cx);
17576        });
17577        cx.emit(EditorEvent::BufferFoldToggled {
17578            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17579            folded: false,
17580        });
17581        cx.notify();
17582    }
17583
17584    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17585        self.display_map.read(cx).is_buffer_folded(buffer)
17586    }
17587
17588    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17589        self.display_map.read(cx).folded_buffers()
17590    }
17591
17592    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17593        self.display_map.update(cx, |display_map, cx| {
17594            display_map.disable_header_for_buffer(buffer_id, cx);
17595        });
17596        cx.notify();
17597    }
17598
17599    /// Removes any folds with the given ranges.
17600    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17601        &mut self,
17602        ranges: &[Range<T>],
17603        type_id: TypeId,
17604        auto_scroll: bool,
17605        cx: &mut Context<Self>,
17606    ) {
17607        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17608            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17609        });
17610        self.folds_did_change(cx);
17611    }
17612
17613    fn remove_folds_with<T: ToOffset + Clone>(
17614        &mut self,
17615        ranges: &[Range<T>],
17616        auto_scroll: bool,
17617        cx: &mut Context<Self>,
17618        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17619    ) {
17620        if ranges.is_empty() {
17621            return;
17622        }
17623
17624        let mut buffers_affected = HashSet::default();
17625        let multi_buffer = self.buffer().read(cx);
17626        for range in ranges {
17627            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17628                buffers_affected.insert(buffer.read(cx).remote_id());
17629            };
17630        }
17631
17632        self.display_map.update(cx, update);
17633
17634        if auto_scroll {
17635            self.request_autoscroll(Autoscroll::fit(), cx);
17636        }
17637
17638        cx.notify();
17639        self.scrollbar_marker_state.dirty = true;
17640        self.active_indent_guides_state.dirty = true;
17641    }
17642
17643    pub fn update_renderer_widths(
17644        &mut self,
17645        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17646        cx: &mut Context<Self>,
17647    ) -> bool {
17648        self.display_map
17649            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17650    }
17651
17652    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17653        self.display_map.read(cx).fold_placeholder.clone()
17654    }
17655
17656    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17657        self.buffer.update(cx, |buffer, cx| {
17658            buffer.set_all_diff_hunks_expanded(cx);
17659        });
17660    }
17661
17662    pub fn expand_all_diff_hunks(
17663        &mut self,
17664        _: &ExpandAllDiffHunks,
17665        _window: &mut Window,
17666        cx: &mut Context<Self>,
17667    ) {
17668        self.buffer.update(cx, |buffer, cx| {
17669            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17670        });
17671    }
17672
17673    pub fn toggle_selected_diff_hunks(
17674        &mut self,
17675        _: &ToggleSelectedDiffHunks,
17676        _window: &mut Window,
17677        cx: &mut Context<Self>,
17678    ) {
17679        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17680        self.toggle_diff_hunks_in_ranges(ranges, cx);
17681    }
17682
17683    pub fn diff_hunks_in_ranges<'a>(
17684        &'a self,
17685        ranges: &'a [Range<Anchor>],
17686        buffer: &'a MultiBufferSnapshot,
17687    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17688        ranges.iter().flat_map(move |range| {
17689            let end_excerpt_id = range.end.excerpt_id;
17690            let range = range.to_point(buffer);
17691            let mut peek_end = range.end;
17692            if range.end.row < buffer.max_row().0 {
17693                peek_end = Point::new(range.end.row + 1, 0);
17694            }
17695            buffer
17696                .diff_hunks_in_range(range.start..peek_end)
17697                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17698        })
17699    }
17700
17701    pub fn has_stageable_diff_hunks_in_ranges(
17702        &self,
17703        ranges: &[Range<Anchor>],
17704        snapshot: &MultiBufferSnapshot,
17705    ) -> bool {
17706        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17707        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17708    }
17709
17710    pub fn toggle_staged_selected_diff_hunks(
17711        &mut self,
17712        _: &::git::ToggleStaged,
17713        _: &mut Window,
17714        cx: &mut Context<Self>,
17715    ) {
17716        let snapshot = self.buffer.read(cx).snapshot(cx);
17717        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17718        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17719        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17720    }
17721
17722    pub fn set_render_diff_hunk_controls(
17723        &mut self,
17724        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17725        cx: &mut Context<Self>,
17726    ) {
17727        self.render_diff_hunk_controls = render_diff_hunk_controls;
17728        cx.notify();
17729    }
17730
17731    pub fn stage_and_next(
17732        &mut self,
17733        _: &::git::StageAndNext,
17734        window: &mut Window,
17735        cx: &mut Context<Self>,
17736    ) {
17737        self.do_stage_or_unstage_and_next(true, window, cx);
17738    }
17739
17740    pub fn unstage_and_next(
17741        &mut self,
17742        _: &::git::UnstageAndNext,
17743        window: &mut Window,
17744        cx: &mut Context<Self>,
17745    ) {
17746        self.do_stage_or_unstage_and_next(false, window, cx);
17747    }
17748
17749    pub fn stage_or_unstage_diff_hunks(
17750        &mut self,
17751        stage: bool,
17752        ranges: Vec<Range<Anchor>>,
17753        cx: &mut Context<Self>,
17754    ) {
17755        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17756        cx.spawn(async move |this, cx| {
17757            task.await?;
17758            this.update(cx, |this, cx| {
17759                let snapshot = this.buffer.read(cx).snapshot(cx);
17760                let chunk_by = this
17761                    .diff_hunks_in_ranges(&ranges, &snapshot)
17762                    .chunk_by(|hunk| hunk.buffer_id);
17763                for (buffer_id, hunks) in &chunk_by {
17764                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17765                }
17766            })
17767        })
17768        .detach_and_log_err(cx);
17769    }
17770
17771    fn save_buffers_for_ranges_if_needed(
17772        &mut self,
17773        ranges: &[Range<Anchor>],
17774        cx: &mut Context<Editor>,
17775    ) -> Task<Result<()>> {
17776        let multibuffer = self.buffer.read(cx);
17777        let snapshot = multibuffer.read(cx);
17778        let buffer_ids: HashSet<_> = ranges
17779            .iter()
17780            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17781            .collect();
17782        drop(snapshot);
17783
17784        let mut buffers = HashSet::default();
17785        for buffer_id in buffer_ids {
17786            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17787                let buffer = buffer_entity.read(cx);
17788                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17789                {
17790                    buffers.insert(buffer_entity);
17791                }
17792            }
17793        }
17794
17795        if let Some(project) = &self.project {
17796            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17797        } else {
17798            Task::ready(Ok(()))
17799        }
17800    }
17801
17802    fn do_stage_or_unstage_and_next(
17803        &mut self,
17804        stage: bool,
17805        window: &mut Window,
17806        cx: &mut Context<Self>,
17807    ) {
17808        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17809
17810        if ranges.iter().any(|range| range.start != range.end) {
17811            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17812            return;
17813        }
17814
17815        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17816        let snapshot = self.snapshot(window, cx);
17817        let position = self.selections.newest::<Point>(cx).head();
17818        let mut row = snapshot
17819            .buffer_snapshot
17820            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17821            .find(|hunk| hunk.row_range.start.0 > position.row)
17822            .map(|hunk| hunk.row_range.start);
17823
17824        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17825        // Outside of the project diff editor, wrap around to the beginning.
17826        if !all_diff_hunks_expanded {
17827            row = row.or_else(|| {
17828                snapshot
17829                    .buffer_snapshot
17830                    .diff_hunks_in_range(Point::zero()..position)
17831                    .find(|hunk| hunk.row_range.end.0 < position.row)
17832                    .map(|hunk| hunk.row_range.start)
17833            });
17834        }
17835
17836        if let Some(row) = row {
17837            let destination = Point::new(row.0, 0);
17838            let autoscroll = Autoscroll::center();
17839
17840            self.unfold_ranges(&[destination..destination], false, false, cx);
17841            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17842                s.select_ranges([destination..destination]);
17843            });
17844        }
17845    }
17846
17847    fn do_stage_or_unstage(
17848        &self,
17849        stage: bool,
17850        buffer_id: BufferId,
17851        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17852        cx: &mut App,
17853    ) -> Option<()> {
17854        let project = self.project.as_ref()?;
17855        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17856        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17857        let buffer_snapshot = buffer.read(cx).snapshot();
17858        let file_exists = buffer_snapshot
17859            .file()
17860            .is_some_and(|file| file.disk_state().exists());
17861        diff.update(cx, |diff, cx| {
17862            diff.stage_or_unstage_hunks(
17863                stage,
17864                &hunks
17865                    .map(|hunk| buffer_diff::DiffHunk {
17866                        buffer_range: hunk.buffer_range,
17867                        diff_base_byte_range: hunk.diff_base_byte_range,
17868                        secondary_status: hunk.secondary_status,
17869                        range: Point::zero()..Point::zero(), // unused
17870                    })
17871                    .collect::<Vec<_>>(),
17872                &buffer_snapshot,
17873                file_exists,
17874                cx,
17875            )
17876        });
17877        None
17878    }
17879
17880    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17881        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17882        self.buffer
17883            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17884    }
17885
17886    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17887        self.buffer.update(cx, |buffer, cx| {
17888            let ranges = vec![Anchor::min()..Anchor::max()];
17889            if !buffer.all_diff_hunks_expanded()
17890                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17891            {
17892                buffer.collapse_diff_hunks(ranges, cx);
17893                true
17894            } else {
17895                false
17896            }
17897        })
17898    }
17899
17900    fn toggle_diff_hunks_in_ranges(
17901        &mut self,
17902        ranges: Vec<Range<Anchor>>,
17903        cx: &mut Context<Editor>,
17904    ) {
17905        self.buffer.update(cx, |buffer, cx| {
17906            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17907            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17908        })
17909    }
17910
17911    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17912        self.buffer.update(cx, |buffer, cx| {
17913            let snapshot = buffer.snapshot(cx);
17914            let excerpt_id = range.end.excerpt_id;
17915            let point_range = range.to_point(&snapshot);
17916            let expand = !buffer.single_hunk_is_expanded(range, cx);
17917            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17918        })
17919    }
17920
17921    pub(crate) fn apply_all_diff_hunks(
17922        &mut self,
17923        _: &ApplyAllDiffHunks,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926    ) {
17927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17928
17929        let buffers = self.buffer.read(cx).all_buffers();
17930        for branch_buffer in buffers {
17931            branch_buffer.update(cx, |branch_buffer, cx| {
17932                branch_buffer.merge_into_base(Vec::new(), cx);
17933            });
17934        }
17935
17936        if let Some(project) = self.project.clone() {
17937            self.save(
17938                SaveOptions {
17939                    format: true,
17940                    autosave: false,
17941                },
17942                project,
17943                window,
17944                cx,
17945            )
17946            .detach_and_log_err(cx);
17947        }
17948    }
17949
17950    pub(crate) fn apply_selected_diff_hunks(
17951        &mut self,
17952        _: &ApplyDiffHunk,
17953        window: &mut Window,
17954        cx: &mut Context<Self>,
17955    ) {
17956        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17957        let snapshot = self.snapshot(window, cx);
17958        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17959        let mut ranges_by_buffer = HashMap::default();
17960        self.transact(window, cx, |editor, _window, cx| {
17961            for hunk in hunks {
17962                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17963                    ranges_by_buffer
17964                        .entry(buffer.clone())
17965                        .or_insert_with(Vec::new)
17966                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17967                }
17968            }
17969
17970            for (buffer, ranges) in ranges_by_buffer {
17971                buffer.update(cx, |buffer, cx| {
17972                    buffer.merge_into_base(ranges, cx);
17973                });
17974            }
17975        });
17976
17977        if let Some(project) = self.project.clone() {
17978            self.save(
17979                SaveOptions {
17980                    format: true,
17981                    autosave: false,
17982                },
17983                project,
17984                window,
17985                cx,
17986            )
17987            .detach_and_log_err(cx);
17988        }
17989    }
17990
17991    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17992        if hovered != self.gutter_hovered {
17993            self.gutter_hovered = hovered;
17994            cx.notify();
17995        }
17996    }
17997
17998    pub fn insert_blocks(
17999        &mut self,
18000        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18001        autoscroll: Option<Autoscroll>,
18002        cx: &mut Context<Self>,
18003    ) -> Vec<CustomBlockId> {
18004        let blocks = self
18005            .display_map
18006            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18007        if let Some(autoscroll) = autoscroll {
18008            self.request_autoscroll(autoscroll, cx);
18009        }
18010        cx.notify();
18011        blocks
18012    }
18013
18014    pub fn resize_blocks(
18015        &mut self,
18016        heights: HashMap<CustomBlockId, u32>,
18017        autoscroll: Option<Autoscroll>,
18018        cx: &mut Context<Self>,
18019    ) {
18020        self.display_map
18021            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18022        if let Some(autoscroll) = autoscroll {
18023            self.request_autoscroll(autoscroll, cx);
18024        }
18025        cx.notify();
18026    }
18027
18028    pub fn replace_blocks(
18029        &mut self,
18030        renderers: HashMap<CustomBlockId, RenderBlock>,
18031        autoscroll: Option<Autoscroll>,
18032        cx: &mut Context<Self>,
18033    ) {
18034        self.display_map
18035            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18036        if let Some(autoscroll) = autoscroll {
18037            self.request_autoscroll(autoscroll, cx);
18038        }
18039        cx.notify();
18040    }
18041
18042    pub fn remove_blocks(
18043        &mut self,
18044        block_ids: HashSet<CustomBlockId>,
18045        autoscroll: Option<Autoscroll>,
18046        cx: &mut Context<Self>,
18047    ) {
18048        self.display_map.update(cx, |display_map, cx| {
18049            display_map.remove_blocks(block_ids, cx)
18050        });
18051        if let Some(autoscroll) = autoscroll {
18052            self.request_autoscroll(autoscroll, cx);
18053        }
18054        cx.notify();
18055    }
18056
18057    pub fn row_for_block(
18058        &self,
18059        block_id: CustomBlockId,
18060        cx: &mut Context<Self>,
18061    ) -> Option<DisplayRow> {
18062        self.display_map
18063            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18064    }
18065
18066    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18067        self.focused_block = Some(focused_block);
18068    }
18069
18070    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18071        self.focused_block.take()
18072    }
18073
18074    pub fn insert_creases(
18075        &mut self,
18076        creases: impl IntoIterator<Item = Crease<Anchor>>,
18077        cx: &mut Context<Self>,
18078    ) -> Vec<CreaseId> {
18079        self.display_map
18080            .update(cx, |map, cx| map.insert_creases(creases, cx))
18081    }
18082
18083    pub fn remove_creases(
18084        &mut self,
18085        ids: impl IntoIterator<Item = CreaseId>,
18086        cx: &mut Context<Self>,
18087    ) -> Vec<(CreaseId, Range<Anchor>)> {
18088        self.display_map
18089            .update(cx, |map, cx| map.remove_creases(ids, cx))
18090    }
18091
18092    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18093        self.display_map
18094            .update(cx, |map, cx| map.snapshot(cx))
18095            .longest_row()
18096    }
18097
18098    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18099        self.display_map
18100            .update(cx, |map, cx| map.snapshot(cx))
18101            .max_point()
18102    }
18103
18104    pub fn text(&self, cx: &App) -> String {
18105        self.buffer.read(cx).read(cx).text()
18106    }
18107
18108    pub fn is_empty(&self, cx: &App) -> bool {
18109        self.buffer.read(cx).read(cx).is_empty()
18110    }
18111
18112    pub fn text_option(&self, cx: &App) -> Option<String> {
18113        let text = self.text(cx);
18114        let text = text.trim();
18115
18116        if text.is_empty() {
18117            return None;
18118        }
18119
18120        Some(text.to_string())
18121    }
18122
18123    pub fn set_text(
18124        &mut self,
18125        text: impl Into<Arc<str>>,
18126        window: &mut Window,
18127        cx: &mut Context<Self>,
18128    ) {
18129        self.transact(window, cx, |this, _, cx| {
18130            this.buffer
18131                .read(cx)
18132                .as_singleton()
18133                .expect("you can only call set_text on editors for singleton buffers")
18134                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18135        });
18136    }
18137
18138    pub fn display_text(&self, cx: &mut App) -> String {
18139        self.display_map
18140            .update(cx, |map, cx| map.snapshot(cx))
18141            .text()
18142    }
18143
18144    fn create_minimap(
18145        &self,
18146        minimap_settings: MinimapSettings,
18147        window: &mut Window,
18148        cx: &mut Context<Self>,
18149    ) -> Option<Entity<Self>> {
18150        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18151            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18152    }
18153
18154    fn initialize_new_minimap(
18155        &self,
18156        minimap_settings: MinimapSettings,
18157        window: &mut Window,
18158        cx: &mut Context<Self>,
18159    ) -> Entity<Self> {
18160        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18161
18162        let mut minimap = Editor::new_internal(
18163            EditorMode::Minimap {
18164                parent: cx.weak_entity(),
18165            },
18166            self.buffer.clone(),
18167            None,
18168            Some(self.display_map.clone()),
18169            window,
18170            cx,
18171        );
18172        minimap.scroll_manager.clone_state(&self.scroll_manager);
18173        minimap.set_text_style_refinement(TextStyleRefinement {
18174            font_size: Some(MINIMAP_FONT_SIZE),
18175            font_weight: Some(MINIMAP_FONT_WEIGHT),
18176            ..Default::default()
18177        });
18178        minimap.update_minimap_configuration(minimap_settings, cx);
18179        cx.new(|_| minimap)
18180    }
18181
18182    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18183        let current_line_highlight = minimap_settings
18184            .current_line_highlight
18185            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18186        self.set_current_line_highlight(Some(current_line_highlight));
18187    }
18188
18189    pub fn minimap(&self) -> Option<&Entity<Self>> {
18190        self.minimap
18191            .as_ref()
18192            .filter(|_| self.minimap_visibility.visible())
18193    }
18194
18195    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18196        let mut wrap_guides = smallvec![];
18197
18198        if self.show_wrap_guides == Some(false) {
18199            return wrap_guides;
18200        }
18201
18202        let settings = self.buffer.read(cx).language_settings(cx);
18203        if settings.show_wrap_guides {
18204            match self.soft_wrap_mode(cx) {
18205                SoftWrap::Column(soft_wrap) => {
18206                    wrap_guides.push((soft_wrap as usize, true));
18207                }
18208                SoftWrap::Bounded(soft_wrap) => {
18209                    wrap_guides.push((soft_wrap as usize, true));
18210                }
18211                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18212            }
18213            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18214        }
18215
18216        wrap_guides
18217    }
18218
18219    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18220        let settings = self.buffer.read(cx).language_settings(cx);
18221        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18222        match mode {
18223            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18224                SoftWrap::None
18225            }
18226            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18227            language_settings::SoftWrap::PreferredLineLength => {
18228                SoftWrap::Column(settings.preferred_line_length)
18229            }
18230            language_settings::SoftWrap::Bounded => {
18231                SoftWrap::Bounded(settings.preferred_line_length)
18232            }
18233        }
18234    }
18235
18236    pub fn set_soft_wrap_mode(
18237        &mut self,
18238        mode: language_settings::SoftWrap,
18239
18240        cx: &mut Context<Self>,
18241    ) {
18242        self.soft_wrap_mode_override = Some(mode);
18243        cx.notify();
18244    }
18245
18246    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18247        self.hard_wrap = hard_wrap;
18248        cx.notify();
18249    }
18250
18251    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18252        self.text_style_refinement = Some(style);
18253    }
18254
18255    /// called by the Element so we know what style we were most recently rendered with.
18256    pub(crate) fn set_style(
18257        &mut self,
18258        style: EditorStyle,
18259        window: &mut Window,
18260        cx: &mut Context<Self>,
18261    ) {
18262        // We intentionally do not inform the display map about the minimap style
18263        // so that wrapping is not recalculated and stays consistent for the editor
18264        // and its linked minimap.
18265        if !self.mode.is_minimap() {
18266            let rem_size = window.rem_size();
18267            self.display_map.update(cx, |map, cx| {
18268                map.set_font(
18269                    style.text.font(),
18270                    style.text.font_size.to_pixels(rem_size),
18271                    cx,
18272                )
18273            });
18274        }
18275        self.style = Some(style);
18276    }
18277
18278    pub fn style(&self) -> Option<&EditorStyle> {
18279        self.style.as_ref()
18280    }
18281
18282    // Called by the element. This method is not designed to be called outside of the editor
18283    // element's layout code because it does not notify when rewrapping is computed synchronously.
18284    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18285        self.display_map
18286            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18287    }
18288
18289    pub fn set_soft_wrap(&mut self) {
18290        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18291    }
18292
18293    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18294        if self.soft_wrap_mode_override.is_some() {
18295            self.soft_wrap_mode_override.take();
18296        } else {
18297            let soft_wrap = match self.soft_wrap_mode(cx) {
18298                SoftWrap::GitDiff => return,
18299                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18300                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18301                    language_settings::SoftWrap::None
18302                }
18303            };
18304            self.soft_wrap_mode_override = Some(soft_wrap);
18305        }
18306        cx.notify();
18307    }
18308
18309    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18310        let Some(workspace) = self.workspace() else {
18311            return;
18312        };
18313        let fs = workspace.read(cx).app_state().fs.clone();
18314        let current_show = TabBarSettings::get_global(cx).show;
18315        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18316            setting.show = Some(!current_show);
18317        });
18318    }
18319
18320    pub fn toggle_indent_guides(
18321        &mut self,
18322        _: &ToggleIndentGuides,
18323        _: &mut Window,
18324        cx: &mut Context<Self>,
18325    ) {
18326        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18327            self.buffer
18328                .read(cx)
18329                .language_settings(cx)
18330                .indent_guides
18331                .enabled
18332        });
18333        self.show_indent_guides = Some(!currently_enabled);
18334        cx.notify();
18335    }
18336
18337    fn should_show_indent_guides(&self) -> Option<bool> {
18338        self.show_indent_guides
18339    }
18340
18341    pub fn toggle_line_numbers(
18342        &mut self,
18343        _: &ToggleLineNumbers,
18344        _: &mut Window,
18345        cx: &mut Context<Self>,
18346    ) {
18347        let mut editor_settings = EditorSettings::get_global(cx).clone();
18348        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18349        EditorSettings::override_global(editor_settings, cx);
18350    }
18351
18352    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18353        if let Some(show_line_numbers) = self.show_line_numbers {
18354            return show_line_numbers;
18355        }
18356        EditorSettings::get_global(cx).gutter.line_numbers
18357    }
18358
18359    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18360        self.use_relative_line_numbers
18361            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18362    }
18363
18364    pub fn toggle_relative_line_numbers(
18365        &mut self,
18366        _: &ToggleRelativeLineNumbers,
18367        _: &mut Window,
18368        cx: &mut Context<Self>,
18369    ) {
18370        let is_relative = self.should_use_relative_line_numbers(cx);
18371        self.set_relative_line_number(Some(!is_relative), cx)
18372    }
18373
18374    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18375        self.use_relative_line_numbers = is_relative;
18376        cx.notify();
18377    }
18378
18379    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18380        self.show_gutter = show_gutter;
18381        cx.notify();
18382    }
18383
18384    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18385        self.show_scrollbars = ScrollbarAxes {
18386            horizontal: show,
18387            vertical: show,
18388        };
18389        cx.notify();
18390    }
18391
18392    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18393        self.show_scrollbars.vertical = show;
18394        cx.notify();
18395    }
18396
18397    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18398        self.show_scrollbars.horizontal = show;
18399        cx.notify();
18400    }
18401
18402    pub fn set_minimap_visibility(
18403        &mut self,
18404        minimap_visibility: MinimapVisibility,
18405        window: &mut Window,
18406        cx: &mut Context<Self>,
18407    ) {
18408        if self.minimap_visibility != minimap_visibility {
18409            if minimap_visibility.visible() && self.minimap.is_none() {
18410                let minimap_settings = EditorSettings::get_global(cx).minimap;
18411                self.minimap =
18412                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18413            }
18414            self.minimap_visibility = minimap_visibility;
18415            cx.notify();
18416        }
18417    }
18418
18419    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18420        self.set_show_scrollbars(false, cx);
18421        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18422    }
18423
18424    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18425        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18426    }
18427
18428    /// Normally the text in full mode and auto height editors is padded on the
18429    /// left side by roughly half a character width for improved hit testing.
18430    ///
18431    /// Use this method to disable this for cases where this is not wanted (e.g.
18432    /// if you want to align the editor text with some other text above or below)
18433    /// or if you want to add this padding to single-line editors.
18434    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18435        self.offset_content = offset_content;
18436        cx.notify();
18437    }
18438
18439    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18440        self.show_line_numbers = Some(show_line_numbers);
18441        cx.notify();
18442    }
18443
18444    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18445        self.disable_expand_excerpt_buttons = true;
18446        cx.notify();
18447    }
18448
18449    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18450        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18451        cx.notify();
18452    }
18453
18454    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18455        self.show_code_actions = Some(show_code_actions);
18456        cx.notify();
18457    }
18458
18459    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18460        self.show_runnables = Some(show_runnables);
18461        cx.notify();
18462    }
18463
18464    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18465        self.show_breakpoints = Some(show_breakpoints);
18466        cx.notify();
18467    }
18468
18469    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18470        if self.display_map.read(cx).masked != masked {
18471            self.display_map.update(cx, |map, _| map.masked = masked);
18472        }
18473        cx.notify()
18474    }
18475
18476    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18477        self.show_wrap_guides = Some(show_wrap_guides);
18478        cx.notify();
18479    }
18480
18481    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18482        self.show_indent_guides = Some(show_indent_guides);
18483        cx.notify();
18484    }
18485
18486    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18487        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18488            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18489                if let Some(dir) = file.abs_path(cx).parent() {
18490                    return Some(dir.to_owned());
18491                }
18492            }
18493
18494            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18495                return Some(project_path.path.to_path_buf());
18496            }
18497        }
18498
18499        None
18500    }
18501
18502    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18503        self.active_excerpt(cx)?
18504            .1
18505            .read(cx)
18506            .file()
18507            .and_then(|f| f.as_local())
18508    }
18509
18510    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18511        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18512            let buffer = buffer.read(cx);
18513            if let Some(project_path) = buffer.project_path(cx) {
18514                let project = self.project.as_ref()?.read(cx);
18515                project.absolute_path(&project_path, cx)
18516            } else {
18517                buffer
18518                    .file()
18519                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18520            }
18521        })
18522    }
18523
18524    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18525        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18526            let project_path = buffer.read(cx).project_path(cx)?;
18527            let project = self.project.as_ref()?.read(cx);
18528            let entry = project.entry_for_path(&project_path, cx)?;
18529            let path = entry.path.to_path_buf();
18530            Some(path)
18531        })
18532    }
18533
18534    pub fn reveal_in_finder(
18535        &mut self,
18536        _: &RevealInFileManager,
18537        _window: &mut Window,
18538        cx: &mut Context<Self>,
18539    ) {
18540        if let Some(target) = self.target_file(cx) {
18541            cx.reveal_path(&target.abs_path(cx));
18542        }
18543    }
18544
18545    pub fn copy_path(
18546        &mut self,
18547        _: &zed_actions::workspace::CopyPath,
18548        _window: &mut Window,
18549        cx: &mut Context<Self>,
18550    ) {
18551        if let Some(path) = self.target_file_abs_path(cx) {
18552            if let Some(path) = path.to_str() {
18553                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18554            }
18555        }
18556    }
18557
18558    pub fn copy_relative_path(
18559        &mut self,
18560        _: &zed_actions::workspace::CopyRelativePath,
18561        _window: &mut Window,
18562        cx: &mut Context<Self>,
18563    ) {
18564        if let Some(path) = self.target_file_path(cx) {
18565            if let Some(path) = path.to_str() {
18566                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18567            }
18568        }
18569    }
18570
18571    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18572        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18573            buffer.read(cx).project_path(cx)
18574        } else {
18575            None
18576        }
18577    }
18578
18579    // Returns true if the editor handled a go-to-line request
18580    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18581        maybe!({
18582            let breakpoint_store = self.breakpoint_store.as_ref()?;
18583
18584            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18585            else {
18586                self.clear_row_highlights::<ActiveDebugLine>();
18587                return None;
18588            };
18589
18590            let position = active_stack_frame.position;
18591            let buffer_id = position.buffer_id?;
18592            let snapshot = self
18593                .project
18594                .as_ref()?
18595                .read(cx)
18596                .buffer_for_id(buffer_id, cx)?
18597                .read(cx)
18598                .snapshot();
18599
18600            let mut handled = false;
18601            for (id, ExcerptRange { context, .. }) in
18602                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18603            {
18604                if context.start.cmp(&position, &snapshot).is_ge()
18605                    || context.end.cmp(&position, &snapshot).is_lt()
18606                {
18607                    continue;
18608                }
18609                let snapshot = self.buffer.read(cx).snapshot(cx);
18610                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18611
18612                handled = true;
18613                self.clear_row_highlights::<ActiveDebugLine>();
18614
18615                self.go_to_line::<ActiveDebugLine>(
18616                    multibuffer_anchor,
18617                    Some(cx.theme().colors().editor_debugger_active_line_background),
18618                    window,
18619                    cx,
18620                );
18621
18622                cx.notify();
18623            }
18624
18625            handled.then_some(())
18626        })
18627        .is_some()
18628    }
18629
18630    pub fn copy_file_name_without_extension(
18631        &mut self,
18632        _: &CopyFileNameWithoutExtension,
18633        _: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        if let Some(file) = self.target_file(cx) {
18637            if let Some(file_stem) = file.path().file_stem() {
18638                if let Some(name) = file_stem.to_str() {
18639                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18640                }
18641            }
18642        }
18643    }
18644
18645    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18646        if let Some(file) = self.target_file(cx) {
18647            if let Some(file_name) = file.path().file_name() {
18648                if let Some(name) = file_name.to_str() {
18649                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18650                }
18651            }
18652        }
18653    }
18654
18655    pub fn toggle_git_blame(
18656        &mut self,
18657        _: &::git::Blame,
18658        window: &mut Window,
18659        cx: &mut Context<Self>,
18660    ) {
18661        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18662
18663        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18664            self.start_git_blame(true, window, cx);
18665        }
18666
18667        cx.notify();
18668    }
18669
18670    pub fn toggle_git_blame_inline(
18671        &mut self,
18672        _: &ToggleGitBlameInline,
18673        window: &mut Window,
18674        cx: &mut Context<Self>,
18675    ) {
18676        self.toggle_git_blame_inline_internal(true, window, cx);
18677        cx.notify();
18678    }
18679
18680    pub fn open_git_blame_commit(
18681        &mut self,
18682        _: &OpenGitBlameCommit,
18683        window: &mut Window,
18684        cx: &mut Context<Self>,
18685    ) {
18686        self.open_git_blame_commit_internal(window, cx);
18687    }
18688
18689    fn open_git_blame_commit_internal(
18690        &mut self,
18691        window: &mut Window,
18692        cx: &mut Context<Self>,
18693    ) -> Option<()> {
18694        let blame = self.blame.as_ref()?;
18695        let snapshot = self.snapshot(window, cx);
18696        let cursor = self.selections.newest::<Point>(cx).head();
18697        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18698        let blame_entry = blame
18699            .update(cx, |blame, cx| {
18700                blame
18701                    .blame_for_rows(
18702                        &[RowInfo {
18703                            buffer_id: Some(buffer.remote_id()),
18704                            buffer_row: Some(point.row),
18705                            ..Default::default()
18706                        }],
18707                        cx,
18708                    )
18709                    .next()
18710            })
18711            .flatten()?;
18712        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18713        let repo = blame.read(cx).repository(cx)?;
18714        let workspace = self.workspace()?.downgrade();
18715        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18716        None
18717    }
18718
18719    pub fn git_blame_inline_enabled(&self) -> bool {
18720        self.git_blame_inline_enabled
18721    }
18722
18723    pub fn toggle_selection_menu(
18724        &mut self,
18725        _: &ToggleSelectionMenu,
18726        _: &mut Window,
18727        cx: &mut Context<Self>,
18728    ) {
18729        self.show_selection_menu = self
18730            .show_selection_menu
18731            .map(|show_selections_menu| !show_selections_menu)
18732            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18733
18734        cx.notify();
18735    }
18736
18737    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18738        self.show_selection_menu
18739            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18740    }
18741
18742    fn start_git_blame(
18743        &mut self,
18744        user_triggered: bool,
18745        window: &mut Window,
18746        cx: &mut Context<Self>,
18747    ) {
18748        if let Some(project) = self.project.as_ref() {
18749            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18750                return;
18751            };
18752
18753            if buffer.read(cx).file().is_none() {
18754                return;
18755            }
18756
18757            let focused = self.focus_handle(cx).contains_focused(window, cx);
18758
18759            let project = project.clone();
18760            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18761            self.blame_subscription =
18762                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18763            self.blame = Some(blame);
18764        }
18765    }
18766
18767    fn toggle_git_blame_inline_internal(
18768        &mut self,
18769        user_triggered: bool,
18770        window: &mut Window,
18771        cx: &mut Context<Self>,
18772    ) {
18773        if self.git_blame_inline_enabled {
18774            self.git_blame_inline_enabled = false;
18775            self.show_git_blame_inline = false;
18776            self.show_git_blame_inline_delay_task.take();
18777        } else {
18778            self.git_blame_inline_enabled = true;
18779            self.start_git_blame_inline(user_triggered, window, cx);
18780        }
18781
18782        cx.notify();
18783    }
18784
18785    fn start_git_blame_inline(
18786        &mut self,
18787        user_triggered: bool,
18788        window: &mut Window,
18789        cx: &mut Context<Self>,
18790    ) {
18791        self.start_git_blame(user_triggered, window, cx);
18792
18793        if ProjectSettings::get_global(cx)
18794            .git
18795            .inline_blame_delay()
18796            .is_some()
18797        {
18798            self.start_inline_blame_timer(window, cx);
18799        } else {
18800            self.show_git_blame_inline = true
18801        }
18802    }
18803
18804    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18805        self.blame.as_ref()
18806    }
18807
18808    pub fn show_git_blame_gutter(&self) -> bool {
18809        self.show_git_blame_gutter
18810    }
18811
18812    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18813        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18814    }
18815
18816    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18817        self.show_git_blame_inline
18818            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18819            && !self.newest_selection_head_on_empty_line(cx)
18820            && self.has_blame_entries(cx)
18821    }
18822
18823    fn has_blame_entries(&self, cx: &App) -> bool {
18824        self.blame()
18825            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18826    }
18827
18828    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18829        let cursor_anchor = self.selections.newest_anchor().head();
18830
18831        let snapshot = self.buffer.read(cx).snapshot(cx);
18832        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18833
18834        snapshot.line_len(buffer_row) == 0
18835    }
18836
18837    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18838        let buffer_and_selection = maybe!({
18839            let selection = self.selections.newest::<Point>(cx);
18840            let selection_range = selection.range();
18841
18842            let multi_buffer = self.buffer().read(cx);
18843            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18844            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18845
18846            let (buffer, range, _) = if selection.reversed {
18847                buffer_ranges.first()
18848            } else {
18849                buffer_ranges.last()
18850            }?;
18851
18852            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18853                ..text::ToPoint::to_point(&range.end, &buffer).row;
18854            Some((
18855                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18856                selection,
18857            ))
18858        });
18859
18860        let Some((buffer, selection)) = buffer_and_selection else {
18861            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18862        };
18863
18864        let Some(project) = self.project.as_ref() else {
18865            return Task::ready(Err(anyhow!("editor does not have project")));
18866        };
18867
18868        project.update(cx, |project, cx| {
18869            project.get_permalink_to_line(&buffer, selection, cx)
18870        })
18871    }
18872
18873    pub fn copy_permalink_to_line(
18874        &mut self,
18875        _: &CopyPermalinkToLine,
18876        window: &mut Window,
18877        cx: &mut Context<Self>,
18878    ) {
18879        let permalink_task = self.get_permalink_to_line(cx);
18880        let workspace = self.workspace();
18881
18882        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18883            Ok(permalink) => {
18884                cx.update(|_, cx| {
18885                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18886                })
18887                .ok();
18888            }
18889            Err(err) => {
18890                let message = format!("Failed to copy permalink: {err}");
18891
18892                anyhow::Result::<()>::Err(err).log_err();
18893
18894                if let Some(workspace) = workspace {
18895                    workspace
18896                        .update_in(cx, |workspace, _, cx| {
18897                            struct CopyPermalinkToLine;
18898
18899                            workspace.show_toast(
18900                                Toast::new(
18901                                    NotificationId::unique::<CopyPermalinkToLine>(),
18902                                    message,
18903                                ),
18904                                cx,
18905                            )
18906                        })
18907                        .ok();
18908                }
18909            }
18910        })
18911        .detach();
18912    }
18913
18914    pub fn copy_file_location(
18915        &mut self,
18916        _: &CopyFileLocation,
18917        _: &mut Window,
18918        cx: &mut Context<Self>,
18919    ) {
18920        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18921        if let Some(file) = self.target_file(cx) {
18922            if let Some(path) = file.path().to_str() {
18923                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18924            }
18925        }
18926    }
18927
18928    pub fn open_permalink_to_line(
18929        &mut self,
18930        _: &OpenPermalinkToLine,
18931        window: &mut Window,
18932        cx: &mut Context<Self>,
18933    ) {
18934        let permalink_task = self.get_permalink_to_line(cx);
18935        let workspace = self.workspace();
18936
18937        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18938            Ok(permalink) => {
18939                cx.update(|_, cx| {
18940                    cx.open_url(permalink.as_ref());
18941                })
18942                .ok();
18943            }
18944            Err(err) => {
18945                let message = format!("Failed to open permalink: {err}");
18946
18947                anyhow::Result::<()>::Err(err).log_err();
18948
18949                if let Some(workspace) = workspace {
18950                    workspace
18951                        .update(cx, |workspace, cx| {
18952                            struct OpenPermalinkToLine;
18953
18954                            workspace.show_toast(
18955                                Toast::new(
18956                                    NotificationId::unique::<OpenPermalinkToLine>(),
18957                                    message,
18958                                ),
18959                                cx,
18960                            )
18961                        })
18962                        .ok();
18963                }
18964            }
18965        })
18966        .detach();
18967    }
18968
18969    pub fn insert_uuid_v4(
18970        &mut self,
18971        _: &InsertUuidV4,
18972        window: &mut Window,
18973        cx: &mut Context<Self>,
18974    ) {
18975        self.insert_uuid(UuidVersion::V4, window, cx);
18976    }
18977
18978    pub fn insert_uuid_v7(
18979        &mut self,
18980        _: &InsertUuidV7,
18981        window: &mut Window,
18982        cx: &mut Context<Self>,
18983    ) {
18984        self.insert_uuid(UuidVersion::V7, window, cx);
18985    }
18986
18987    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18989        self.transact(window, cx, |this, window, cx| {
18990            let edits = this
18991                .selections
18992                .all::<Point>(cx)
18993                .into_iter()
18994                .map(|selection| {
18995                    let uuid = match version {
18996                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18997                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18998                    };
18999
19000                    (selection.range(), uuid.to_string())
19001                });
19002            this.edit(edits, cx);
19003            this.refresh_inline_completion(true, false, window, cx);
19004        });
19005    }
19006
19007    pub fn open_selections_in_multibuffer(
19008        &mut self,
19009        _: &OpenSelectionsInMultibuffer,
19010        window: &mut Window,
19011        cx: &mut Context<Self>,
19012    ) {
19013        let multibuffer = self.buffer.read(cx);
19014
19015        let Some(buffer) = multibuffer.as_singleton() else {
19016            return;
19017        };
19018
19019        let Some(workspace) = self.workspace() else {
19020            return;
19021        };
19022
19023        let title = multibuffer.title(cx).to_string();
19024
19025        let locations = self
19026            .selections
19027            .all_anchors(cx)
19028            .into_iter()
19029            .map(|selection| Location {
19030                buffer: buffer.clone(),
19031                range: selection.start.text_anchor..selection.end.text_anchor,
19032            })
19033            .collect::<Vec<_>>();
19034
19035        cx.spawn_in(window, async move |_, cx| {
19036            workspace.update_in(cx, |workspace, window, cx| {
19037                Self::open_locations_in_multibuffer(
19038                    workspace,
19039                    locations,
19040                    format!("Selections for '{title}'"),
19041                    false,
19042                    MultibufferSelectionMode::All,
19043                    window,
19044                    cx,
19045                );
19046            })
19047        })
19048        .detach();
19049    }
19050
19051    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19052    /// last highlight added will be used.
19053    ///
19054    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19055    pub fn highlight_rows<T: 'static>(
19056        &mut self,
19057        range: Range<Anchor>,
19058        color: Hsla,
19059        options: RowHighlightOptions,
19060        cx: &mut Context<Self>,
19061    ) {
19062        let snapshot = self.buffer().read(cx).snapshot(cx);
19063        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19064        let ix = row_highlights.binary_search_by(|highlight| {
19065            Ordering::Equal
19066                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19067                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19068        });
19069
19070        if let Err(mut ix) = ix {
19071            let index = post_inc(&mut self.highlight_order);
19072
19073            // If this range intersects with the preceding highlight, then merge it with
19074            // the preceding highlight. Otherwise insert a new highlight.
19075            let mut merged = false;
19076            if ix > 0 {
19077                let prev_highlight = &mut row_highlights[ix - 1];
19078                if prev_highlight
19079                    .range
19080                    .end
19081                    .cmp(&range.start, &snapshot)
19082                    .is_ge()
19083                {
19084                    ix -= 1;
19085                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19086                        prev_highlight.range.end = range.end;
19087                    }
19088                    merged = true;
19089                    prev_highlight.index = index;
19090                    prev_highlight.color = color;
19091                    prev_highlight.options = options;
19092                }
19093            }
19094
19095            if !merged {
19096                row_highlights.insert(
19097                    ix,
19098                    RowHighlight {
19099                        range: range.clone(),
19100                        index,
19101                        color,
19102                        options,
19103                        type_id: TypeId::of::<T>(),
19104                    },
19105                );
19106            }
19107
19108            // If any of the following highlights intersect with this one, merge them.
19109            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19110                let highlight = &row_highlights[ix];
19111                if next_highlight
19112                    .range
19113                    .start
19114                    .cmp(&highlight.range.end, &snapshot)
19115                    .is_le()
19116                {
19117                    if next_highlight
19118                        .range
19119                        .end
19120                        .cmp(&highlight.range.end, &snapshot)
19121                        .is_gt()
19122                    {
19123                        row_highlights[ix].range.end = next_highlight.range.end;
19124                    }
19125                    row_highlights.remove(ix + 1);
19126                } else {
19127                    break;
19128                }
19129            }
19130        }
19131    }
19132
19133    /// Remove any highlighted row ranges of the given type that intersect the
19134    /// given ranges.
19135    pub fn remove_highlighted_rows<T: 'static>(
19136        &mut self,
19137        ranges_to_remove: Vec<Range<Anchor>>,
19138        cx: &mut Context<Self>,
19139    ) {
19140        let snapshot = self.buffer().read(cx).snapshot(cx);
19141        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19142        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19143        row_highlights.retain(|highlight| {
19144            while let Some(range_to_remove) = ranges_to_remove.peek() {
19145                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19146                    Ordering::Less | Ordering::Equal => {
19147                        ranges_to_remove.next();
19148                    }
19149                    Ordering::Greater => {
19150                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19151                            Ordering::Less | Ordering::Equal => {
19152                                return false;
19153                            }
19154                            Ordering::Greater => break,
19155                        }
19156                    }
19157                }
19158            }
19159
19160            true
19161        })
19162    }
19163
19164    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19165    pub fn clear_row_highlights<T: 'static>(&mut self) {
19166        self.highlighted_rows.remove(&TypeId::of::<T>());
19167    }
19168
19169    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19170    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19171        self.highlighted_rows
19172            .get(&TypeId::of::<T>())
19173            .map_or(&[] as &[_], |vec| vec.as_slice())
19174            .iter()
19175            .map(|highlight| (highlight.range.clone(), highlight.color))
19176    }
19177
19178    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19179    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19180    /// Allows to ignore certain kinds of highlights.
19181    pub fn highlighted_display_rows(
19182        &self,
19183        window: &mut Window,
19184        cx: &mut App,
19185    ) -> BTreeMap<DisplayRow, LineHighlight> {
19186        let snapshot = self.snapshot(window, cx);
19187        let mut used_highlight_orders = HashMap::default();
19188        self.highlighted_rows
19189            .iter()
19190            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19191            .fold(
19192                BTreeMap::<DisplayRow, LineHighlight>::new(),
19193                |mut unique_rows, highlight| {
19194                    let start = highlight.range.start.to_display_point(&snapshot);
19195                    let end = highlight.range.end.to_display_point(&snapshot);
19196                    let start_row = start.row().0;
19197                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19198                        && end.column() == 0
19199                    {
19200                        end.row().0.saturating_sub(1)
19201                    } else {
19202                        end.row().0
19203                    };
19204                    for row in start_row..=end_row {
19205                        let used_index =
19206                            used_highlight_orders.entry(row).or_insert(highlight.index);
19207                        if highlight.index >= *used_index {
19208                            *used_index = highlight.index;
19209                            unique_rows.insert(
19210                                DisplayRow(row),
19211                                LineHighlight {
19212                                    include_gutter: highlight.options.include_gutter,
19213                                    border: None,
19214                                    background: highlight.color.into(),
19215                                    type_id: Some(highlight.type_id),
19216                                },
19217                            );
19218                        }
19219                    }
19220                    unique_rows
19221                },
19222            )
19223    }
19224
19225    pub fn highlighted_display_row_for_autoscroll(
19226        &self,
19227        snapshot: &DisplaySnapshot,
19228    ) -> Option<DisplayRow> {
19229        self.highlighted_rows
19230            .values()
19231            .flat_map(|highlighted_rows| highlighted_rows.iter())
19232            .filter_map(|highlight| {
19233                if highlight.options.autoscroll {
19234                    Some(highlight.range.start.to_display_point(snapshot).row())
19235                } else {
19236                    None
19237                }
19238            })
19239            .min()
19240    }
19241
19242    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19243        self.highlight_background::<SearchWithinRange>(
19244            ranges,
19245            |colors| colors.colors().editor_document_highlight_read_background,
19246            cx,
19247        )
19248    }
19249
19250    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19251        self.breadcrumb_header = Some(new_header);
19252    }
19253
19254    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19255        self.clear_background_highlights::<SearchWithinRange>(cx);
19256    }
19257
19258    pub fn highlight_background<T: 'static>(
19259        &mut self,
19260        ranges: &[Range<Anchor>],
19261        color_fetcher: fn(&Theme) -> Hsla,
19262        cx: &mut Context<Self>,
19263    ) {
19264        self.background_highlights.insert(
19265            HighlightKey::Type(TypeId::of::<T>()),
19266            (color_fetcher, Arc::from(ranges)),
19267        );
19268        self.scrollbar_marker_state.dirty = true;
19269        cx.notify();
19270    }
19271
19272    pub fn highlight_background_key<T: 'static>(
19273        &mut self,
19274        key: usize,
19275        ranges: &[Range<Anchor>],
19276        color_fetcher: fn(&Theme) -> Hsla,
19277        cx: &mut Context<Self>,
19278    ) {
19279        self.background_highlights.insert(
19280            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19281            (color_fetcher, Arc::from(ranges)),
19282        );
19283        self.scrollbar_marker_state.dirty = true;
19284        cx.notify();
19285    }
19286
19287    pub fn clear_background_highlights<T: 'static>(
19288        &mut self,
19289        cx: &mut Context<Self>,
19290    ) -> Option<BackgroundHighlight> {
19291        let text_highlights = self
19292            .background_highlights
19293            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19294        if !text_highlights.1.is_empty() {
19295            self.scrollbar_marker_state.dirty = true;
19296            cx.notify();
19297        }
19298        Some(text_highlights)
19299    }
19300
19301    pub fn highlight_gutter<T: 'static>(
19302        &mut self,
19303        ranges: impl Into<Vec<Range<Anchor>>>,
19304        color_fetcher: fn(&App) -> Hsla,
19305        cx: &mut Context<Self>,
19306    ) {
19307        self.gutter_highlights
19308            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19309        cx.notify();
19310    }
19311
19312    pub fn clear_gutter_highlights<T: 'static>(
19313        &mut self,
19314        cx: &mut Context<Self>,
19315    ) -> Option<GutterHighlight> {
19316        cx.notify();
19317        self.gutter_highlights.remove(&TypeId::of::<T>())
19318    }
19319
19320    pub fn insert_gutter_highlight<T: 'static>(
19321        &mut self,
19322        range: Range<Anchor>,
19323        color_fetcher: fn(&App) -> Hsla,
19324        cx: &mut Context<Self>,
19325    ) {
19326        let snapshot = self.buffer().read(cx).snapshot(cx);
19327        let mut highlights = self
19328            .gutter_highlights
19329            .remove(&TypeId::of::<T>())
19330            .map(|(_, highlights)| highlights)
19331            .unwrap_or_default();
19332        let ix = highlights.binary_search_by(|highlight| {
19333            Ordering::Equal
19334                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19335                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19336        });
19337        if let Err(ix) = ix {
19338            highlights.insert(ix, range);
19339        }
19340        self.gutter_highlights
19341            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19342    }
19343
19344    pub fn remove_gutter_highlights<T: 'static>(
19345        &mut self,
19346        ranges_to_remove: Vec<Range<Anchor>>,
19347        cx: &mut Context<Self>,
19348    ) {
19349        let snapshot = self.buffer().read(cx).snapshot(cx);
19350        let Some((color_fetcher, mut gutter_highlights)) =
19351            self.gutter_highlights.remove(&TypeId::of::<T>())
19352        else {
19353            return;
19354        };
19355        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19356        gutter_highlights.retain(|highlight| {
19357            while let Some(range_to_remove) = ranges_to_remove.peek() {
19358                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19359                    Ordering::Less | Ordering::Equal => {
19360                        ranges_to_remove.next();
19361                    }
19362                    Ordering::Greater => {
19363                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19364                            Ordering::Less | Ordering::Equal => {
19365                                return false;
19366                            }
19367                            Ordering::Greater => break,
19368                        }
19369                    }
19370                }
19371            }
19372
19373            true
19374        });
19375        self.gutter_highlights
19376            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19377    }
19378
19379    #[cfg(feature = "test-support")]
19380    pub fn all_text_highlights(
19381        &self,
19382        window: &mut Window,
19383        cx: &mut Context<Self>,
19384    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19385        let snapshot = self.snapshot(window, cx);
19386        self.display_map.update(cx, |display_map, _| {
19387            display_map
19388                .all_text_highlights()
19389                .map(|highlight| {
19390                    let (style, ranges) = highlight.as_ref();
19391                    (
19392                        *style,
19393                        ranges
19394                            .iter()
19395                            .map(|range| range.clone().to_display_points(&snapshot))
19396                            .collect(),
19397                    )
19398                })
19399                .collect()
19400        })
19401    }
19402
19403    #[cfg(feature = "test-support")]
19404    pub fn all_text_background_highlights(
19405        &self,
19406        window: &mut Window,
19407        cx: &mut Context<Self>,
19408    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19409        let snapshot = self.snapshot(window, cx);
19410        let buffer = &snapshot.buffer_snapshot;
19411        let start = buffer.anchor_before(0);
19412        let end = buffer.anchor_after(buffer.len());
19413        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19414    }
19415
19416    #[cfg(feature = "test-support")]
19417    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19418        let snapshot = self.buffer().read(cx).snapshot(cx);
19419
19420        let highlights = self
19421            .background_highlights
19422            .get(&HighlightKey::Type(TypeId::of::<
19423                items::BufferSearchHighlights,
19424            >()));
19425
19426        if let Some((_color, ranges)) = highlights {
19427            ranges
19428                .iter()
19429                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19430                .collect_vec()
19431        } else {
19432            vec![]
19433        }
19434    }
19435
19436    fn document_highlights_for_position<'a>(
19437        &'a self,
19438        position: Anchor,
19439        buffer: &'a MultiBufferSnapshot,
19440    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19441        let read_highlights = self
19442            .background_highlights
19443            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19444            .map(|h| &h.1);
19445        let write_highlights = self
19446            .background_highlights
19447            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19448            .map(|h| &h.1);
19449        let left_position = position.bias_left(buffer);
19450        let right_position = position.bias_right(buffer);
19451        read_highlights
19452            .into_iter()
19453            .chain(write_highlights)
19454            .flat_map(move |ranges| {
19455                let start_ix = match ranges.binary_search_by(|probe| {
19456                    let cmp = probe.end.cmp(&left_position, buffer);
19457                    if cmp.is_ge() {
19458                        Ordering::Greater
19459                    } else {
19460                        Ordering::Less
19461                    }
19462                }) {
19463                    Ok(i) | Err(i) => i,
19464                };
19465
19466                ranges[start_ix..]
19467                    .iter()
19468                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19469            })
19470    }
19471
19472    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19473        self.background_highlights
19474            .get(&HighlightKey::Type(TypeId::of::<T>()))
19475            .map_or(false, |(_, highlights)| !highlights.is_empty())
19476    }
19477
19478    pub fn background_highlights_in_range(
19479        &self,
19480        search_range: Range<Anchor>,
19481        display_snapshot: &DisplaySnapshot,
19482        theme: &Theme,
19483    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19484        let mut results = Vec::new();
19485        for (color_fetcher, ranges) in self.background_highlights.values() {
19486            let color = color_fetcher(theme);
19487            let start_ix = match ranges.binary_search_by(|probe| {
19488                let cmp = probe
19489                    .end
19490                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19491                if cmp.is_gt() {
19492                    Ordering::Greater
19493                } else {
19494                    Ordering::Less
19495                }
19496            }) {
19497                Ok(i) | Err(i) => i,
19498            };
19499            for range in &ranges[start_ix..] {
19500                if range
19501                    .start
19502                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19503                    .is_ge()
19504                {
19505                    break;
19506                }
19507
19508                let start = range.start.to_display_point(display_snapshot);
19509                let end = range.end.to_display_point(display_snapshot);
19510                results.push((start..end, color))
19511            }
19512        }
19513        results
19514    }
19515
19516    pub fn background_highlight_row_ranges<T: 'static>(
19517        &self,
19518        search_range: Range<Anchor>,
19519        display_snapshot: &DisplaySnapshot,
19520        count: usize,
19521    ) -> Vec<RangeInclusive<DisplayPoint>> {
19522        let mut results = Vec::new();
19523        let Some((_, ranges)) = self
19524            .background_highlights
19525            .get(&HighlightKey::Type(TypeId::of::<T>()))
19526        else {
19527            return vec![];
19528        };
19529
19530        let start_ix = match ranges.binary_search_by(|probe| {
19531            let cmp = probe
19532                .end
19533                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19534            if cmp.is_gt() {
19535                Ordering::Greater
19536            } else {
19537                Ordering::Less
19538            }
19539        }) {
19540            Ok(i) | Err(i) => i,
19541        };
19542        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19543            if let (Some(start_display), Some(end_display)) = (start, end) {
19544                results.push(
19545                    start_display.to_display_point(display_snapshot)
19546                        ..=end_display.to_display_point(display_snapshot),
19547                );
19548            }
19549        };
19550        let mut start_row: Option<Point> = None;
19551        let mut end_row: Option<Point> = None;
19552        if ranges.len() > count {
19553            return Vec::new();
19554        }
19555        for range in &ranges[start_ix..] {
19556            if range
19557                .start
19558                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19559                .is_ge()
19560            {
19561                break;
19562            }
19563            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19564            if let Some(current_row) = &end_row {
19565                if end.row == current_row.row {
19566                    continue;
19567                }
19568            }
19569            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19570            if start_row.is_none() {
19571                assert_eq!(end_row, None);
19572                start_row = Some(start);
19573                end_row = Some(end);
19574                continue;
19575            }
19576            if let Some(current_end) = end_row.as_mut() {
19577                if start.row > current_end.row + 1 {
19578                    push_region(start_row, end_row);
19579                    start_row = Some(start);
19580                    end_row = Some(end);
19581                } else {
19582                    // Merge two hunks.
19583                    *current_end = end;
19584                }
19585            } else {
19586                unreachable!();
19587            }
19588        }
19589        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19590        push_region(start_row, end_row);
19591        results
19592    }
19593
19594    pub fn gutter_highlights_in_range(
19595        &self,
19596        search_range: Range<Anchor>,
19597        display_snapshot: &DisplaySnapshot,
19598        cx: &App,
19599    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19600        let mut results = Vec::new();
19601        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19602            let color = color_fetcher(cx);
19603            let start_ix = match ranges.binary_search_by(|probe| {
19604                let cmp = probe
19605                    .end
19606                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19607                if cmp.is_gt() {
19608                    Ordering::Greater
19609                } else {
19610                    Ordering::Less
19611                }
19612            }) {
19613                Ok(i) | Err(i) => i,
19614            };
19615            for range in &ranges[start_ix..] {
19616                if range
19617                    .start
19618                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19619                    .is_ge()
19620                {
19621                    break;
19622                }
19623
19624                let start = range.start.to_display_point(display_snapshot);
19625                let end = range.end.to_display_point(display_snapshot);
19626                results.push((start..end, color))
19627            }
19628        }
19629        results
19630    }
19631
19632    /// Get the text ranges corresponding to the redaction query
19633    pub fn redacted_ranges(
19634        &self,
19635        search_range: Range<Anchor>,
19636        display_snapshot: &DisplaySnapshot,
19637        cx: &App,
19638    ) -> Vec<Range<DisplayPoint>> {
19639        display_snapshot
19640            .buffer_snapshot
19641            .redacted_ranges(search_range, |file| {
19642                if let Some(file) = file {
19643                    file.is_private()
19644                        && EditorSettings::get(
19645                            Some(SettingsLocation {
19646                                worktree_id: file.worktree_id(cx),
19647                                path: file.path().as_ref(),
19648                            }),
19649                            cx,
19650                        )
19651                        .redact_private_values
19652                } else {
19653                    false
19654                }
19655            })
19656            .map(|range| {
19657                range.start.to_display_point(display_snapshot)
19658                    ..range.end.to_display_point(display_snapshot)
19659            })
19660            .collect()
19661    }
19662
19663    pub fn highlight_text_key<T: 'static>(
19664        &mut self,
19665        key: usize,
19666        ranges: Vec<Range<Anchor>>,
19667        style: HighlightStyle,
19668        cx: &mut Context<Self>,
19669    ) {
19670        self.display_map.update(cx, |map, _| {
19671            map.highlight_text(
19672                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19673                ranges,
19674                style,
19675            );
19676        });
19677        cx.notify();
19678    }
19679
19680    pub fn highlight_text<T: 'static>(
19681        &mut self,
19682        ranges: Vec<Range<Anchor>>,
19683        style: HighlightStyle,
19684        cx: &mut Context<Self>,
19685    ) {
19686        self.display_map.update(cx, |map, _| {
19687            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19688        });
19689        cx.notify();
19690    }
19691
19692    pub(crate) fn highlight_inlays<T: 'static>(
19693        &mut self,
19694        highlights: Vec<InlayHighlight>,
19695        style: HighlightStyle,
19696        cx: &mut Context<Self>,
19697    ) {
19698        self.display_map.update(cx, |map, _| {
19699            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19700        });
19701        cx.notify();
19702    }
19703
19704    pub fn text_highlights<'a, T: 'static>(
19705        &'a self,
19706        cx: &'a App,
19707    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19708        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19709    }
19710
19711    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19712        let cleared = self
19713            .display_map
19714            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19715        if cleared {
19716            cx.notify();
19717        }
19718    }
19719
19720    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19721        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19722            && self.focus_handle.is_focused(window)
19723    }
19724
19725    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19726        self.show_cursor_when_unfocused = is_enabled;
19727        cx.notify();
19728    }
19729
19730    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19731        cx.notify();
19732    }
19733
19734    fn on_debug_session_event(
19735        &mut self,
19736        _session: Entity<Session>,
19737        event: &SessionEvent,
19738        cx: &mut Context<Self>,
19739    ) {
19740        match event {
19741            SessionEvent::InvalidateInlineValue => {
19742                self.refresh_inline_values(cx);
19743            }
19744            _ => {}
19745        }
19746    }
19747
19748    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19749        let Some(project) = self.project.clone() else {
19750            return;
19751        };
19752
19753        if !self.inline_value_cache.enabled {
19754            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19755            self.splice_inlays(&inlays, Vec::new(), cx);
19756            return;
19757        }
19758
19759        let current_execution_position = self
19760            .highlighted_rows
19761            .get(&TypeId::of::<ActiveDebugLine>())
19762            .and_then(|lines| lines.last().map(|line| line.range.end));
19763
19764        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19765            let inline_values = editor
19766                .update(cx, |editor, cx| {
19767                    let Some(current_execution_position) = current_execution_position else {
19768                        return Some(Task::ready(Ok(Vec::new())));
19769                    };
19770
19771                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19772                        let snapshot = buffer.snapshot(cx);
19773
19774                        let excerpt = snapshot.excerpt_containing(
19775                            current_execution_position..current_execution_position,
19776                        )?;
19777
19778                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19779                    })?;
19780
19781                    let range =
19782                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19783
19784                    project.inline_values(buffer, range, cx)
19785                })
19786                .ok()
19787                .flatten()?
19788                .await
19789                .context("refreshing debugger inlays")
19790                .log_err()?;
19791
19792            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19793
19794            for (buffer_id, inline_value) in inline_values
19795                .into_iter()
19796                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19797            {
19798                buffer_inline_values
19799                    .entry(buffer_id)
19800                    .or_default()
19801                    .push(inline_value);
19802            }
19803
19804            editor
19805                .update(cx, |editor, cx| {
19806                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19807                    let mut new_inlays = Vec::default();
19808
19809                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19810                        let buffer_id = buffer_snapshot.remote_id();
19811                        buffer_inline_values
19812                            .get(&buffer_id)
19813                            .into_iter()
19814                            .flatten()
19815                            .for_each(|hint| {
19816                                let inlay = Inlay::debugger(
19817                                    post_inc(&mut editor.next_inlay_id),
19818                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19819                                    hint.text(),
19820                                );
19821                                if !inlay.text.chars().contains(&'\n') {
19822                                    new_inlays.push(inlay);
19823                                }
19824                            });
19825                    }
19826
19827                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19828                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19829
19830                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19831                })
19832                .ok()?;
19833            Some(())
19834        });
19835    }
19836
19837    fn on_buffer_event(
19838        &mut self,
19839        multibuffer: &Entity<MultiBuffer>,
19840        event: &multi_buffer::Event,
19841        window: &mut Window,
19842        cx: &mut Context<Self>,
19843    ) {
19844        match event {
19845            multi_buffer::Event::Edited {
19846                singleton_buffer_edited,
19847                edited_buffer,
19848            } => {
19849                self.scrollbar_marker_state.dirty = true;
19850                self.active_indent_guides_state.dirty = true;
19851                self.refresh_active_diagnostics(cx);
19852                self.refresh_code_actions(window, cx);
19853                self.refresh_selected_text_highlights(true, window, cx);
19854                self.refresh_single_line_folds(window, cx);
19855                refresh_matching_bracket_highlights(self, window, cx);
19856                if self.has_active_inline_completion() {
19857                    self.update_visible_inline_completion(window, cx);
19858                }
19859                if let Some(project) = self.project.as_ref() {
19860                    if let Some(edited_buffer) = edited_buffer {
19861                        project.update(cx, |project, cx| {
19862                            self.registered_buffers
19863                                .entry(edited_buffer.read(cx).remote_id())
19864                                .or_insert_with(|| {
19865                                    project
19866                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19867                                });
19868                        });
19869                    }
19870                }
19871                cx.emit(EditorEvent::BufferEdited);
19872                cx.emit(SearchEvent::MatchesInvalidated);
19873
19874                if let Some(buffer) = edited_buffer {
19875                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
19876                }
19877
19878                if *singleton_buffer_edited {
19879                    if let Some(buffer) = edited_buffer {
19880                        if buffer.read(cx).file().is_none() {
19881                            cx.emit(EditorEvent::TitleChanged);
19882                        }
19883                    }
19884                    if let Some(project) = &self.project {
19885                        #[allow(clippy::mutable_key_type)]
19886                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19887                            multibuffer
19888                                .all_buffers()
19889                                .into_iter()
19890                                .filter_map(|buffer| {
19891                                    buffer.update(cx, |buffer, cx| {
19892                                        let language = buffer.language()?;
19893                                        let should_discard = project.update(cx, |project, cx| {
19894                                            project.is_local()
19895                                                && !project.has_language_servers_for(buffer, cx)
19896                                        });
19897                                        should_discard.not().then_some(language.clone())
19898                                    })
19899                                })
19900                                .collect::<HashSet<_>>()
19901                        });
19902                        if !languages_affected.is_empty() {
19903                            self.refresh_inlay_hints(
19904                                InlayHintRefreshReason::BufferEdited(languages_affected),
19905                                cx,
19906                            );
19907                        }
19908                    }
19909                }
19910
19911                let Some(project) = &self.project else { return };
19912                let (telemetry, is_via_ssh) = {
19913                    let project = project.read(cx);
19914                    let telemetry = project.client().telemetry().clone();
19915                    let is_via_ssh = project.is_via_ssh();
19916                    (telemetry, is_via_ssh)
19917                };
19918                refresh_linked_ranges(self, window, cx);
19919                telemetry.log_edit_event("editor", is_via_ssh);
19920            }
19921            multi_buffer::Event::ExcerptsAdded {
19922                buffer,
19923                predecessor,
19924                excerpts,
19925            } => {
19926                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19927                let buffer_id = buffer.read(cx).remote_id();
19928                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19929                    if let Some(project) = &self.project {
19930                        update_uncommitted_diff_for_buffer(
19931                            cx.entity(),
19932                            project,
19933                            [buffer.clone()],
19934                            self.buffer.clone(),
19935                            cx,
19936                        )
19937                        .detach();
19938                    }
19939                }
19940                self.update_lsp_data(false, Some(buffer_id), window, cx);
19941                cx.emit(EditorEvent::ExcerptsAdded {
19942                    buffer: buffer.clone(),
19943                    predecessor: *predecessor,
19944                    excerpts: excerpts.clone(),
19945                });
19946                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19947            }
19948            multi_buffer::Event::ExcerptsRemoved {
19949                ids,
19950                removed_buffer_ids,
19951            } => {
19952                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19953                let buffer = self.buffer.read(cx);
19954                self.registered_buffers
19955                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19956                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19957                cx.emit(EditorEvent::ExcerptsRemoved {
19958                    ids: ids.clone(),
19959                    removed_buffer_ids: removed_buffer_ids.clone(),
19960                });
19961            }
19962            multi_buffer::Event::ExcerptsEdited {
19963                excerpt_ids,
19964                buffer_ids,
19965            } => {
19966                self.display_map.update(cx, |map, cx| {
19967                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19968                });
19969                cx.emit(EditorEvent::ExcerptsEdited {
19970                    ids: excerpt_ids.clone(),
19971                });
19972            }
19973            multi_buffer::Event::ExcerptsExpanded { ids } => {
19974                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19975                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19976            }
19977            multi_buffer::Event::Reparsed(buffer_id) => {
19978                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19979                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19980
19981                cx.emit(EditorEvent::Reparsed(*buffer_id));
19982            }
19983            multi_buffer::Event::DiffHunksToggled => {
19984                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19985            }
19986            multi_buffer::Event::LanguageChanged(buffer_id) => {
19987                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19988                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19989                cx.emit(EditorEvent::Reparsed(*buffer_id));
19990                cx.notify();
19991            }
19992            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19993            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19994            multi_buffer::Event::FileHandleChanged
19995            | multi_buffer::Event::Reloaded
19996            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19997            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19998            multi_buffer::Event::DiagnosticsUpdated => {
19999                self.update_diagnostics_state(window, cx);
20000            }
20001            _ => {}
20002        };
20003    }
20004
20005    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20006        if !self.diagnostics_enabled() {
20007            return;
20008        }
20009        self.refresh_active_diagnostics(cx);
20010        self.refresh_inline_diagnostics(true, window, cx);
20011        self.scrollbar_marker_state.dirty = true;
20012        cx.notify();
20013    }
20014
20015    pub fn start_temporary_diff_override(&mut self) {
20016        self.load_diff_task.take();
20017        self.temporary_diff_override = true;
20018    }
20019
20020    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20021        self.temporary_diff_override = false;
20022        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20023        self.buffer.update(cx, |buffer, cx| {
20024            buffer.set_all_diff_hunks_collapsed(cx);
20025        });
20026
20027        if let Some(project) = self.project.clone() {
20028            self.load_diff_task = Some(
20029                update_uncommitted_diff_for_buffer(
20030                    cx.entity(),
20031                    &project,
20032                    self.buffer.read(cx).all_buffers(),
20033                    self.buffer.clone(),
20034                    cx,
20035                )
20036                .shared(),
20037            );
20038        }
20039    }
20040
20041    fn on_display_map_changed(
20042        &mut self,
20043        _: Entity<DisplayMap>,
20044        _: &mut Window,
20045        cx: &mut Context<Self>,
20046    ) {
20047        cx.notify();
20048    }
20049
20050    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20051        if self.diagnostics_enabled() {
20052            let new_severity = EditorSettings::get_global(cx)
20053                .diagnostics_max_severity
20054                .unwrap_or(DiagnosticSeverity::Hint);
20055            self.set_max_diagnostics_severity(new_severity, cx);
20056        }
20057        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20058        self.update_edit_prediction_settings(cx);
20059        self.refresh_inline_completion(true, false, window, cx);
20060        self.refresh_inline_values(cx);
20061        self.refresh_inlay_hints(
20062            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20063                self.selections.newest_anchor().head(),
20064                &self.buffer.read(cx).snapshot(cx),
20065                cx,
20066            )),
20067            cx,
20068        );
20069
20070        let old_cursor_shape = self.cursor_shape;
20071
20072        {
20073            let editor_settings = EditorSettings::get_global(cx);
20074            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20075            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20076            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20077            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20078        }
20079
20080        if old_cursor_shape != self.cursor_shape {
20081            cx.emit(EditorEvent::CursorShapeChanged);
20082        }
20083
20084        let project_settings = ProjectSettings::get_global(cx);
20085        self.serialize_dirty_buffers =
20086            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20087
20088        if self.mode.is_full() {
20089            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20090            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20091            if self.show_inline_diagnostics != show_inline_diagnostics {
20092                self.show_inline_diagnostics = show_inline_diagnostics;
20093                self.refresh_inline_diagnostics(false, window, cx);
20094            }
20095
20096            if self.git_blame_inline_enabled != inline_blame_enabled {
20097                self.toggle_git_blame_inline_internal(false, window, cx);
20098            }
20099
20100            let minimap_settings = EditorSettings::get_global(cx).minimap;
20101            if self.minimap_visibility != MinimapVisibility::Disabled {
20102                if self.minimap_visibility.settings_visibility()
20103                    != minimap_settings.minimap_enabled()
20104                {
20105                    self.set_minimap_visibility(
20106                        MinimapVisibility::for_mode(self.mode(), cx),
20107                        window,
20108                        cx,
20109                    );
20110                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20111                    minimap_entity.update(cx, |minimap_editor, cx| {
20112                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20113                    })
20114                }
20115            }
20116        }
20117
20118        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20119            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20120        }) {
20121            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20122                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20123            }
20124            self.refresh_colors(false, None, window, cx);
20125        }
20126
20127        cx.notify();
20128    }
20129
20130    pub fn set_searchable(&mut self, searchable: bool) {
20131        self.searchable = searchable;
20132    }
20133
20134    pub fn searchable(&self) -> bool {
20135        self.searchable
20136    }
20137
20138    fn open_proposed_changes_editor(
20139        &mut self,
20140        _: &OpenProposedChangesEditor,
20141        window: &mut Window,
20142        cx: &mut Context<Self>,
20143    ) {
20144        let Some(workspace) = self.workspace() else {
20145            cx.propagate();
20146            return;
20147        };
20148
20149        let selections = self.selections.all::<usize>(cx);
20150        let multi_buffer = self.buffer.read(cx);
20151        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20152        let mut new_selections_by_buffer = HashMap::default();
20153        for selection in selections {
20154            for (buffer, range, _) in
20155                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20156            {
20157                let mut range = range.to_point(buffer);
20158                range.start.column = 0;
20159                range.end.column = buffer.line_len(range.end.row);
20160                new_selections_by_buffer
20161                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20162                    .or_insert(Vec::new())
20163                    .push(range)
20164            }
20165        }
20166
20167        let proposed_changes_buffers = new_selections_by_buffer
20168            .into_iter()
20169            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20170            .collect::<Vec<_>>();
20171        let proposed_changes_editor = cx.new(|cx| {
20172            ProposedChangesEditor::new(
20173                "Proposed changes",
20174                proposed_changes_buffers,
20175                self.project.clone(),
20176                window,
20177                cx,
20178            )
20179        });
20180
20181        window.defer(cx, move |window, cx| {
20182            workspace.update(cx, |workspace, cx| {
20183                workspace.active_pane().update(cx, |pane, cx| {
20184                    pane.add_item(
20185                        Box::new(proposed_changes_editor),
20186                        true,
20187                        true,
20188                        None,
20189                        window,
20190                        cx,
20191                    );
20192                });
20193            });
20194        });
20195    }
20196
20197    pub fn open_excerpts_in_split(
20198        &mut self,
20199        _: &OpenExcerptsSplit,
20200        window: &mut Window,
20201        cx: &mut Context<Self>,
20202    ) {
20203        self.open_excerpts_common(None, true, window, cx)
20204    }
20205
20206    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20207        self.open_excerpts_common(None, false, window, cx)
20208    }
20209
20210    fn open_excerpts_common(
20211        &mut self,
20212        jump_data: Option<JumpData>,
20213        split: bool,
20214        window: &mut Window,
20215        cx: &mut Context<Self>,
20216    ) {
20217        let Some(workspace) = self.workspace() else {
20218            cx.propagate();
20219            return;
20220        };
20221
20222        if self.buffer.read(cx).is_singleton() {
20223            cx.propagate();
20224            return;
20225        }
20226
20227        let mut new_selections_by_buffer = HashMap::default();
20228        match &jump_data {
20229            Some(JumpData::MultiBufferPoint {
20230                excerpt_id,
20231                position,
20232                anchor,
20233                line_offset_from_top,
20234            }) => {
20235                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20236                if let Some(buffer) = multi_buffer_snapshot
20237                    .buffer_id_for_excerpt(*excerpt_id)
20238                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20239                {
20240                    let buffer_snapshot = buffer.read(cx).snapshot();
20241                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20242                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20243                    } else {
20244                        buffer_snapshot.clip_point(*position, Bias::Left)
20245                    };
20246                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20247                    new_selections_by_buffer.insert(
20248                        buffer,
20249                        (
20250                            vec![jump_to_offset..jump_to_offset],
20251                            Some(*line_offset_from_top),
20252                        ),
20253                    );
20254                }
20255            }
20256            Some(JumpData::MultiBufferRow {
20257                row,
20258                line_offset_from_top,
20259            }) => {
20260                let point = MultiBufferPoint::new(row.0, 0);
20261                if let Some((buffer, buffer_point, _)) =
20262                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20263                {
20264                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20265                    new_selections_by_buffer
20266                        .entry(buffer)
20267                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20268                        .0
20269                        .push(buffer_offset..buffer_offset)
20270                }
20271            }
20272            None => {
20273                let selections = self.selections.all::<usize>(cx);
20274                let multi_buffer = self.buffer.read(cx);
20275                for selection in selections {
20276                    for (snapshot, range, _, anchor) in multi_buffer
20277                        .snapshot(cx)
20278                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20279                    {
20280                        if let Some(anchor) = anchor {
20281                            // selection is in a deleted hunk
20282                            let Some(buffer_id) = anchor.buffer_id else {
20283                                continue;
20284                            };
20285                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20286                                continue;
20287                            };
20288                            let offset = text::ToOffset::to_offset(
20289                                &anchor.text_anchor,
20290                                &buffer_handle.read(cx).snapshot(),
20291                            );
20292                            let range = offset..offset;
20293                            new_selections_by_buffer
20294                                .entry(buffer_handle)
20295                                .or_insert((Vec::new(), None))
20296                                .0
20297                                .push(range)
20298                        } else {
20299                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20300                            else {
20301                                continue;
20302                            };
20303                            new_selections_by_buffer
20304                                .entry(buffer_handle)
20305                                .or_insert((Vec::new(), None))
20306                                .0
20307                                .push(range)
20308                        }
20309                    }
20310                }
20311            }
20312        }
20313
20314        new_selections_by_buffer
20315            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20316
20317        if new_selections_by_buffer.is_empty() {
20318            return;
20319        }
20320
20321        // We defer the pane interaction because we ourselves are a workspace item
20322        // and activating a new item causes the pane to call a method on us reentrantly,
20323        // which panics if we're on the stack.
20324        window.defer(cx, move |window, cx| {
20325            workspace.update(cx, |workspace, cx| {
20326                let pane = if split {
20327                    workspace.adjacent_pane(window, cx)
20328                } else {
20329                    workspace.active_pane().clone()
20330                };
20331
20332                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20333                    let editor = buffer
20334                        .read(cx)
20335                        .file()
20336                        .is_none()
20337                        .then(|| {
20338                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20339                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20340                            // Instead, we try to activate the existing editor in the pane first.
20341                            let (editor, pane_item_index) =
20342                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20343                                    let editor = item.downcast::<Editor>()?;
20344                                    let singleton_buffer =
20345                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20346                                    if singleton_buffer == buffer {
20347                                        Some((editor, i))
20348                                    } else {
20349                                        None
20350                                    }
20351                                })?;
20352                            pane.update(cx, |pane, cx| {
20353                                pane.activate_item(pane_item_index, true, true, window, cx)
20354                            });
20355                            Some(editor)
20356                        })
20357                        .flatten()
20358                        .unwrap_or_else(|| {
20359                            workspace.open_project_item::<Self>(
20360                                pane.clone(),
20361                                buffer,
20362                                true,
20363                                true,
20364                                window,
20365                                cx,
20366                            )
20367                        });
20368
20369                    editor.update(cx, |editor, cx| {
20370                        let autoscroll = match scroll_offset {
20371                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20372                            None => Autoscroll::newest(),
20373                        };
20374                        let nav_history = editor.nav_history.take();
20375                        editor.change_selections(
20376                            SelectionEffects::scroll(autoscroll),
20377                            window,
20378                            cx,
20379                            |s| {
20380                                s.select_ranges(ranges);
20381                            },
20382                        );
20383                        editor.nav_history = nav_history;
20384                    });
20385                }
20386            })
20387        });
20388    }
20389
20390    // For now, don't allow opening excerpts in buffers that aren't backed by
20391    // regular project files.
20392    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20393        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20394    }
20395
20396    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20397        let snapshot = self.buffer.read(cx).read(cx);
20398        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20399        Some(
20400            ranges
20401                .iter()
20402                .map(move |range| {
20403                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20404                })
20405                .collect(),
20406        )
20407    }
20408
20409    fn selection_replacement_ranges(
20410        &self,
20411        range: Range<OffsetUtf16>,
20412        cx: &mut App,
20413    ) -> Vec<Range<OffsetUtf16>> {
20414        let selections = self.selections.all::<OffsetUtf16>(cx);
20415        let newest_selection = selections
20416            .iter()
20417            .max_by_key(|selection| selection.id)
20418            .unwrap();
20419        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20420        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20421        let snapshot = self.buffer.read(cx).read(cx);
20422        selections
20423            .into_iter()
20424            .map(|mut selection| {
20425                selection.start.0 =
20426                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20427                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20428                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20429                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20430            })
20431            .collect()
20432    }
20433
20434    fn report_editor_event(
20435        &self,
20436        event_type: &'static str,
20437        file_extension: Option<String>,
20438        cx: &App,
20439    ) {
20440        if cfg!(any(test, feature = "test-support")) {
20441            return;
20442        }
20443
20444        let Some(project) = &self.project else { return };
20445
20446        // If None, we are in a file without an extension
20447        let file = self
20448            .buffer
20449            .read(cx)
20450            .as_singleton()
20451            .and_then(|b| b.read(cx).file());
20452        let file_extension = file_extension.or(file
20453            .as_ref()
20454            .and_then(|file| Path::new(file.file_name(cx)).extension())
20455            .and_then(|e| e.to_str())
20456            .map(|a| a.to_string()));
20457
20458        let vim_mode = vim_enabled(cx);
20459
20460        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20461        let copilot_enabled = edit_predictions_provider
20462            == language::language_settings::EditPredictionProvider::Copilot;
20463        let copilot_enabled_for_language = self
20464            .buffer
20465            .read(cx)
20466            .language_settings(cx)
20467            .show_edit_predictions;
20468
20469        let project = project.read(cx);
20470        telemetry::event!(
20471            event_type,
20472            file_extension,
20473            vim_mode,
20474            copilot_enabled,
20475            copilot_enabled_for_language,
20476            edit_predictions_provider,
20477            is_via_ssh = project.is_via_ssh(),
20478        );
20479    }
20480
20481    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20482    /// with each line being an array of {text, highlight} objects.
20483    fn copy_highlight_json(
20484        &mut self,
20485        _: &CopyHighlightJson,
20486        window: &mut Window,
20487        cx: &mut Context<Self>,
20488    ) {
20489        #[derive(Serialize)]
20490        struct Chunk<'a> {
20491            text: String,
20492            highlight: Option<&'a str>,
20493        }
20494
20495        let snapshot = self.buffer.read(cx).snapshot(cx);
20496        let range = self
20497            .selected_text_range(false, window, cx)
20498            .and_then(|selection| {
20499                if selection.range.is_empty() {
20500                    None
20501                } else {
20502                    Some(selection.range)
20503                }
20504            })
20505            .unwrap_or_else(|| 0..snapshot.len());
20506
20507        let chunks = snapshot.chunks(range, true);
20508        let mut lines = Vec::new();
20509        let mut line: VecDeque<Chunk> = VecDeque::new();
20510
20511        let Some(style) = self.style.as_ref() else {
20512            return;
20513        };
20514
20515        for chunk in chunks {
20516            let highlight = chunk
20517                .syntax_highlight_id
20518                .and_then(|id| id.name(&style.syntax));
20519            let mut chunk_lines = chunk.text.split('\n').peekable();
20520            while let Some(text) = chunk_lines.next() {
20521                let mut merged_with_last_token = false;
20522                if let Some(last_token) = line.back_mut() {
20523                    if last_token.highlight == highlight {
20524                        last_token.text.push_str(text);
20525                        merged_with_last_token = true;
20526                    }
20527                }
20528
20529                if !merged_with_last_token {
20530                    line.push_back(Chunk {
20531                        text: text.into(),
20532                        highlight,
20533                    });
20534                }
20535
20536                if chunk_lines.peek().is_some() {
20537                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20538                        line.pop_front();
20539                    }
20540                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20541                        line.pop_back();
20542                    }
20543
20544                    lines.push(mem::take(&mut line));
20545                }
20546            }
20547        }
20548
20549        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20550            return;
20551        };
20552        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20553    }
20554
20555    pub fn open_context_menu(
20556        &mut self,
20557        _: &OpenContextMenu,
20558        window: &mut Window,
20559        cx: &mut Context<Self>,
20560    ) {
20561        self.request_autoscroll(Autoscroll::newest(), cx);
20562        let position = self.selections.newest_display(cx).start;
20563        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20564    }
20565
20566    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20567        &self.inlay_hint_cache
20568    }
20569
20570    pub fn replay_insert_event(
20571        &mut self,
20572        text: &str,
20573        relative_utf16_range: Option<Range<isize>>,
20574        window: &mut Window,
20575        cx: &mut Context<Self>,
20576    ) {
20577        if !self.input_enabled {
20578            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20579            return;
20580        }
20581        if let Some(relative_utf16_range) = relative_utf16_range {
20582            let selections = self.selections.all::<OffsetUtf16>(cx);
20583            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20584                let new_ranges = selections.into_iter().map(|range| {
20585                    let start = OffsetUtf16(
20586                        range
20587                            .head()
20588                            .0
20589                            .saturating_add_signed(relative_utf16_range.start),
20590                    );
20591                    let end = OffsetUtf16(
20592                        range
20593                            .head()
20594                            .0
20595                            .saturating_add_signed(relative_utf16_range.end),
20596                    );
20597                    start..end
20598                });
20599                s.select_ranges(new_ranges);
20600            });
20601        }
20602
20603        self.handle_input(text, window, cx);
20604    }
20605
20606    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20607        let Some(provider) = self.semantics_provider.as_ref() else {
20608            return false;
20609        };
20610
20611        let mut supports = false;
20612        self.buffer().update(cx, |this, cx| {
20613            this.for_each_buffer(|buffer| {
20614                supports |= provider.supports_inlay_hints(buffer, cx);
20615            });
20616        });
20617
20618        supports
20619    }
20620
20621    pub fn is_focused(&self, window: &Window) -> bool {
20622        self.focus_handle.is_focused(window)
20623    }
20624
20625    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20626        cx.emit(EditorEvent::Focused);
20627
20628        if let Some(descendant) = self
20629            .last_focused_descendant
20630            .take()
20631            .and_then(|descendant| descendant.upgrade())
20632        {
20633            window.focus(&descendant);
20634        } else {
20635            if let Some(blame) = self.blame.as_ref() {
20636                blame.update(cx, GitBlame::focus)
20637            }
20638
20639            self.blink_manager.update(cx, BlinkManager::enable);
20640            self.show_cursor_names(window, cx);
20641            self.buffer.update(cx, |buffer, cx| {
20642                buffer.finalize_last_transaction(cx);
20643                if self.leader_id.is_none() {
20644                    buffer.set_active_selections(
20645                        &self.selections.disjoint_anchors(),
20646                        self.selections.line_mode,
20647                        self.cursor_shape,
20648                        cx,
20649                    );
20650                }
20651            });
20652        }
20653    }
20654
20655    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20656        cx.emit(EditorEvent::FocusedIn)
20657    }
20658
20659    fn handle_focus_out(
20660        &mut self,
20661        event: FocusOutEvent,
20662        _window: &mut Window,
20663        cx: &mut Context<Self>,
20664    ) {
20665        if event.blurred != self.focus_handle {
20666            self.last_focused_descendant = Some(event.blurred);
20667        }
20668        self.selection_drag_state = SelectionDragState::None;
20669        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20670    }
20671
20672    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20673        self.blink_manager.update(cx, BlinkManager::disable);
20674        self.buffer
20675            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20676
20677        if let Some(blame) = self.blame.as_ref() {
20678            blame.update(cx, GitBlame::blur)
20679        }
20680        if !self.hover_state.focused(window, cx) {
20681            hide_hover(self, cx);
20682        }
20683        if !self
20684            .context_menu
20685            .borrow()
20686            .as_ref()
20687            .is_some_and(|context_menu| context_menu.focused(window, cx))
20688        {
20689            self.hide_context_menu(window, cx);
20690        }
20691        self.discard_inline_completion(false, cx);
20692        cx.emit(EditorEvent::Blurred);
20693        cx.notify();
20694    }
20695
20696    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20697        let mut pending: String = window
20698            .pending_input_keystrokes()
20699            .into_iter()
20700            .flatten()
20701            .filter_map(|keystroke| {
20702                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20703                    keystroke.key_char.clone()
20704                } else {
20705                    None
20706                }
20707            })
20708            .collect();
20709
20710        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20711            pending = "".to_string();
20712        }
20713
20714        let existing_pending = self
20715            .text_highlights::<PendingInput>(cx)
20716            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20717        if existing_pending.is_none() && pending.is_empty() {
20718            return;
20719        }
20720        let transaction =
20721            self.transact(window, cx, |this, window, cx| {
20722                let selections = this.selections.all::<usize>(cx);
20723                let edits = selections
20724                    .iter()
20725                    .map(|selection| (selection.end..selection.end, pending.clone()));
20726                this.edit(edits, cx);
20727                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20728                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20729                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20730                    }));
20731                });
20732                if let Some(existing_ranges) = existing_pending {
20733                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20734                    this.edit(edits, cx);
20735                }
20736            });
20737
20738        let snapshot = self.snapshot(window, cx);
20739        let ranges = self
20740            .selections
20741            .all::<usize>(cx)
20742            .into_iter()
20743            .map(|selection| {
20744                snapshot.buffer_snapshot.anchor_after(selection.end)
20745                    ..snapshot
20746                        .buffer_snapshot
20747                        .anchor_before(selection.end + pending.len())
20748            })
20749            .collect();
20750
20751        if pending.is_empty() {
20752            self.clear_highlights::<PendingInput>(cx);
20753        } else {
20754            self.highlight_text::<PendingInput>(
20755                ranges,
20756                HighlightStyle {
20757                    underline: Some(UnderlineStyle {
20758                        thickness: px(1.),
20759                        color: None,
20760                        wavy: false,
20761                    }),
20762                    ..Default::default()
20763                },
20764                cx,
20765            );
20766        }
20767
20768        self.ime_transaction = self.ime_transaction.or(transaction);
20769        if let Some(transaction) = self.ime_transaction {
20770            self.buffer.update(cx, |buffer, cx| {
20771                buffer.group_until_transaction(transaction, cx);
20772            });
20773        }
20774
20775        if self.text_highlights::<PendingInput>(cx).is_none() {
20776            self.ime_transaction.take();
20777        }
20778    }
20779
20780    pub fn register_action_renderer(
20781        &mut self,
20782        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20783    ) -> Subscription {
20784        let id = self.next_editor_action_id.post_inc();
20785        self.editor_actions
20786            .borrow_mut()
20787            .insert(id, Box::new(listener));
20788
20789        let editor_actions = self.editor_actions.clone();
20790        Subscription::new(move || {
20791            editor_actions.borrow_mut().remove(&id);
20792        })
20793    }
20794
20795    pub fn register_action<A: Action>(
20796        &mut self,
20797        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20798    ) -> Subscription {
20799        let id = self.next_editor_action_id.post_inc();
20800        let listener = Arc::new(listener);
20801        self.editor_actions.borrow_mut().insert(
20802            id,
20803            Box::new(move |_, window, _| {
20804                let listener = listener.clone();
20805                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20806                    let action = action.downcast_ref().unwrap();
20807                    if phase == DispatchPhase::Bubble {
20808                        listener(action, window, cx)
20809                    }
20810                })
20811            }),
20812        );
20813
20814        let editor_actions = self.editor_actions.clone();
20815        Subscription::new(move || {
20816            editor_actions.borrow_mut().remove(&id);
20817        })
20818    }
20819
20820    pub fn file_header_size(&self) -> u32 {
20821        FILE_HEADER_HEIGHT
20822    }
20823
20824    pub fn restore(
20825        &mut self,
20826        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20827        window: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) {
20830        let workspace = self.workspace();
20831        let project = self.project.as_ref();
20832        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20833            let mut tasks = Vec::new();
20834            for (buffer_id, changes) in revert_changes {
20835                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20836                    buffer.update(cx, |buffer, cx| {
20837                        buffer.edit(
20838                            changes
20839                                .into_iter()
20840                                .map(|(range, text)| (range, text.to_string())),
20841                            None,
20842                            cx,
20843                        );
20844                    });
20845
20846                    if let Some(project) =
20847                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20848                    {
20849                        project.update(cx, |project, cx| {
20850                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20851                        })
20852                    }
20853                }
20854            }
20855            tasks
20856        });
20857        cx.spawn_in(window, async move |_, cx| {
20858            for (buffer, task) in save_tasks {
20859                let result = task.await;
20860                if result.is_err() {
20861                    let Some(path) = buffer
20862                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20863                        .ok()
20864                    else {
20865                        continue;
20866                    };
20867                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20868                        let Some(task) = cx
20869                            .update_window_entity(&workspace, |workspace, window, cx| {
20870                                workspace
20871                                    .open_path_preview(path, None, false, false, false, window, cx)
20872                            })
20873                            .ok()
20874                        else {
20875                            continue;
20876                        };
20877                        task.await.log_err();
20878                    }
20879                }
20880            }
20881        })
20882        .detach();
20883        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
20884            selections.refresh()
20885        });
20886    }
20887
20888    pub fn to_pixel_point(
20889        &self,
20890        source: multi_buffer::Anchor,
20891        editor_snapshot: &EditorSnapshot,
20892        window: &mut Window,
20893    ) -> Option<gpui::Point<Pixels>> {
20894        let source_point = source.to_display_point(editor_snapshot);
20895        self.display_to_pixel_point(source_point, editor_snapshot, window)
20896    }
20897
20898    pub fn display_to_pixel_point(
20899        &self,
20900        source: DisplayPoint,
20901        editor_snapshot: &EditorSnapshot,
20902        window: &mut Window,
20903    ) -> Option<gpui::Point<Pixels>> {
20904        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20905        let text_layout_details = self.text_layout_details(window);
20906        let scroll_top = text_layout_details
20907            .scroll_anchor
20908            .scroll_position(editor_snapshot)
20909            .y;
20910
20911        if source.row().as_f32() < scroll_top.floor() {
20912            return None;
20913        }
20914        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20915        let source_y = line_height * (source.row().as_f32() - scroll_top);
20916        Some(gpui::Point::new(source_x, source_y))
20917    }
20918
20919    pub fn has_visible_completions_menu(&self) -> bool {
20920        !self.edit_prediction_preview_is_active()
20921            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20922                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20923            })
20924    }
20925
20926    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20927        if self.mode.is_minimap() {
20928            return;
20929        }
20930        self.addons
20931            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20932    }
20933
20934    pub fn unregister_addon<T: Addon>(&mut self) {
20935        self.addons.remove(&std::any::TypeId::of::<T>());
20936    }
20937
20938    pub fn addon<T: Addon>(&self) -> Option<&T> {
20939        let type_id = std::any::TypeId::of::<T>();
20940        self.addons
20941            .get(&type_id)
20942            .and_then(|item| item.to_any().downcast_ref::<T>())
20943    }
20944
20945    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20946        let type_id = std::any::TypeId::of::<T>();
20947        self.addons
20948            .get_mut(&type_id)
20949            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20950    }
20951
20952    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
20953        let text_layout_details = self.text_layout_details(window);
20954        let style = &text_layout_details.editor_style;
20955        let font_id = window.text_system().resolve_font(&style.text.font());
20956        let font_size = style.text.font_size.to_pixels(window.rem_size());
20957        let line_height = style.text.line_height_in_pixels(window.rem_size());
20958        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20959        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
20960
20961        CharacterDimensions {
20962            em_width,
20963            em_advance,
20964            line_height,
20965        }
20966    }
20967
20968    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20969        self.load_diff_task.clone()
20970    }
20971
20972    fn read_metadata_from_db(
20973        &mut self,
20974        item_id: u64,
20975        workspace_id: WorkspaceId,
20976        window: &mut Window,
20977        cx: &mut Context<Editor>,
20978    ) {
20979        if self.is_singleton(cx)
20980            && !self.mode.is_minimap()
20981            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20982        {
20983            let buffer_snapshot = OnceCell::new();
20984
20985            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20986                if !folds.is_empty() {
20987                    let snapshot =
20988                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20989                    self.fold_ranges(
20990                        folds
20991                            .into_iter()
20992                            .map(|(start, end)| {
20993                                snapshot.clip_offset(start, Bias::Left)
20994                                    ..snapshot.clip_offset(end, Bias::Right)
20995                            })
20996                            .collect(),
20997                        false,
20998                        window,
20999                        cx,
21000                    );
21001                }
21002            }
21003
21004            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21005                if !selections.is_empty() {
21006                    let snapshot =
21007                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21008                    // skip adding the initial selection to selection history
21009                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21010                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21011                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21012                            snapshot.clip_offset(start, Bias::Left)
21013                                ..snapshot.clip_offset(end, Bias::Right)
21014                        }));
21015                    });
21016                    self.selection_history.mode = SelectionHistoryMode::Normal;
21017                }
21018            };
21019        }
21020
21021        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21022    }
21023
21024    fn update_lsp_data(
21025        &mut self,
21026        ignore_cache: bool,
21027        for_buffer: Option<BufferId>,
21028        window: &mut Window,
21029        cx: &mut Context<'_, Self>,
21030    ) {
21031        self.pull_diagnostics(for_buffer, window, cx);
21032        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21033    }
21034}
21035
21036fn vim_enabled(cx: &App) -> bool {
21037    cx.global::<SettingsStore>()
21038        .raw_user_settings()
21039        .get("vim_mode")
21040        == Some(&serde_json::Value::Bool(true))
21041}
21042
21043fn process_completion_for_edit(
21044    completion: &Completion,
21045    intent: CompletionIntent,
21046    buffer: &Entity<Buffer>,
21047    cursor_position: &text::Anchor,
21048    cx: &mut Context<Editor>,
21049) -> CompletionEdit {
21050    let buffer = buffer.read(cx);
21051    let buffer_snapshot = buffer.snapshot();
21052    let (snippet, new_text) = if completion.is_snippet() {
21053        // Workaround for typescript language server issues so that methods don't expand within
21054        // strings and functions with type expressions. The previous point is used because the query
21055        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21056        let mut snippet_source = completion.new_text.clone();
21057        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21058        previous_point.column = previous_point.column.saturating_sub(1);
21059        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21060            if scope.prefers_label_for_snippet_in_completion() {
21061                if let Some(label) = completion.label() {
21062                    if matches!(
21063                        completion.kind(),
21064                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21065                    ) {
21066                        snippet_source = label;
21067                    }
21068                }
21069            }
21070        }
21071        match Snippet::parse(&snippet_source).log_err() {
21072            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21073            None => (None, completion.new_text.clone()),
21074        }
21075    } else {
21076        (None, completion.new_text.clone())
21077    };
21078
21079    let mut range_to_replace = {
21080        let replace_range = &completion.replace_range;
21081        if let CompletionSource::Lsp {
21082            insert_range: Some(insert_range),
21083            ..
21084        } = &completion.source
21085        {
21086            debug_assert_eq!(
21087                insert_range.start, replace_range.start,
21088                "insert_range and replace_range should start at the same position"
21089            );
21090            debug_assert!(
21091                insert_range
21092                    .start
21093                    .cmp(&cursor_position, &buffer_snapshot)
21094                    .is_le(),
21095                "insert_range should start before or at cursor position"
21096            );
21097            debug_assert!(
21098                replace_range
21099                    .start
21100                    .cmp(&cursor_position, &buffer_snapshot)
21101                    .is_le(),
21102                "replace_range should start before or at cursor position"
21103            );
21104            debug_assert!(
21105                insert_range
21106                    .end
21107                    .cmp(&cursor_position, &buffer_snapshot)
21108                    .is_le(),
21109                "insert_range should end before or at cursor position"
21110            );
21111
21112            let should_replace = match intent {
21113                CompletionIntent::CompleteWithInsert => false,
21114                CompletionIntent::CompleteWithReplace => true,
21115                CompletionIntent::Complete | CompletionIntent::Compose => {
21116                    let insert_mode =
21117                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21118                            .completions
21119                            .lsp_insert_mode;
21120                    match insert_mode {
21121                        LspInsertMode::Insert => false,
21122                        LspInsertMode::Replace => true,
21123                        LspInsertMode::ReplaceSubsequence => {
21124                            let mut text_to_replace = buffer.chars_for_range(
21125                                buffer.anchor_before(replace_range.start)
21126                                    ..buffer.anchor_after(replace_range.end),
21127                            );
21128                            let mut current_needle = text_to_replace.next();
21129                            for haystack_ch in completion.label.text.chars() {
21130                                if let Some(needle_ch) = current_needle {
21131                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21132                                        current_needle = text_to_replace.next();
21133                                    }
21134                                }
21135                            }
21136                            current_needle.is_none()
21137                        }
21138                        LspInsertMode::ReplaceSuffix => {
21139                            if replace_range
21140                                .end
21141                                .cmp(&cursor_position, &buffer_snapshot)
21142                                .is_gt()
21143                            {
21144                                let range_after_cursor = *cursor_position..replace_range.end;
21145                                let text_after_cursor = buffer
21146                                    .text_for_range(
21147                                        buffer.anchor_before(range_after_cursor.start)
21148                                            ..buffer.anchor_after(range_after_cursor.end),
21149                                    )
21150                                    .collect::<String>()
21151                                    .to_ascii_lowercase();
21152                                completion
21153                                    .label
21154                                    .text
21155                                    .to_ascii_lowercase()
21156                                    .ends_with(&text_after_cursor)
21157                            } else {
21158                                true
21159                            }
21160                        }
21161                    }
21162                }
21163            };
21164
21165            if should_replace {
21166                replace_range.clone()
21167            } else {
21168                insert_range.clone()
21169            }
21170        } else {
21171            replace_range.clone()
21172        }
21173    };
21174
21175    if range_to_replace
21176        .end
21177        .cmp(&cursor_position, &buffer_snapshot)
21178        .is_lt()
21179    {
21180        range_to_replace.end = *cursor_position;
21181    }
21182
21183    CompletionEdit {
21184        new_text,
21185        replace_range: range_to_replace.to_offset(&buffer),
21186        snippet,
21187    }
21188}
21189
21190struct CompletionEdit {
21191    new_text: String,
21192    replace_range: Range<usize>,
21193    snippet: Option<Snippet>,
21194}
21195
21196fn insert_extra_newline_brackets(
21197    buffer: &MultiBufferSnapshot,
21198    range: Range<usize>,
21199    language: &language::LanguageScope,
21200) -> bool {
21201    let leading_whitespace_len = buffer
21202        .reversed_chars_at(range.start)
21203        .take_while(|c| c.is_whitespace() && *c != '\n')
21204        .map(|c| c.len_utf8())
21205        .sum::<usize>();
21206    let trailing_whitespace_len = buffer
21207        .chars_at(range.end)
21208        .take_while(|c| c.is_whitespace() && *c != '\n')
21209        .map(|c| c.len_utf8())
21210        .sum::<usize>();
21211    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21212
21213    language.brackets().any(|(pair, enabled)| {
21214        let pair_start = pair.start.trim_end();
21215        let pair_end = pair.end.trim_start();
21216
21217        enabled
21218            && pair.newline
21219            && buffer.contains_str_at(range.end, pair_end)
21220            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21221    })
21222}
21223
21224fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21225    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21226        [(buffer, range, _)] => (*buffer, range.clone()),
21227        _ => return false,
21228    };
21229    let pair = {
21230        let mut result: Option<BracketMatch> = None;
21231
21232        for pair in buffer
21233            .all_bracket_ranges(range.clone())
21234            .filter(move |pair| {
21235                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21236            })
21237        {
21238            let len = pair.close_range.end - pair.open_range.start;
21239
21240            if let Some(existing) = &result {
21241                let existing_len = existing.close_range.end - existing.open_range.start;
21242                if len > existing_len {
21243                    continue;
21244                }
21245            }
21246
21247            result = Some(pair);
21248        }
21249
21250        result
21251    };
21252    let Some(pair) = pair else {
21253        return false;
21254    };
21255    pair.newline_only
21256        && buffer
21257            .chars_for_range(pair.open_range.end..range.start)
21258            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21259            .all(|c| c.is_whitespace() && c != '\n')
21260}
21261
21262fn update_uncommitted_diff_for_buffer(
21263    editor: Entity<Editor>,
21264    project: &Entity<Project>,
21265    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21266    buffer: Entity<MultiBuffer>,
21267    cx: &mut App,
21268) -> Task<()> {
21269    let mut tasks = Vec::new();
21270    project.update(cx, |project, cx| {
21271        for buffer in buffers {
21272            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21273                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21274            }
21275        }
21276    });
21277    cx.spawn(async move |cx| {
21278        let diffs = future::join_all(tasks).await;
21279        if editor
21280            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21281            .unwrap_or(false)
21282        {
21283            return;
21284        }
21285
21286        buffer
21287            .update(cx, |buffer, cx| {
21288                for diff in diffs.into_iter().flatten() {
21289                    buffer.add_diff(diff, cx);
21290                }
21291            })
21292            .ok();
21293    })
21294}
21295
21296fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21297    let tab_size = tab_size.get() as usize;
21298    let mut width = offset;
21299
21300    for ch in text.chars() {
21301        width += if ch == '\t' {
21302            tab_size - (width % tab_size)
21303        } else {
21304            1
21305        };
21306    }
21307
21308    width - offset
21309}
21310
21311#[cfg(test)]
21312mod tests {
21313    use super::*;
21314
21315    #[test]
21316    fn test_string_size_with_expanded_tabs() {
21317        let nz = |val| NonZeroU32::new(val).unwrap();
21318        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21319        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21320        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21321        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21322        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21323        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21324        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21325        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21326    }
21327}
21328
21329/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21330struct WordBreakingTokenizer<'a> {
21331    input: &'a str,
21332}
21333
21334impl<'a> WordBreakingTokenizer<'a> {
21335    fn new(input: &'a str) -> Self {
21336        Self { input }
21337    }
21338}
21339
21340fn is_char_ideographic(ch: char) -> bool {
21341    use unicode_script::Script::*;
21342    use unicode_script::UnicodeScript;
21343    matches!(ch.script(), Han | Tangut | Yi)
21344}
21345
21346fn is_grapheme_ideographic(text: &str) -> bool {
21347    text.chars().any(is_char_ideographic)
21348}
21349
21350fn is_grapheme_whitespace(text: &str) -> bool {
21351    text.chars().any(|x| x.is_whitespace())
21352}
21353
21354fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21355    text.chars().next().map_or(false, |ch| {
21356        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21357    })
21358}
21359
21360#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21361enum WordBreakToken<'a> {
21362    Word { token: &'a str, grapheme_len: usize },
21363    InlineWhitespace { token: &'a str, grapheme_len: usize },
21364    Newline,
21365}
21366
21367impl<'a> Iterator for WordBreakingTokenizer<'a> {
21368    /// Yields a span, the count of graphemes in the token, and whether it was
21369    /// whitespace. Note that it also breaks at word boundaries.
21370    type Item = WordBreakToken<'a>;
21371
21372    fn next(&mut self) -> Option<Self::Item> {
21373        use unicode_segmentation::UnicodeSegmentation;
21374        if self.input.is_empty() {
21375            return None;
21376        }
21377
21378        let mut iter = self.input.graphemes(true).peekable();
21379        let mut offset = 0;
21380        let mut grapheme_len = 0;
21381        if let Some(first_grapheme) = iter.next() {
21382            let is_newline = first_grapheme == "\n";
21383            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21384            offset += first_grapheme.len();
21385            grapheme_len += 1;
21386            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21387                if let Some(grapheme) = iter.peek().copied() {
21388                    if should_stay_with_preceding_ideograph(grapheme) {
21389                        offset += grapheme.len();
21390                        grapheme_len += 1;
21391                    }
21392                }
21393            } else {
21394                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21395                let mut next_word_bound = words.peek().copied();
21396                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21397                    next_word_bound = words.next();
21398                }
21399                while let Some(grapheme) = iter.peek().copied() {
21400                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21401                        break;
21402                    };
21403                    if is_grapheme_whitespace(grapheme) != is_whitespace
21404                        || (grapheme == "\n") != is_newline
21405                    {
21406                        break;
21407                    };
21408                    offset += grapheme.len();
21409                    grapheme_len += 1;
21410                    iter.next();
21411                }
21412            }
21413            let token = &self.input[..offset];
21414            self.input = &self.input[offset..];
21415            if token == "\n" {
21416                Some(WordBreakToken::Newline)
21417            } else if is_whitespace {
21418                Some(WordBreakToken::InlineWhitespace {
21419                    token,
21420                    grapheme_len,
21421                })
21422            } else {
21423                Some(WordBreakToken::Word {
21424                    token,
21425                    grapheme_len,
21426                })
21427            }
21428        } else {
21429            None
21430        }
21431    }
21432}
21433
21434#[test]
21435fn test_word_breaking_tokenizer() {
21436    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21437        ("", &[]),
21438        ("  ", &[whitespace("  ", 2)]),
21439        ("Ʒ", &[word("Ʒ", 1)]),
21440        ("Ǽ", &[word("Ǽ", 1)]),
21441        ("", &[word("", 1)]),
21442        ("⋑⋑", &[word("⋑⋑", 2)]),
21443        (
21444            "原理,进而",
21445            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21446        ),
21447        (
21448            "hello world",
21449            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21450        ),
21451        (
21452            "hello, world",
21453            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21454        ),
21455        (
21456            "  hello world",
21457            &[
21458                whitespace("  ", 2),
21459                word("hello", 5),
21460                whitespace(" ", 1),
21461                word("world", 5),
21462            ],
21463        ),
21464        (
21465            "这是什么 \n 钢笔",
21466            &[
21467                word("", 1),
21468                word("", 1),
21469                word("", 1),
21470                word("", 1),
21471                whitespace(" ", 1),
21472                newline(),
21473                whitespace(" ", 1),
21474                word("", 1),
21475                word("", 1),
21476            ],
21477        ),
21478        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21479    ];
21480
21481    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21482        WordBreakToken::Word {
21483            token,
21484            grapheme_len,
21485        }
21486    }
21487
21488    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21489        WordBreakToken::InlineWhitespace {
21490            token,
21491            grapheme_len,
21492        }
21493    }
21494
21495    fn newline() -> WordBreakToken<'static> {
21496        WordBreakToken::Newline
21497    }
21498
21499    for (input, result) in tests {
21500        assert_eq!(
21501            WordBreakingTokenizer::new(input)
21502                .collect::<Vec<_>>()
21503                .as_slice(),
21504            *result,
21505        );
21506    }
21507}
21508
21509fn wrap_with_prefix(
21510    first_line_prefix: String,
21511    subsequent_lines_prefix: String,
21512    unwrapped_text: String,
21513    wrap_column: usize,
21514    tab_size: NonZeroU32,
21515    preserve_existing_whitespace: bool,
21516) -> String {
21517    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21518    let subsequent_lines_prefix_len =
21519        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21520    let mut wrapped_text = String::new();
21521    let mut current_line = first_line_prefix.clone();
21522    let mut is_first_line = true;
21523
21524    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21525    let mut current_line_len = first_line_prefix_len;
21526    let mut in_whitespace = false;
21527    for token in tokenizer {
21528        let have_preceding_whitespace = in_whitespace;
21529        match token {
21530            WordBreakToken::Word {
21531                token,
21532                grapheme_len,
21533            } => {
21534                in_whitespace = false;
21535                let current_prefix_len = if is_first_line {
21536                    first_line_prefix_len
21537                } else {
21538                    subsequent_lines_prefix_len
21539                };
21540                if current_line_len + grapheme_len > wrap_column
21541                    && current_line_len != current_prefix_len
21542                {
21543                    wrapped_text.push_str(current_line.trim_end());
21544                    wrapped_text.push('\n');
21545                    is_first_line = false;
21546                    current_line = subsequent_lines_prefix.clone();
21547                    current_line_len = subsequent_lines_prefix_len;
21548                }
21549                current_line.push_str(token);
21550                current_line_len += grapheme_len;
21551            }
21552            WordBreakToken::InlineWhitespace {
21553                mut token,
21554                mut grapheme_len,
21555            } => {
21556                in_whitespace = true;
21557                if have_preceding_whitespace && !preserve_existing_whitespace {
21558                    continue;
21559                }
21560                if !preserve_existing_whitespace {
21561                    token = " ";
21562                    grapheme_len = 1;
21563                }
21564                let current_prefix_len = if is_first_line {
21565                    first_line_prefix_len
21566                } else {
21567                    subsequent_lines_prefix_len
21568                };
21569                if current_line_len + grapheme_len > wrap_column {
21570                    wrapped_text.push_str(current_line.trim_end());
21571                    wrapped_text.push('\n');
21572                    is_first_line = false;
21573                    current_line = subsequent_lines_prefix.clone();
21574                    current_line_len = subsequent_lines_prefix_len;
21575                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21576                    current_line.push_str(token);
21577                    current_line_len += grapheme_len;
21578                }
21579            }
21580            WordBreakToken::Newline => {
21581                in_whitespace = true;
21582                let current_prefix_len = if is_first_line {
21583                    first_line_prefix_len
21584                } else {
21585                    subsequent_lines_prefix_len
21586                };
21587                if preserve_existing_whitespace {
21588                    wrapped_text.push_str(current_line.trim_end());
21589                    wrapped_text.push('\n');
21590                    is_first_line = false;
21591                    current_line = subsequent_lines_prefix.clone();
21592                    current_line_len = subsequent_lines_prefix_len;
21593                } else if have_preceding_whitespace {
21594                    continue;
21595                } else if current_line_len + 1 > wrap_column
21596                    && current_line_len != current_prefix_len
21597                {
21598                    wrapped_text.push_str(current_line.trim_end());
21599                    wrapped_text.push('\n');
21600                    is_first_line = false;
21601                    current_line = subsequent_lines_prefix.clone();
21602                    current_line_len = subsequent_lines_prefix_len;
21603                } else if current_line_len != current_prefix_len {
21604                    current_line.push(' ');
21605                    current_line_len += 1;
21606                }
21607            }
21608        }
21609    }
21610
21611    if !current_line.is_empty() {
21612        wrapped_text.push_str(&current_line);
21613    }
21614    wrapped_text
21615}
21616
21617#[test]
21618fn test_wrap_with_prefix() {
21619    assert_eq!(
21620        wrap_with_prefix(
21621            "# ".to_string(),
21622            "# ".to_string(),
21623            "abcdefg".to_string(),
21624            4,
21625            NonZeroU32::new(4).unwrap(),
21626            false,
21627        ),
21628        "# abcdefg"
21629    );
21630    assert_eq!(
21631        wrap_with_prefix(
21632            "".to_string(),
21633            "".to_string(),
21634            "\thello world".to_string(),
21635            8,
21636            NonZeroU32::new(4).unwrap(),
21637            false,
21638        ),
21639        "hello\nworld"
21640    );
21641    assert_eq!(
21642        wrap_with_prefix(
21643            "// ".to_string(),
21644            "// ".to_string(),
21645            "xx \nyy zz aa bb cc".to_string(),
21646            12,
21647            NonZeroU32::new(4).unwrap(),
21648            false,
21649        ),
21650        "// xx yy zz\n// aa bb cc"
21651    );
21652    assert_eq!(
21653        wrap_with_prefix(
21654            String::new(),
21655            String::new(),
21656            "这是什么 \n 钢笔".to_string(),
21657            3,
21658            NonZeroU32::new(4).unwrap(),
21659            false,
21660        ),
21661        "这是什\n么 钢\n"
21662    );
21663}
21664
21665pub trait CollaborationHub {
21666    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21667    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21668    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21669}
21670
21671impl CollaborationHub for Entity<Project> {
21672    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21673        self.read(cx).collaborators()
21674    }
21675
21676    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21677        self.read(cx).user_store().read(cx).participant_indices()
21678    }
21679
21680    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21681        let this = self.read(cx);
21682        let user_ids = this.collaborators().values().map(|c| c.user_id);
21683        this.user_store().read(cx).participant_names(user_ids, cx)
21684    }
21685}
21686
21687pub trait SemanticsProvider {
21688    fn hover(
21689        &self,
21690        buffer: &Entity<Buffer>,
21691        position: text::Anchor,
21692        cx: &mut App,
21693    ) -> Option<Task<Vec<project::Hover>>>;
21694
21695    fn inline_values(
21696        &self,
21697        buffer_handle: Entity<Buffer>,
21698        range: Range<text::Anchor>,
21699        cx: &mut App,
21700    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21701
21702    fn inlay_hints(
21703        &self,
21704        buffer_handle: Entity<Buffer>,
21705        range: Range<text::Anchor>,
21706        cx: &mut App,
21707    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21708
21709    fn resolve_inlay_hint(
21710        &self,
21711        hint: InlayHint,
21712        buffer_handle: Entity<Buffer>,
21713        server_id: LanguageServerId,
21714        cx: &mut App,
21715    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21716
21717    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21718
21719    fn document_highlights(
21720        &self,
21721        buffer: &Entity<Buffer>,
21722        position: text::Anchor,
21723        cx: &mut App,
21724    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21725
21726    fn definitions(
21727        &self,
21728        buffer: &Entity<Buffer>,
21729        position: text::Anchor,
21730        kind: GotoDefinitionKind,
21731        cx: &mut App,
21732    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21733
21734    fn range_for_rename(
21735        &self,
21736        buffer: &Entity<Buffer>,
21737        position: text::Anchor,
21738        cx: &mut App,
21739    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21740
21741    fn perform_rename(
21742        &self,
21743        buffer: &Entity<Buffer>,
21744        position: text::Anchor,
21745        new_name: String,
21746        cx: &mut App,
21747    ) -> Option<Task<Result<ProjectTransaction>>>;
21748}
21749
21750pub trait CompletionProvider {
21751    fn completions(
21752        &self,
21753        excerpt_id: ExcerptId,
21754        buffer: &Entity<Buffer>,
21755        buffer_position: text::Anchor,
21756        trigger: CompletionContext,
21757        window: &mut Window,
21758        cx: &mut Context<Editor>,
21759    ) -> Task<Result<Vec<CompletionResponse>>>;
21760
21761    fn resolve_completions(
21762        &self,
21763        _buffer: Entity<Buffer>,
21764        _completion_indices: Vec<usize>,
21765        _completions: Rc<RefCell<Box<[Completion]>>>,
21766        _cx: &mut Context<Editor>,
21767    ) -> Task<Result<bool>> {
21768        Task::ready(Ok(false))
21769    }
21770
21771    fn apply_additional_edits_for_completion(
21772        &self,
21773        _buffer: Entity<Buffer>,
21774        _completions: Rc<RefCell<Box<[Completion]>>>,
21775        _completion_index: usize,
21776        _push_to_history: bool,
21777        _cx: &mut Context<Editor>,
21778    ) -> Task<Result<Option<language::Transaction>>> {
21779        Task::ready(Ok(None))
21780    }
21781
21782    fn is_completion_trigger(
21783        &self,
21784        buffer: &Entity<Buffer>,
21785        position: language::Anchor,
21786        text: &str,
21787        trigger_in_words: bool,
21788        menu_is_open: bool,
21789        cx: &mut Context<Editor>,
21790    ) -> bool;
21791
21792    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21793
21794    fn sort_completions(&self) -> bool {
21795        true
21796    }
21797
21798    fn filter_completions(&self) -> bool {
21799        true
21800    }
21801}
21802
21803pub trait CodeActionProvider {
21804    fn id(&self) -> Arc<str>;
21805
21806    fn code_actions(
21807        &self,
21808        buffer: &Entity<Buffer>,
21809        range: Range<text::Anchor>,
21810        window: &mut Window,
21811        cx: &mut App,
21812    ) -> Task<Result<Vec<CodeAction>>>;
21813
21814    fn apply_code_action(
21815        &self,
21816        buffer_handle: Entity<Buffer>,
21817        action: CodeAction,
21818        excerpt_id: ExcerptId,
21819        push_to_history: bool,
21820        window: &mut Window,
21821        cx: &mut App,
21822    ) -> Task<Result<ProjectTransaction>>;
21823}
21824
21825impl CodeActionProvider for Entity<Project> {
21826    fn id(&self) -> Arc<str> {
21827        "project".into()
21828    }
21829
21830    fn code_actions(
21831        &self,
21832        buffer: &Entity<Buffer>,
21833        range: Range<text::Anchor>,
21834        _window: &mut Window,
21835        cx: &mut App,
21836    ) -> Task<Result<Vec<CodeAction>>> {
21837        self.update(cx, |project, cx| {
21838            let code_lens = project.code_lens(buffer, range.clone(), cx);
21839            let code_actions = project.code_actions(buffer, range, None, cx);
21840            cx.background_spawn(async move {
21841                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21842                Ok(code_lens
21843                    .context("code lens fetch")?
21844                    .into_iter()
21845                    .chain(code_actions.context("code action fetch")?)
21846                    .collect())
21847            })
21848        })
21849    }
21850
21851    fn apply_code_action(
21852        &self,
21853        buffer_handle: Entity<Buffer>,
21854        action: CodeAction,
21855        _excerpt_id: ExcerptId,
21856        push_to_history: bool,
21857        _window: &mut Window,
21858        cx: &mut App,
21859    ) -> Task<Result<ProjectTransaction>> {
21860        self.update(cx, |project, cx| {
21861            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21862        })
21863    }
21864}
21865
21866fn snippet_completions(
21867    project: &Project,
21868    buffer: &Entity<Buffer>,
21869    buffer_position: text::Anchor,
21870    cx: &mut App,
21871) -> Task<Result<CompletionResponse>> {
21872    let languages = buffer.read(cx).languages_at(buffer_position);
21873    let snippet_store = project.snippets().read(cx);
21874
21875    let scopes: Vec<_> = languages
21876        .iter()
21877        .filter_map(|language| {
21878            let language_name = language.lsp_id();
21879            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21880
21881            if snippets.is_empty() {
21882                None
21883            } else {
21884                Some((language.default_scope(), snippets))
21885            }
21886        })
21887        .collect();
21888
21889    if scopes.is_empty() {
21890        return Task::ready(Ok(CompletionResponse {
21891            completions: vec![],
21892            is_incomplete: false,
21893        }));
21894    }
21895
21896    let snapshot = buffer.read(cx).text_snapshot();
21897    let chars: String = snapshot
21898        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21899        .collect();
21900    let executor = cx.background_executor().clone();
21901
21902    cx.background_spawn(async move {
21903        let mut is_incomplete = false;
21904        let mut completions: Vec<Completion> = Vec::new();
21905        for (scope, snippets) in scopes.into_iter() {
21906            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21907            let mut last_word = chars
21908                .chars()
21909                .take_while(|c| classifier.is_word(*c))
21910                .collect::<String>();
21911            last_word = last_word.chars().rev().collect();
21912
21913            if last_word.is_empty() {
21914                return Ok(CompletionResponse {
21915                    completions: vec![],
21916                    is_incomplete: true,
21917                });
21918            }
21919
21920            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21921            let to_lsp = |point: &text::Anchor| {
21922                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21923                point_to_lsp(end)
21924            };
21925            let lsp_end = to_lsp(&buffer_position);
21926
21927            let candidates = snippets
21928                .iter()
21929                .enumerate()
21930                .flat_map(|(ix, snippet)| {
21931                    snippet
21932                        .prefix
21933                        .iter()
21934                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21935                })
21936                .collect::<Vec<StringMatchCandidate>>();
21937
21938            const MAX_RESULTS: usize = 100;
21939            let mut matches = fuzzy::match_strings(
21940                &candidates,
21941                &last_word,
21942                last_word.chars().any(|c| c.is_uppercase()),
21943                true,
21944                MAX_RESULTS,
21945                &Default::default(),
21946                executor.clone(),
21947            )
21948            .await;
21949
21950            if matches.len() >= MAX_RESULTS {
21951                is_incomplete = true;
21952            }
21953
21954            // Remove all candidates where the query's start does not match the start of any word in the candidate
21955            if let Some(query_start) = last_word.chars().next() {
21956                matches.retain(|string_match| {
21957                    split_words(&string_match.string).any(|word| {
21958                        // Check that the first codepoint of the word as lowercase matches the first
21959                        // codepoint of the query as lowercase
21960                        word.chars()
21961                            .flat_map(|codepoint| codepoint.to_lowercase())
21962                            .zip(query_start.to_lowercase())
21963                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21964                    })
21965                });
21966            }
21967
21968            let matched_strings = matches
21969                .into_iter()
21970                .map(|m| m.string)
21971                .collect::<HashSet<_>>();
21972
21973            completions.extend(snippets.iter().filter_map(|snippet| {
21974                let matching_prefix = snippet
21975                    .prefix
21976                    .iter()
21977                    .find(|prefix| matched_strings.contains(*prefix))?;
21978                let start = as_offset - last_word.len();
21979                let start = snapshot.anchor_before(start);
21980                let range = start..buffer_position;
21981                let lsp_start = to_lsp(&start);
21982                let lsp_range = lsp::Range {
21983                    start: lsp_start,
21984                    end: lsp_end,
21985                };
21986                Some(Completion {
21987                    replace_range: range,
21988                    new_text: snippet.body.clone(),
21989                    source: CompletionSource::Lsp {
21990                        insert_range: None,
21991                        server_id: LanguageServerId(usize::MAX),
21992                        resolved: true,
21993                        lsp_completion: Box::new(lsp::CompletionItem {
21994                            label: snippet.prefix.first().unwrap().clone(),
21995                            kind: Some(CompletionItemKind::SNIPPET),
21996                            label_details: snippet.description.as_ref().map(|description| {
21997                                lsp::CompletionItemLabelDetails {
21998                                    detail: Some(description.clone()),
21999                                    description: None,
22000                                }
22001                            }),
22002                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22003                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22004                                lsp::InsertReplaceEdit {
22005                                    new_text: snippet.body.clone(),
22006                                    insert: lsp_range,
22007                                    replace: lsp_range,
22008                                },
22009                            )),
22010                            filter_text: Some(snippet.body.clone()),
22011                            sort_text: Some(char::MAX.to_string()),
22012                            ..lsp::CompletionItem::default()
22013                        }),
22014                        lsp_defaults: None,
22015                    },
22016                    label: CodeLabel {
22017                        text: matching_prefix.clone(),
22018                        runs: Vec::new(),
22019                        filter_range: 0..matching_prefix.len(),
22020                    },
22021                    icon_path: None,
22022                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22023                        single_line: snippet.name.clone().into(),
22024                        plain_text: snippet
22025                            .description
22026                            .clone()
22027                            .map(|description| description.into()),
22028                    }),
22029                    insert_text_mode: None,
22030                    confirm: None,
22031                })
22032            }))
22033        }
22034
22035        Ok(CompletionResponse {
22036            completions,
22037            is_incomplete,
22038        })
22039    })
22040}
22041
22042impl CompletionProvider for Entity<Project> {
22043    fn completions(
22044        &self,
22045        _excerpt_id: ExcerptId,
22046        buffer: &Entity<Buffer>,
22047        buffer_position: text::Anchor,
22048        options: CompletionContext,
22049        _window: &mut Window,
22050        cx: &mut Context<Editor>,
22051    ) -> Task<Result<Vec<CompletionResponse>>> {
22052        self.update(cx, |project, cx| {
22053            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22054            let project_completions = project.completions(buffer, buffer_position, options, cx);
22055            cx.background_spawn(async move {
22056                let mut responses = project_completions.await?;
22057                let snippets = snippets.await?;
22058                if !snippets.completions.is_empty() {
22059                    responses.push(snippets);
22060                }
22061                Ok(responses)
22062            })
22063        })
22064    }
22065
22066    fn resolve_completions(
22067        &self,
22068        buffer: Entity<Buffer>,
22069        completion_indices: Vec<usize>,
22070        completions: Rc<RefCell<Box<[Completion]>>>,
22071        cx: &mut Context<Editor>,
22072    ) -> Task<Result<bool>> {
22073        self.update(cx, |project, cx| {
22074            project.lsp_store().update(cx, |lsp_store, cx| {
22075                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22076            })
22077        })
22078    }
22079
22080    fn apply_additional_edits_for_completion(
22081        &self,
22082        buffer: Entity<Buffer>,
22083        completions: Rc<RefCell<Box<[Completion]>>>,
22084        completion_index: usize,
22085        push_to_history: bool,
22086        cx: &mut Context<Editor>,
22087    ) -> Task<Result<Option<language::Transaction>>> {
22088        self.update(cx, |project, cx| {
22089            project.lsp_store().update(cx, |lsp_store, cx| {
22090                lsp_store.apply_additional_edits_for_completion(
22091                    buffer,
22092                    completions,
22093                    completion_index,
22094                    push_to_history,
22095                    cx,
22096                )
22097            })
22098        })
22099    }
22100
22101    fn is_completion_trigger(
22102        &self,
22103        buffer: &Entity<Buffer>,
22104        position: language::Anchor,
22105        text: &str,
22106        trigger_in_words: bool,
22107        menu_is_open: bool,
22108        cx: &mut Context<Editor>,
22109    ) -> bool {
22110        let mut chars = text.chars();
22111        let char = if let Some(char) = chars.next() {
22112            char
22113        } else {
22114            return false;
22115        };
22116        if chars.next().is_some() {
22117            return false;
22118        }
22119
22120        let buffer = buffer.read(cx);
22121        let snapshot = buffer.snapshot();
22122        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22123            return false;
22124        }
22125        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22126        if trigger_in_words && classifier.is_word(char) {
22127            return true;
22128        }
22129
22130        buffer.completion_triggers().contains(text)
22131    }
22132}
22133
22134impl SemanticsProvider for Entity<Project> {
22135    fn hover(
22136        &self,
22137        buffer: &Entity<Buffer>,
22138        position: text::Anchor,
22139        cx: &mut App,
22140    ) -> Option<Task<Vec<project::Hover>>> {
22141        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22142    }
22143
22144    fn document_highlights(
22145        &self,
22146        buffer: &Entity<Buffer>,
22147        position: text::Anchor,
22148        cx: &mut App,
22149    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22150        Some(self.update(cx, |project, cx| {
22151            project.document_highlights(buffer, position, cx)
22152        }))
22153    }
22154
22155    fn definitions(
22156        &self,
22157        buffer: &Entity<Buffer>,
22158        position: text::Anchor,
22159        kind: GotoDefinitionKind,
22160        cx: &mut App,
22161    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22162        Some(self.update(cx, |project, cx| match kind {
22163            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22164            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22165            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22166            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22167        }))
22168    }
22169
22170    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22171        // TODO: make this work for remote projects
22172        self.update(cx, |project, cx| {
22173            if project
22174                .active_debug_session(cx)
22175                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22176            {
22177                return true;
22178            }
22179
22180            buffer.update(cx, |buffer, cx| {
22181                project.any_language_server_supports_inlay_hints(buffer, cx)
22182            })
22183        })
22184    }
22185
22186    fn inline_values(
22187        &self,
22188        buffer_handle: Entity<Buffer>,
22189        range: Range<text::Anchor>,
22190        cx: &mut App,
22191    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22192        self.update(cx, |project, cx| {
22193            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22194
22195            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22196        })
22197    }
22198
22199    fn inlay_hints(
22200        &self,
22201        buffer_handle: Entity<Buffer>,
22202        range: Range<text::Anchor>,
22203        cx: &mut App,
22204    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22205        Some(self.update(cx, |project, cx| {
22206            project.inlay_hints(buffer_handle, range, cx)
22207        }))
22208    }
22209
22210    fn resolve_inlay_hint(
22211        &self,
22212        hint: InlayHint,
22213        buffer_handle: Entity<Buffer>,
22214        server_id: LanguageServerId,
22215        cx: &mut App,
22216    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22217        Some(self.update(cx, |project, cx| {
22218            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22219        }))
22220    }
22221
22222    fn range_for_rename(
22223        &self,
22224        buffer: &Entity<Buffer>,
22225        position: text::Anchor,
22226        cx: &mut App,
22227    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22228        Some(self.update(cx, |project, cx| {
22229            let buffer = buffer.clone();
22230            let task = project.prepare_rename(buffer.clone(), position, cx);
22231            cx.spawn(async move |_, cx| {
22232                Ok(match task.await? {
22233                    PrepareRenameResponse::Success(range) => Some(range),
22234                    PrepareRenameResponse::InvalidPosition => None,
22235                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22236                        // Fallback on using TreeSitter info to determine identifier range
22237                        buffer.read_with(cx, |buffer, _| {
22238                            let snapshot = buffer.snapshot();
22239                            let (range, kind) = snapshot.surrounding_word(position, false);
22240                            if kind != Some(CharKind::Word) {
22241                                return None;
22242                            }
22243                            Some(
22244                                snapshot.anchor_before(range.start)
22245                                    ..snapshot.anchor_after(range.end),
22246                            )
22247                        })?
22248                    }
22249                })
22250            })
22251        }))
22252    }
22253
22254    fn perform_rename(
22255        &self,
22256        buffer: &Entity<Buffer>,
22257        position: text::Anchor,
22258        new_name: String,
22259        cx: &mut App,
22260    ) -> Option<Task<Result<ProjectTransaction>>> {
22261        Some(self.update(cx, |project, cx| {
22262            project.perform_rename(buffer.clone(), position, new_name, cx)
22263        }))
22264    }
22265}
22266
22267fn inlay_hint_settings(
22268    location: Anchor,
22269    snapshot: &MultiBufferSnapshot,
22270    cx: &mut Context<Editor>,
22271) -> InlayHintSettings {
22272    let file = snapshot.file_at(location);
22273    let language = snapshot.language_at(location).map(|l| l.name());
22274    language_settings(language, file, cx).inlay_hints
22275}
22276
22277fn consume_contiguous_rows(
22278    contiguous_row_selections: &mut Vec<Selection<Point>>,
22279    selection: &Selection<Point>,
22280    display_map: &DisplaySnapshot,
22281    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22282) -> (MultiBufferRow, MultiBufferRow) {
22283    contiguous_row_selections.push(selection.clone());
22284    let start_row = starting_row(selection, display_map);
22285    let mut end_row = ending_row(selection, display_map);
22286
22287    while let Some(next_selection) = selections.peek() {
22288        if next_selection.start.row <= end_row.0 {
22289            end_row = ending_row(next_selection, display_map);
22290            contiguous_row_selections.push(selections.next().unwrap().clone());
22291        } else {
22292            break;
22293        }
22294    }
22295    (start_row, end_row)
22296}
22297
22298fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22299    if selection.start.column > 0 {
22300        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22301    } else {
22302        MultiBufferRow(selection.start.row)
22303    }
22304}
22305
22306fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22307    if next_selection.end.column > 0 || next_selection.is_empty() {
22308        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22309    } else {
22310        MultiBufferRow(next_selection.end.row)
22311    }
22312}
22313
22314impl EditorSnapshot {
22315    pub fn remote_selections_in_range<'a>(
22316        &'a self,
22317        range: &'a Range<Anchor>,
22318        collaboration_hub: &dyn CollaborationHub,
22319        cx: &'a App,
22320    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22321        let participant_names = collaboration_hub.user_names(cx);
22322        let participant_indices = collaboration_hub.user_participant_indices(cx);
22323        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22324        let collaborators_by_replica_id = collaborators_by_peer_id
22325            .values()
22326            .map(|collaborator| (collaborator.replica_id, collaborator))
22327            .collect::<HashMap<_, _>>();
22328        self.buffer_snapshot
22329            .selections_in_range(range, false)
22330            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22331                if replica_id == AGENT_REPLICA_ID {
22332                    Some(RemoteSelection {
22333                        replica_id,
22334                        selection,
22335                        cursor_shape,
22336                        line_mode,
22337                        collaborator_id: CollaboratorId::Agent,
22338                        user_name: Some("Agent".into()),
22339                        color: cx.theme().players().agent(),
22340                    })
22341                } else {
22342                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22343                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22344                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22345                    Some(RemoteSelection {
22346                        replica_id,
22347                        selection,
22348                        cursor_shape,
22349                        line_mode,
22350                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22351                        user_name,
22352                        color: if let Some(index) = participant_index {
22353                            cx.theme().players().color_for_participant(index.0)
22354                        } else {
22355                            cx.theme().players().absent()
22356                        },
22357                    })
22358                }
22359            })
22360    }
22361
22362    pub fn hunks_for_ranges(
22363        &self,
22364        ranges: impl IntoIterator<Item = Range<Point>>,
22365    ) -> Vec<MultiBufferDiffHunk> {
22366        let mut hunks = Vec::new();
22367        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22368            HashMap::default();
22369        for query_range in ranges {
22370            let query_rows =
22371                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22372            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22373                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22374            ) {
22375                // Include deleted hunks that are adjacent to the query range, because
22376                // otherwise they would be missed.
22377                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22378                if hunk.status().is_deleted() {
22379                    intersects_range |= hunk.row_range.start == query_rows.end;
22380                    intersects_range |= hunk.row_range.end == query_rows.start;
22381                }
22382                if intersects_range {
22383                    if !processed_buffer_rows
22384                        .entry(hunk.buffer_id)
22385                        .or_default()
22386                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22387                    {
22388                        continue;
22389                    }
22390                    hunks.push(hunk);
22391                }
22392            }
22393        }
22394
22395        hunks
22396    }
22397
22398    fn display_diff_hunks_for_rows<'a>(
22399        &'a self,
22400        display_rows: Range<DisplayRow>,
22401        folded_buffers: &'a HashSet<BufferId>,
22402    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22403        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22404        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22405
22406        self.buffer_snapshot
22407            .diff_hunks_in_range(buffer_start..buffer_end)
22408            .filter_map(|hunk| {
22409                if folded_buffers.contains(&hunk.buffer_id) {
22410                    return None;
22411                }
22412
22413                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22414                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22415
22416                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22417                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22418
22419                let display_hunk = if hunk_display_start.column() != 0 {
22420                    DisplayDiffHunk::Folded {
22421                        display_row: hunk_display_start.row(),
22422                    }
22423                } else {
22424                    let mut end_row = hunk_display_end.row();
22425                    if hunk_display_end.column() > 0 {
22426                        end_row.0 += 1;
22427                    }
22428                    let is_created_file = hunk.is_created_file();
22429                    DisplayDiffHunk::Unfolded {
22430                        status: hunk.status(),
22431                        diff_base_byte_range: hunk.diff_base_byte_range,
22432                        display_row_range: hunk_display_start.row()..end_row,
22433                        multi_buffer_range: Anchor::range_in_buffer(
22434                            hunk.excerpt_id,
22435                            hunk.buffer_id,
22436                            hunk.buffer_range,
22437                        ),
22438                        is_created_file,
22439                    }
22440                };
22441
22442                Some(display_hunk)
22443            })
22444    }
22445
22446    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22447        self.display_snapshot.buffer_snapshot.language_at(position)
22448    }
22449
22450    pub fn is_focused(&self) -> bool {
22451        self.is_focused
22452    }
22453
22454    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22455        self.placeholder_text.as_ref()
22456    }
22457
22458    pub fn scroll_position(&self) -> gpui::Point<f32> {
22459        self.scroll_anchor.scroll_position(&self.display_snapshot)
22460    }
22461
22462    fn gutter_dimensions(
22463        &self,
22464        font_id: FontId,
22465        font_size: Pixels,
22466        max_line_number_width: Pixels,
22467        cx: &App,
22468    ) -> Option<GutterDimensions> {
22469        if !self.show_gutter {
22470            return None;
22471        }
22472
22473        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22474        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22475
22476        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22477            matches!(
22478                ProjectSettings::get_global(cx).git.git_gutter,
22479                Some(GitGutterSetting::TrackedFiles)
22480            )
22481        });
22482        let gutter_settings = EditorSettings::get_global(cx).gutter;
22483        let show_line_numbers = self
22484            .show_line_numbers
22485            .unwrap_or(gutter_settings.line_numbers);
22486        let line_gutter_width = if show_line_numbers {
22487            // Avoid flicker-like gutter resizes when the line number gains another digit by
22488            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22489            let min_width_for_number_on_gutter =
22490                ch_advance * gutter_settings.min_line_number_digits as f32;
22491            max_line_number_width.max(min_width_for_number_on_gutter)
22492        } else {
22493            0.0.into()
22494        };
22495
22496        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22497        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22498
22499        let git_blame_entries_width =
22500            self.git_blame_gutter_max_author_length
22501                .map(|max_author_length| {
22502                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22503                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22504
22505                    /// The number of characters to dedicate to gaps and margins.
22506                    const SPACING_WIDTH: usize = 4;
22507
22508                    let max_char_count = max_author_length.min(renderer.max_author_length())
22509                        + ::git::SHORT_SHA_LENGTH
22510                        + MAX_RELATIVE_TIMESTAMP.len()
22511                        + SPACING_WIDTH;
22512
22513                    ch_advance * max_char_count
22514                });
22515
22516        let is_singleton = self.buffer_snapshot.is_singleton();
22517
22518        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22519        left_padding += if !is_singleton {
22520            ch_width * 4.0
22521        } else if show_runnables || show_breakpoints {
22522            ch_width * 3.0
22523        } else if show_git_gutter && show_line_numbers {
22524            ch_width * 2.0
22525        } else if show_git_gutter || show_line_numbers {
22526            ch_width
22527        } else {
22528            px(0.)
22529        };
22530
22531        let shows_folds = is_singleton && gutter_settings.folds;
22532
22533        let right_padding = if shows_folds && show_line_numbers {
22534            ch_width * 4.0
22535        } else if shows_folds || (!is_singleton && show_line_numbers) {
22536            ch_width * 3.0
22537        } else if show_line_numbers {
22538            ch_width
22539        } else {
22540            px(0.)
22541        };
22542
22543        Some(GutterDimensions {
22544            left_padding,
22545            right_padding,
22546            width: line_gutter_width + left_padding + right_padding,
22547            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22548            git_blame_entries_width,
22549        })
22550    }
22551
22552    pub fn render_crease_toggle(
22553        &self,
22554        buffer_row: MultiBufferRow,
22555        row_contains_cursor: bool,
22556        editor: Entity<Editor>,
22557        window: &mut Window,
22558        cx: &mut App,
22559    ) -> Option<AnyElement> {
22560        let folded = self.is_line_folded(buffer_row);
22561        let mut is_foldable = false;
22562
22563        if let Some(crease) = self
22564            .crease_snapshot
22565            .query_row(buffer_row, &self.buffer_snapshot)
22566        {
22567            is_foldable = true;
22568            match crease {
22569                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22570                    if let Some(render_toggle) = render_toggle {
22571                        let toggle_callback =
22572                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22573                                if folded {
22574                                    editor.update(cx, |editor, cx| {
22575                                        editor.fold_at(buffer_row, window, cx)
22576                                    });
22577                                } else {
22578                                    editor.update(cx, |editor, cx| {
22579                                        editor.unfold_at(buffer_row, window, cx)
22580                                    });
22581                                }
22582                            });
22583                        return Some((render_toggle)(
22584                            buffer_row,
22585                            folded,
22586                            toggle_callback,
22587                            window,
22588                            cx,
22589                        ));
22590                    }
22591                }
22592            }
22593        }
22594
22595        is_foldable |= self.starts_indent(buffer_row);
22596
22597        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22598            Some(
22599                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22600                    .toggle_state(folded)
22601                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22602                        if folded {
22603                            this.unfold_at(buffer_row, window, cx);
22604                        } else {
22605                            this.fold_at(buffer_row, window, cx);
22606                        }
22607                    }))
22608                    .into_any_element(),
22609            )
22610        } else {
22611            None
22612        }
22613    }
22614
22615    pub fn render_crease_trailer(
22616        &self,
22617        buffer_row: MultiBufferRow,
22618        window: &mut Window,
22619        cx: &mut App,
22620    ) -> Option<AnyElement> {
22621        let folded = self.is_line_folded(buffer_row);
22622        if let Crease::Inline { render_trailer, .. } = self
22623            .crease_snapshot
22624            .query_row(buffer_row, &self.buffer_snapshot)?
22625        {
22626            let render_trailer = render_trailer.as_ref()?;
22627            Some(render_trailer(buffer_row, folded, window, cx))
22628        } else {
22629            None
22630        }
22631    }
22632}
22633
22634impl Deref for EditorSnapshot {
22635    type Target = DisplaySnapshot;
22636
22637    fn deref(&self) -> &Self::Target {
22638        &self.display_snapshot
22639    }
22640}
22641
22642#[derive(Clone, Debug, PartialEq, Eq)]
22643pub enum EditorEvent {
22644    InputIgnored {
22645        text: Arc<str>,
22646    },
22647    InputHandled {
22648        utf16_range_to_replace: Option<Range<isize>>,
22649        text: Arc<str>,
22650    },
22651    ExcerptsAdded {
22652        buffer: Entity<Buffer>,
22653        predecessor: ExcerptId,
22654        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22655    },
22656    ExcerptsRemoved {
22657        ids: Vec<ExcerptId>,
22658        removed_buffer_ids: Vec<BufferId>,
22659    },
22660    BufferFoldToggled {
22661        ids: Vec<ExcerptId>,
22662        folded: bool,
22663    },
22664    ExcerptsEdited {
22665        ids: Vec<ExcerptId>,
22666    },
22667    ExcerptsExpanded {
22668        ids: Vec<ExcerptId>,
22669    },
22670    BufferEdited,
22671    Edited {
22672        transaction_id: clock::Lamport,
22673    },
22674    Reparsed(BufferId),
22675    Focused,
22676    FocusedIn,
22677    Blurred,
22678    DirtyChanged,
22679    Saved,
22680    TitleChanged,
22681    DiffBaseChanged,
22682    SelectionsChanged {
22683        local: bool,
22684    },
22685    ScrollPositionChanged {
22686        local: bool,
22687        autoscroll: bool,
22688    },
22689    Closed,
22690    TransactionUndone {
22691        transaction_id: clock::Lamport,
22692    },
22693    TransactionBegun {
22694        transaction_id: clock::Lamport,
22695    },
22696    Reloaded,
22697    CursorShapeChanged,
22698    PushedToNavHistory {
22699        anchor: Anchor,
22700        is_deactivate: bool,
22701    },
22702}
22703
22704impl EventEmitter<EditorEvent> for Editor {}
22705
22706impl Focusable for Editor {
22707    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22708        self.focus_handle.clone()
22709    }
22710}
22711
22712impl Render for Editor {
22713    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22714        let settings = ThemeSettings::get_global(cx);
22715
22716        let mut text_style = match self.mode {
22717            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22718                color: cx.theme().colors().editor_foreground,
22719                font_family: settings.ui_font.family.clone(),
22720                font_features: settings.ui_font.features.clone(),
22721                font_fallbacks: settings.ui_font.fallbacks.clone(),
22722                font_size: rems(0.875).into(),
22723                font_weight: settings.ui_font.weight,
22724                line_height: relative(settings.buffer_line_height.value()),
22725                ..Default::default()
22726            },
22727            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22728                color: cx.theme().colors().editor_foreground,
22729                font_family: settings.buffer_font.family.clone(),
22730                font_features: settings.buffer_font.features.clone(),
22731                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22732                font_size: settings.buffer_font_size(cx).into(),
22733                font_weight: settings.buffer_font.weight,
22734                line_height: relative(settings.buffer_line_height.value()),
22735                ..Default::default()
22736            },
22737        };
22738        if let Some(text_style_refinement) = &self.text_style_refinement {
22739            text_style.refine(text_style_refinement)
22740        }
22741
22742        let background = match self.mode {
22743            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22744            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22745            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22746            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22747        };
22748
22749        EditorElement::new(
22750            &cx.entity(),
22751            EditorStyle {
22752                background,
22753                border: cx.theme().colors().border,
22754                local_player: cx.theme().players().local(),
22755                text: text_style,
22756                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22757                syntax: cx.theme().syntax().clone(),
22758                status: cx.theme().status().clone(),
22759                inlay_hints_style: make_inlay_hints_style(cx),
22760                inline_completion_styles: make_suggestion_styles(cx),
22761                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22762                show_underlines: self.diagnostics_enabled(),
22763            },
22764        )
22765    }
22766}
22767
22768impl EntityInputHandler for Editor {
22769    fn text_for_range(
22770        &mut self,
22771        range_utf16: Range<usize>,
22772        adjusted_range: &mut Option<Range<usize>>,
22773        _: &mut Window,
22774        cx: &mut Context<Self>,
22775    ) -> Option<String> {
22776        let snapshot = self.buffer.read(cx).read(cx);
22777        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22778        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22779        if (start.0..end.0) != range_utf16 {
22780            adjusted_range.replace(start.0..end.0);
22781        }
22782        Some(snapshot.text_for_range(start..end).collect())
22783    }
22784
22785    fn selected_text_range(
22786        &mut self,
22787        ignore_disabled_input: bool,
22788        _: &mut Window,
22789        cx: &mut Context<Self>,
22790    ) -> Option<UTF16Selection> {
22791        // Prevent the IME menu from appearing when holding down an alphabetic key
22792        // while input is disabled.
22793        if !ignore_disabled_input && !self.input_enabled {
22794            return None;
22795        }
22796
22797        let selection = self.selections.newest::<OffsetUtf16>(cx);
22798        let range = selection.range();
22799
22800        Some(UTF16Selection {
22801            range: range.start.0..range.end.0,
22802            reversed: selection.reversed,
22803        })
22804    }
22805
22806    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22807        let snapshot = self.buffer.read(cx).read(cx);
22808        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22809        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22810    }
22811
22812    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22813        self.clear_highlights::<InputComposition>(cx);
22814        self.ime_transaction.take();
22815    }
22816
22817    fn replace_text_in_range(
22818        &mut self,
22819        range_utf16: Option<Range<usize>>,
22820        text: &str,
22821        window: &mut Window,
22822        cx: &mut Context<Self>,
22823    ) {
22824        if !self.input_enabled {
22825            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22826            return;
22827        }
22828
22829        self.transact(window, cx, |this, window, cx| {
22830            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22831                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22832                Some(this.selection_replacement_ranges(range_utf16, cx))
22833            } else {
22834                this.marked_text_ranges(cx)
22835            };
22836
22837            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22838                let newest_selection_id = this.selections.newest_anchor().id;
22839                this.selections
22840                    .all::<OffsetUtf16>(cx)
22841                    .iter()
22842                    .zip(ranges_to_replace.iter())
22843                    .find_map(|(selection, range)| {
22844                        if selection.id == newest_selection_id {
22845                            Some(
22846                                (range.start.0 as isize - selection.head().0 as isize)
22847                                    ..(range.end.0 as isize - selection.head().0 as isize),
22848                            )
22849                        } else {
22850                            None
22851                        }
22852                    })
22853            });
22854
22855            cx.emit(EditorEvent::InputHandled {
22856                utf16_range_to_replace: range_to_replace,
22857                text: text.into(),
22858            });
22859
22860            if let Some(new_selected_ranges) = new_selected_ranges {
22861                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22862                    selections.select_ranges(new_selected_ranges)
22863                });
22864                this.backspace(&Default::default(), window, cx);
22865            }
22866
22867            this.handle_input(text, window, cx);
22868        });
22869
22870        if let Some(transaction) = self.ime_transaction {
22871            self.buffer.update(cx, |buffer, cx| {
22872                buffer.group_until_transaction(transaction, cx);
22873            });
22874        }
22875
22876        self.unmark_text(window, cx);
22877    }
22878
22879    fn replace_and_mark_text_in_range(
22880        &mut self,
22881        range_utf16: Option<Range<usize>>,
22882        text: &str,
22883        new_selected_range_utf16: Option<Range<usize>>,
22884        window: &mut Window,
22885        cx: &mut Context<Self>,
22886    ) {
22887        if !self.input_enabled {
22888            return;
22889        }
22890
22891        let transaction = self.transact(window, cx, |this, window, cx| {
22892            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22893                let snapshot = this.buffer.read(cx).read(cx);
22894                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22895                    for marked_range in &mut marked_ranges {
22896                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22897                        marked_range.start.0 += relative_range_utf16.start;
22898                        marked_range.start =
22899                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22900                        marked_range.end =
22901                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22902                    }
22903                }
22904                Some(marked_ranges)
22905            } else if let Some(range_utf16) = range_utf16 {
22906                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22907                Some(this.selection_replacement_ranges(range_utf16, cx))
22908            } else {
22909                None
22910            };
22911
22912            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22913                let newest_selection_id = this.selections.newest_anchor().id;
22914                this.selections
22915                    .all::<OffsetUtf16>(cx)
22916                    .iter()
22917                    .zip(ranges_to_replace.iter())
22918                    .find_map(|(selection, range)| {
22919                        if selection.id == newest_selection_id {
22920                            Some(
22921                                (range.start.0 as isize - selection.head().0 as isize)
22922                                    ..(range.end.0 as isize - selection.head().0 as isize),
22923                            )
22924                        } else {
22925                            None
22926                        }
22927                    })
22928            });
22929
22930            cx.emit(EditorEvent::InputHandled {
22931                utf16_range_to_replace: range_to_replace,
22932                text: text.into(),
22933            });
22934
22935            if let Some(ranges) = ranges_to_replace {
22936                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22937                    s.select_ranges(ranges)
22938                });
22939            }
22940
22941            let marked_ranges = {
22942                let snapshot = this.buffer.read(cx).read(cx);
22943                this.selections
22944                    .disjoint_anchors()
22945                    .iter()
22946                    .map(|selection| {
22947                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22948                    })
22949                    .collect::<Vec<_>>()
22950            };
22951
22952            if text.is_empty() {
22953                this.unmark_text(window, cx);
22954            } else {
22955                this.highlight_text::<InputComposition>(
22956                    marked_ranges.clone(),
22957                    HighlightStyle {
22958                        underline: Some(UnderlineStyle {
22959                            thickness: px(1.),
22960                            color: None,
22961                            wavy: false,
22962                        }),
22963                        ..Default::default()
22964                    },
22965                    cx,
22966                );
22967            }
22968
22969            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22970            let use_autoclose = this.use_autoclose;
22971            let use_auto_surround = this.use_auto_surround;
22972            this.set_use_autoclose(false);
22973            this.set_use_auto_surround(false);
22974            this.handle_input(text, window, cx);
22975            this.set_use_autoclose(use_autoclose);
22976            this.set_use_auto_surround(use_auto_surround);
22977
22978            if let Some(new_selected_range) = new_selected_range_utf16 {
22979                let snapshot = this.buffer.read(cx).read(cx);
22980                let new_selected_ranges = marked_ranges
22981                    .into_iter()
22982                    .map(|marked_range| {
22983                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22984                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22985                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22986                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22987                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22988                    })
22989                    .collect::<Vec<_>>();
22990
22991                drop(snapshot);
22992                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22993                    selections.select_ranges(new_selected_ranges)
22994                });
22995            }
22996        });
22997
22998        self.ime_transaction = self.ime_transaction.or(transaction);
22999        if let Some(transaction) = self.ime_transaction {
23000            self.buffer.update(cx, |buffer, cx| {
23001                buffer.group_until_transaction(transaction, cx);
23002            });
23003        }
23004
23005        if self.text_highlights::<InputComposition>(cx).is_none() {
23006            self.ime_transaction.take();
23007        }
23008    }
23009
23010    fn bounds_for_range(
23011        &mut self,
23012        range_utf16: Range<usize>,
23013        element_bounds: gpui::Bounds<Pixels>,
23014        window: &mut Window,
23015        cx: &mut Context<Self>,
23016    ) -> Option<gpui::Bounds<Pixels>> {
23017        let text_layout_details = self.text_layout_details(window);
23018        let CharacterDimensions {
23019            em_width,
23020            em_advance,
23021            line_height,
23022        } = self.character_dimensions(window);
23023
23024        let snapshot = self.snapshot(window, cx);
23025        let scroll_position = snapshot.scroll_position();
23026        let scroll_left = scroll_position.x * em_advance;
23027
23028        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23029        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23030            + self.gutter_dimensions.full_width();
23031        let y = line_height * (start.row().as_f32() - scroll_position.y);
23032
23033        Some(Bounds {
23034            origin: element_bounds.origin + point(x, y),
23035            size: size(em_width, line_height),
23036        })
23037    }
23038
23039    fn character_index_for_point(
23040        &mut self,
23041        point: gpui::Point<Pixels>,
23042        _window: &mut Window,
23043        _cx: &mut Context<Self>,
23044    ) -> Option<usize> {
23045        let position_map = self.last_position_map.as_ref()?;
23046        if !position_map.text_hitbox.contains(&point) {
23047            return None;
23048        }
23049        let display_point = position_map.point_for_position(point).previous_valid;
23050        let anchor = position_map
23051            .snapshot
23052            .display_point_to_anchor(display_point, Bias::Left);
23053        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23054        Some(utf16_offset.0)
23055    }
23056}
23057
23058trait SelectionExt {
23059    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23060    fn spanned_rows(
23061        &self,
23062        include_end_if_at_line_start: bool,
23063        map: &DisplaySnapshot,
23064    ) -> Range<MultiBufferRow>;
23065}
23066
23067impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23068    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23069        let start = self
23070            .start
23071            .to_point(&map.buffer_snapshot)
23072            .to_display_point(map);
23073        let end = self
23074            .end
23075            .to_point(&map.buffer_snapshot)
23076            .to_display_point(map);
23077        if self.reversed {
23078            end..start
23079        } else {
23080            start..end
23081        }
23082    }
23083
23084    fn spanned_rows(
23085        &self,
23086        include_end_if_at_line_start: bool,
23087        map: &DisplaySnapshot,
23088    ) -> Range<MultiBufferRow> {
23089        let start = self.start.to_point(&map.buffer_snapshot);
23090        let mut end = self.end.to_point(&map.buffer_snapshot);
23091        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23092            end.row -= 1;
23093        }
23094
23095        let buffer_start = map.prev_line_boundary(start).0;
23096        let buffer_end = map.next_line_boundary(end).0;
23097        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23098    }
23099}
23100
23101impl<T: InvalidationRegion> InvalidationStack<T> {
23102    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23103    where
23104        S: Clone + ToOffset,
23105    {
23106        while let Some(region) = self.last() {
23107            let all_selections_inside_invalidation_ranges =
23108                if selections.len() == region.ranges().len() {
23109                    selections
23110                        .iter()
23111                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23112                        .all(|(selection, invalidation_range)| {
23113                            let head = selection.head().to_offset(buffer);
23114                            invalidation_range.start <= head && invalidation_range.end >= head
23115                        })
23116                } else {
23117                    false
23118                };
23119
23120            if all_selections_inside_invalidation_ranges {
23121                break;
23122            } else {
23123                self.pop();
23124            }
23125        }
23126    }
23127}
23128
23129impl<T> Default for InvalidationStack<T> {
23130    fn default() -> Self {
23131        Self(Default::default())
23132    }
23133}
23134
23135impl<T> Deref for InvalidationStack<T> {
23136    type Target = Vec<T>;
23137
23138    fn deref(&self) -> &Self::Target {
23139        &self.0
23140    }
23141}
23142
23143impl<T> DerefMut for InvalidationStack<T> {
23144    fn deref_mut(&mut self) -> &mut Self::Target {
23145        &mut self.0
23146    }
23147}
23148
23149impl InvalidationRegion for SnippetState {
23150    fn ranges(&self) -> &[Range<Anchor>] {
23151        &self.ranges[self.active_index]
23152    }
23153}
23154
23155fn inline_completion_edit_text(
23156    current_snapshot: &BufferSnapshot,
23157    edits: &[(Range<Anchor>, String)],
23158    edit_preview: &EditPreview,
23159    include_deletions: bool,
23160    cx: &App,
23161) -> HighlightedText {
23162    let edits = edits
23163        .iter()
23164        .map(|(anchor, text)| {
23165            (
23166                anchor.start.text_anchor..anchor.end.text_anchor,
23167                text.clone(),
23168            )
23169        })
23170        .collect::<Vec<_>>();
23171
23172    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23173}
23174
23175pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23176    match severity {
23177        lsp::DiagnosticSeverity::ERROR => colors.error,
23178        lsp::DiagnosticSeverity::WARNING => colors.warning,
23179        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23180        lsp::DiagnosticSeverity::HINT => colors.info,
23181        _ => colors.ignored,
23182    }
23183}
23184
23185pub fn styled_runs_for_code_label<'a>(
23186    label: &'a CodeLabel,
23187    syntax_theme: &'a theme::SyntaxTheme,
23188) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23189    let fade_out = HighlightStyle {
23190        fade_out: Some(0.35),
23191        ..Default::default()
23192    };
23193
23194    let mut prev_end = label.filter_range.end;
23195    label
23196        .runs
23197        .iter()
23198        .enumerate()
23199        .flat_map(move |(ix, (range, highlight_id))| {
23200            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23201                style
23202            } else {
23203                return Default::default();
23204            };
23205            let mut muted_style = style;
23206            muted_style.highlight(fade_out);
23207
23208            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23209            if range.start >= label.filter_range.end {
23210                if range.start > prev_end {
23211                    runs.push((prev_end..range.start, fade_out));
23212                }
23213                runs.push((range.clone(), muted_style));
23214            } else if range.end <= label.filter_range.end {
23215                runs.push((range.clone(), style));
23216            } else {
23217                runs.push((range.start..label.filter_range.end, style));
23218                runs.push((label.filter_range.end..range.end, muted_style));
23219            }
23220            prev_end = cmp::max(prev_end, range.end);
23221
23222            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23223                runs.push((prev_end..label.text.len(), fade_out));
23224            }
23225
23226            runs
23227        })
23228}
23229
23230pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23231    let mut prev_index = 0;
23232    let mut prev_codepoint: Option<char> = None;
23233    text.char_indices()
23234        .chain([(text.len(), '\0')])
23235        .filter_map(move |(index, codepoint)| {
23236            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23237            let is_boundary = index == text.len()
23238                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23239                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23240            if is_boundary {
23241                let chunk = &text[prev_index..index];
23242                prev_index = index;
23243                Some(chunk)
23244            } else {
23245                None
23246            }
23247        })
23248}
23249
23250pub trait RangeToAnchorExt: Sized {
23251    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23252
23253    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23254        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23255        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23256    }
23257}
23258
23259impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23260    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23261        let start_offset = self.start.to_offset(snapshot);
23262        let end_offset = self.end.to_offset(snapshot);
23263        if start_offset == end_offset {
23264            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23265        } else {
23266            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23267        }
23268    }
23269}
23270
23271pub trait RowExt {
23272    fn as_f32(&self) -> f32;
23273
23274    fn next_row(&self) -> Self;
23275
23276    fn previous_row(&self) -> Self;
23277
23278    fn minus(&self, other: Self) -> u32;
23279}
23280
23281impl RowExt for DisplayRow {
23282    fn as_f32(&self) -> f32 {
23283        self.0 as f32
23284    }
23285
23286    fn next_row(&self) -> Self {
23287        Self(self.0 + 1)
23288    }
23289
23290    fn previous_row(&self) -> Self {
23291        Self(self.0.saturating_sub(1))
23292    }
23293
23294    fn minus(&self, other: Self) -> u32 {
23295        self.0 - other.0
23296    }
23297}
23298
23299impl RowExt for MultiBufferRow {
23300    fn as_f32(&self) -> f32 {
23301        self.0 as f32
23302    }
23303
23304    fn next_row(&self) -> Self {
23305        Self(self.0 + 1)
23306    }
23307
23308    fn previous_row(&self) -> Self {
23309        Self(self.0.saturating_sub(1))
23310    }
23311
23312    fn minus(&self, other: Self) -> u32 {
23313        self.0 - other.0
23314    }
23315}
23316
23317trait RowRangeExt {
23318    type Row;
23319
23320    fn len(&self) -> usize;
23321
23322    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23323}
23324
23325impl RowRangeExt for Range<MultiBufferRow> {
23326    type Row = MultiBufferRow;
23327
23328    fn len(&self) -> usize {
23329        (self.end.0 - self.start.0) as usize
23330    }
23331
23332    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23333        (self.start.0..self.end.0).map(MultiBufferRow)
23334    }
23335}
23336
23337impl RowRangeExt for Range<DisplayRow> {
23338    type Row = DisplayRow;
23339
23340    fn len(&self) -> usize {
23341        (self.end.0 - self.start.0) as usize
23342    }
23343
23344    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23345        (self.start.0..self.end.0).map(DisplayRow)
23346    }
23347}
23348
23349/// If select range has more than one line, we
23350/// just point the cursor to range.start.
23351fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23352    if range.start.row == range.end.row {
23353        range
23354    } else {
23355        range.start..range.start
23356    }
23357}
23358pub struct KillRing(ClipboardItem);
23359impl Global for KillRing {}
23360
23361const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23362
23363enum BreakpointPromptEditAction {
23364    Log,
23365    Condition,
23366    HitCondition,
23367}
23368
23369struct BreakpointPromptEditor {
23370    pub(crate) prompt: Entity<Editor>,
23371    editor: WeakEntity<Editor>,
23372    breakpoint_anchor: Anchor,
23373    breakpoint: Breakpoint,
23374    edit_action: BreakpointPromptEditAction,
23375    block_ids: HashSet<CustomBlockId>,
23376    editor_margins: Arc<Mutex<EditorMargins>>,
23377    _subscriptions: Vec<Subscription>,
23378}
23379
23380impl BreakpointPromptEditor {
23381    const MAX_LINES: u8 = 4;
23382
23383    fn new(
23384        editor: WeakEntity<Editor>,
23385        breakpoint_anchor: Anchor,
23386        breakpoint: Breakpoint,
23387        edit_action: BreakpointPromptEditAction,
23388        window: &mut Window,
23389        cx: &mut Context<Self>,
23390    ) -> Self {
23391        let base_text = match edit_action {
23392            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23393            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23394            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23395        }
23396        .map(|msg| msg.to_string())
23397        .unwrap_or_default();
23398
23399        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23400        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23401
23402        let prompt = cx.new(|cx| {
23403            let mut prompt = Editor::new(
23404                EditorMode::AutoHeight {
23405                    min_lines: 1,
23406                    max_lines: Some(Self::MAX_LINES as usize),
23407                },
23408                buffer,
23409                None,
23410                window,
23411                cx,
23412            );
23413            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23414            prompt.set_show_cursor_when_unfocused(false, cx);
23415            prompt.set_placeholder_text(
23416                match edit_action {
23417                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23418                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23419                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23420                },
23421                cx,
23422            );
23423
23424            prompt
23425        });
23426
23427        Self {
23428            prompt,
23429            editor,
23430            breakpoint_anchor,
23431            breakpoint,
23432            edit_action,
23433            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23434            block_ids: Default::default(),
23435            _subscriptions: vec![],
23436        }
23437    }
23438
23439    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23440        self.block_ids.extend(block_ids)
23441    }
23442
23443    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23444        if let Some(editor) = self.editor.upgrade() {
23445            let message = self
23446                .prompt
23447                .read(cx)
23448                .buffer
23449                .read(cx)
23450                .as_singleton()
23451                .expect("A multi buffer in breakpoint prompt isn't possible")
23452                .read(cx)
23453                .as_rope()
23454                .to_string();
23455
23456            editor.update(cx, |editor, cx| {
23457                editor.edit_breakpoint_at_anchor(
23458                    self.breakpoint_anchor,
23459                    self.breakpoint.clone(),
23460                    match self.edit_action {
23461                        BreakpointPromptEditAction::Log => {
23462                            BreakpointEditAction::EditLogMessage(message.into())
23463                        }
23464                        BreakpointPromptEditAction::Condition => {
23465                            BreakpointEditAction::EditCondition(message.into())
23466                        }
23467                        BreakpointPromptEditAction::HitCondition => {
23468                            BreakpointEditAction::EditHitCondition(message.into())
23469                        }
23470                    },
23471                    cx,
23472                );
23473
23474                editor.remove_blocks(self.block_ids.clone(), None, cx);
23475                cx.focus_self(window);
23476            });
23477        }
23478    }
23479
23480    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23481        self.editor
23482            .update(cx, |editor, cx| {
23483                editor.remove_blocks(self.block_ids.clone(), None, cx);
23484                window.focus(&editor.focus_handle);
23485            })
23486            .log_err();
23487    }
23488
23489    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23490        let settings = ThemeSettings::get_global(cx);
23491        let text_style = TextStyle {
23492            color: if self.prompt.read(cx).read_only(cx) {
23493                cx.theme().colors().text_disabled
23494            } else {
23495                cx.theme().colors().text
23496            },
23497            font_family: settings.buffer_font.family.clone(),
23498            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23499            font_size: settings.buffer_font_size(cx).into(),
23500            font_weight: settings.buffer_font.weight,
23501            line_height: relative(settings.buffer_line_height.value()),
23502            ..Default::default()
23503        };
23504        EditorElement::new(
23505            &self.prompt,
23506            EditorStyle {
23507                background: cx.theme().colors().editor_background,
23508                local_player: cx.theme().players().local(),
23509                text: text_style,
23510                ..Default::default()
23511            },
23512        )
23513    }
23514}
23515
23516impl Render for BreakpointPromptEditor {
23517    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23518        let editor_margins = *self.editor_margins.lock();
23519        let gutter_dimensions = editor_margins.gutter;
23520        h_flex()
23521            .key_context("Editor")
23522            .bg(cx.theme().colors().editor_background)
23523            .border_y_1()
23524            .border_color(cx.theme().status().info_border)
23525            .size_full()
23526            .py(window.line_height() / 2.5)
23527            .on_action(cx.listener(Self::confirm))
23528            .on_action(cx.listener(Self::cancel))
23529            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23530            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23531    }
23532}
23533
23534impl Focusable for BreakpointPromptEditor {
23535    fn focus_handle(&self, cx: &App) -> FocusHandle {
23536        self.prompt.focus_handle(cx)
23537    }
23538}
23539
23540fn all_edits_insertions_or_deletions(
23541    edits: &Vec<(Range<Anchor>, String)>,
23542    snapshot: &MultiBufferSnapshot,
23543) -> bool {
23544    let mut all_insertions = true;
23545    let mut all_deletions = true;
23546
23547    for (range, new_text) in edits.iter() {
23548        let range_is_empty = range.to_offset(&snapshot).is_empty();
23549        let text_is_empty = new_text.is_empty();
23550
23551        if range_is_empty != text_is_empty {
23552            if range_is_empty {
23553                all_deletions = false;
23554            } else {
23555                all_insertions = false;
23556            }
23557        } else {
23558            return false;
23559        }
23560
23561        if !all_insertions && !all_deletions {
23562            return false;
23563        }
23564    }
23565    all_insertions || all_deletions
23566}
23567
23568struct MissingEditPredictionKeybindingTooltip;
23569
23570impl Render for MissingEditPredictionKeybindingTooltip {
23571    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23572        ui::tooltip_container(window, cx, |container, _, cx| {
23573            container
23574                .flex_shrink_0()
23575                .max_w_80()
23576                .min_h(rems_from_px(124.))
23577                .justify_between()
23578                .child(
23579                    v_flex()
23580                        .flex_1()
23581                        .text_ui_sm(cx)
23582                        .child(Label::new("Conflict with Accept Keybinding"))
23583                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23584                )
23585                .child(
23586                    h_flex()
23587                        .pb_1()
23588                        .gap_1()
23589                        .items_end()
23590                        .w_full()
23591                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23592                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23593                        }))
23594                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23595                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23596                        })),
23597                )
23598        })
23599    }
23600}
23601
23602#[derive(Debug, Clone, Copy, PartialEq)]
23603pub struct LineHighlight {
23604    pub background: Background,
23605    pub border: Option<gpui::Hsla>,
23606    pub include_gutter: bool,
23607    pub type_id: Option<TypeId>,
23608}
23609
23610struct LineManipulationResult {
23611    pub new_text: String,
23612    pub line_count_before: usize,
23613    pub line_count_after: usize,
23614}
23615
23616fn render_diff_hunk_controls(
23617    row: u32,
23618    status: &DiffHunkStatus,
23619    hunk_range: Range<Anchor>,
23620    is_created_file: bool,
23621    line_height: Pixels,
23622    editor: &Entity<Editor>,
23623    _window: &mut Window,
23624    cx: &mut App,
23625) -> AnyElement {
23626    h_flex()
23627        .h(line_height)
23628        .mr_1()
23629        .gap_1()
23630        .px_0p5()
23631        .pb_1()
23632        .border_x_1()
23633        .border_b_1()
23634        .border_color(cx.theme().colors().border_variant)
23635        .rounded_b_lg()
23636        .bg(cx.theme().colors().editor_background)
23637        .gap_1()
23638        .block_mouse_except_scroll()
23639        .shadow_md()
23640        .child(if status.has_secondary_hunk() {
23641            Button::new(("stage", row as u64), "Stage")
23642                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23643                .tooltip({
23644                    let focus_handle = editor.focus_handle(cx);
23645                    move |window, cx| {
23646                        Tooltip::for_action_in(
23647                            "Stage Hunk",
23648                            &::git::ToggleStaged,
23649                            &focus_handle,
23650                            window,
23651                            cx,
23652                        )
23653                    }
23654                })
23655                .on_click({
23656                    let editor = editor.clone();
23657                    move |_event, _window, cx| {
23658                        editor.update(cx, |editor, cx| {
23659                            editor.stage_or_unstage_diff_hunks(
23660                                true,
23661                                vec![hunk_range.start..hunk_range.start],
23662                                cx,
23663                            );
23664                        });
23665                    }
23666                })
23667        } else {
23668            Button::new(("unstage", row as u64), "Unstage")
23669                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23670                .tooltip({
23671                    let focus_handle = editor.focus_handle(cx);
23672                    move |window, cx| {
23673                        Tooltip::for_action_in(
23674                            "Unstage Hunk",
23675                            &::git::ToggleStaged,
23676                            &focus_handle,
23677                            window,
23678                            cx,
23679                        )
23680                    }
23681                })
23682                .on_click({
23683                    let editor = editor.clone();
23684                    move |_event, _window, cx| {
23685                        editor.update(cx, |editor, cx| {
23686                            editor.stage_or_unstage_diff_hunks(
23687                                false,
23688                                vec![hunk_range.start..hunk_range.start],
23689                                cx,
23690                            );
23691                        });
23692                    }
23693                })
23694        })
23695        .child(
23696            Button::new(("restore", row as u64), "Restore")
23697                .tooltip({
23698                    let focus_handle = editor.focus_handle(cx);
23699                    move |window, cx| {
23700                        Tooltip::for_action_in(
23701                            "Restore Hunk",
23702                            &::git::Restore,
23703                            &focus_handle,
23704                            window,
23705                            cx,
23706                        )
23707                    }
23708                })
23709                .on_click({
23710                    let editor = editor.clone();
23711                    move |_event, window, cx| {
23712                        editor.update(cx, |editor, cx| {
23713                            let snapshot = editor.snapshot(window, cx);
23714                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23715                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23716                        });
23717                    }
23718                })
23719                .disabled(is_created_file),
23720        )
23721        .when(
23722            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23723            |el| {
23724                el.child(
23725                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23726                        .shape(IconButtonShape::Square)
23727                        .icon_size(IconSize::Small)
23728                        // .disabled(!has_multiple_hunks)
23729                        .tooltip({
23730                            let focus_handle = editor.focus_handle(cx);
23731                            move |window, cx| {
23732                                Tooltip::for_action_in(
23733                                    "Next Hunk",
23734                                    &GoToHunk,
23735                                    &focus_handle,
23736                                    window,
23737                                    cx,
23738                                )
23739                            }
23740                        })
23741                        .on_click({
23742                            let editor = editor.clone();
23743                            move |_event, window, cx| {
23744                                editor.update(cx, |editor, cx| {
23745                                    let snapshot = editor.snapshot(window, cx);
23746                                    let position =
23747                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23748                                    editor.go_to_hunk_before_or_after_position(
23749                                        &snapshot,
23750                                        position,
23751                                        Direction::Next,
23752                                        window,
23753                                        cx,
23754                                    );
23755                                    editor.expand_selected_diff_hunks(cx);
23756                                });
23757                            }
23758                        }),
23759                )
23760                .child(
23761                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23762                        .shape(IconButtonShape::Square)
23763                        .icon_size(IconSize::Small)
23764                        // .disabled(!has_multiple_hunks)
23765                        .tooltip({
23766                            let focus_handle = editor.focus_handle(cx);
23767                            move |window, cx| {
23768                                Tooltip::for_action_in(
23769                                    "Previous Hunk",
23770                                    &GoToPreviousHunk,
23771                                    &focus_handle,
23772                                    window,
23773                                    cx,
23774                                )
23775                            }
23776                        })
23777                        .on_click({
23778                            let editor = editor.clone();
23779                            move |_event, window, cx| {
23780                                editor.update(cx, |editor, cx| {
23781                                    let snapshot = editor.snapshot(window, cx);
23782                                    let point =
23783                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23784                                    editor.go_to_hunk_before_or_after_position(
23785                                        &snapshot,
23786                                        point,
23787                                        Direction::Prev,
23788                                        window,
23789                                        cx,
23790                                    );
23791                                    editor.expand_selected_diff_hunks(cx);
23792                                });
23793                            }
23794                        }),
23795                )
23796            },
23797        )
23798        .into_any_element()
23799}